From 1a28d748330ec57764580372b287c4c3af454e3b Mon Sep 17 00:00:00 2001 From: Aastha Mahendru <aastha.mahendru@mongodb.com> Date: Tue, 15 Oct 2024 17:21:00 +0100 Subject: [PATCH 01/12] support list and nested list --- tools/codegen/codespec/api_spec_schema.go | 4 + .../api_to_provider_spec_mapper_test.go | 95 ++++- tools/codegen/codespec/attribute.go | 79 +++- tools/codegen/codespec/element_type.go | 106 +++++ tools/codegen/codespec/model.go | 10 - tools/codegen/codespec/testdata/api-spec.yml | 362 +++++++++++++++++- .../testdata/config-nested-schema.yml | 14 + 7 files changed, 653 insertions(+), 17 deletions(-) create mode 100644 tools/codegen/codespec/element_type.go create mode 100644 tools/codegen/codespec/testdata/config-nested-schema.yml diff --git a/tools/codegen/codespec/api_spec_schema.go b/tools/codegen/codespec/api_spec_schema.go index c8d0c44f87..a15cc98084 100644 --- a/tools/codegen/codespec/api_spec_schema.go +++ b/tools/codegen/codespec/api_spec_schema.go @@ -57,3 +57,7 @@ func (s *APISpecSchema) IsSensitive() *bool { return &isSensitive } + +func (s *APISpecSchema) IsMap() bool { + return s.Schema.AdditionalProperties != nil && s.Schema.AdditionalProperties.IsA() +} diff --git a/tools/codegen/codespec/api_to_provider_spec_mapper_test.go b/tools/codegen/codespec/api_to_provider_spec_mapper_test.go index 8a999bb2a7..a449926a26 100644 --- a/tools/codegen/codespec/api_to_provider_spec_mapper_test.go +++ b/tools/codegen/codespec/api_to_provider_spec_mapper_test.go @@ -12,7 +12,7 @@ import ( const ( testFieldDesc = "Test field description" - testResourceDesc = "Configures the project level settings for the Test Resource feature." + testResourceDesc = "POST API description" testPathParamDesc = "Path param test description" ) @@ -104,3 +104,96 @@ func TestConvertToProviderSpec(t *testing.T) { }) } } + +func TestConvertToProviderSpec_nested(t *testing.T) { + testCases := map[string]convertToSpecTestCase{ + "Valid input": { + inputOpenAPISpecPath: "testdata/api-spec.yml", + inputConfigPath: "testdata/config-nested-schema.yml", + inputResourceName: "test_resource_with_nested_attr", + + expectedResult: &codespec.Model{ + Resources: []codespec.Resource{{ + Schema: &codespec.Schema{ + Description: conversion.StringPtr(testResourceDesc), + Attributes: codespec.Attributes{ + codespec.Attribute{ + Name: "cluster_name", + ComputedOptionalRequired: codespec.Required, + String: &codespec.StringAttribute{}, + Description: conversion.StringPtr(testPathParamDesc), + }, + codespec.Attribute{ + Name: "group_id", + ComputedOptionalRequired: codespec.Required, + String: &codespec.StringAttribute{}, + Description: conversion.StringPtr(testPathParamDesc), + }, + codespec.Attribute{ + Name: "id", + ComputedOptionalRequired: codespec.Computed, + String: &codespec.StringAttribute{}, + Description: conversion.StringPtr(testFieldDesc), + }, + codespec.Attribute{ + Name: "list_primitive_string_attr", + ComputedOptionalRequired: codespec.Computed, + List: &codespec.ListAttribute{ + ElementType: codespec.String, + }, + Description: conversion.StringPtr(testFieldDesc), + }, + codespec.Attribute{ + Name: "nested_object_array_attr", + ComputedOptionalRequired: codespec.Required, + ListNested: &codespec.ListNestedAttribute{ + NestedObject: codespec.NestedAttributeObject{ + Attributes: codespec.Attributes{ + codespec.Attribute{ + Name: "inner_num_attr", + ComputedOptionalRequired: codespec.Required, + Int64: &codespec.Int64Attribute{}, + Description: conversion.StringPtr(testFieldDesc), + }, + codespec.Attribute{ + Name: "inner_str_attr", + ComputedOptionalRequired: codespec.Required, + String: &codespec.StringAttribute{}, + Description: conversion.StringPtr(testFieldDesc), + }, + codespec.Attribute{ + Name: "list_primitive_string_attr", + ComputedOptionalRequired: codespec.Optional, + List: &codespec.ListAttribute{ + ElementType: codespec.String, + }, + Description: conversion.StringPtr(testFieldDesc), + }, + }, + }, + }, + Description: conversion.StringPtr(testFieldDesc), + }, + codespec.Attribute{ + Name: "str_computed_attr", + ComputedOptionalRequired: codespec.Computed, + String: &codespec.StringAttribute{}, + Description: conversion.StringPtr(testFieldDesc), + }, + }, + }, + Name: "test_resource_with_nested_attr", + }, + }, + }, + }, + } + + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + result, err := codespec.ToCodeSpecModel(tc.inputOpenAPISpecPath, tc.inputConfigPath, tc.inputResourceName) + require.NoError(t, err) + assert.Equal(t, tc.expectedResult, result, "Expected result to match the specified structure") + }) + } +} diff --git a/tools/codegen/codespec/attribute.go b/tools/codegen/codespec/attribute.go index b00f0f0722..1372ce30e4 100644 --- a/tools/codegen/codespec/attribute.go +++ b/tools/codegen/codespec/attribute.go @@ -43,7 +43,9 @@ func (s *APISpecSchema) buildResourceAttr(name string, computability ComputedOpt return s.buildNumberAttr(name, computability) case OASTypeBoolean: return s.buildBoolAttr(name, computability) - case OASTypeArray, OASTypeObject: + case OASTypeArray: + return s.buildArrayAttr(name, computability) + case OASTypeObject: return nil, nil default: return nil, fmt.Errorf("invalid schema type '%s'", s.Type) @@ -143,3 +145,78 @@ func (s *APISpecSchema) buildBoolAttr(name string, computability ComputedOptiona return result, nil } + +func (s *APISpecSchema) buildArrayAttr(name string, computability ComputedOptionalRequired) (*Attribute, error) { + if !s.Schema.Items.IsA() { + return nil, fmt.Errorf("invalid array items property, doesn't have a schema: %s", name) + } + itemSchema, err := BuildSchema(s.Schema.Items.A) + if err != nil { + return nil, fmt.Errorf("error while building nested schema: %s", name) + } + + if itemSchema.Type == OASTypeObject { + objectAttributes, err := buildResourceAttrs(itemSchema) + if err != nil { + return nil, fmt.Errorf("error while building nested schema: %s", name) + } + + result := &Attribute{ + Name: terraformAttrName(name), + ComputedOptionalRequired: computability, + DeprecationMessage: s.GetDeprecationMessage(), + Description: s.GetDescription(), + ListNested: &ListNestedAttribute{ + NestedObject: NestedAttributeObject{ + Attributes: objectAttributes, + }, + }, + } + + return result, nil + } + + elemType, err := itemSchema.buildElementType() + if err != nil { + return nil, fmt.Errorf("error while building nested schema: %s", name) + } + + // if s.Format == util.TF_format_set { + // result := &attrmapper.ResourceSetAttribute{ + // Name: name, + // SetAttribute: resource.SetAttribute{ + // ElementType: elemType, + // ComputedOptionalRequired: computability, + // DeprecationMessage: s.GetDeprecationMessage(), + // Description: s.GetDescription(), + // }, + // } + + // if computability != schema.Computed { + // result.Validators = s.GetSetValidators() + // } + + // return result, nil + // } + + result := &Attribute{ + Name: terraformAttrName(name), + ComputedOptionalRequired: computability, + DeprecationMessage: s.GetDeprecationMessage(), + Description: s.GetDescription(), + List: &ListAttribute{ + ElementType: elemType, + // Default: , + }, + } + + if s.Schema.Default != nil { + var staticDefault bool + if err := s.Schema.Default.Decode(&staticDefault); err == nil { + result.ComputedOptionalRequired = ComputedOptional + result.Bool.Default = &staticDefault + } + } + + return result, nil +} diff --git a/tools/codegen/codespec/element_type.go b/tools/codegen/codespec/element_type.go new file mode 100644 index 0000000000..eac553e1f2 --- /dev/null +++ b/tools/codegen/codespec/element_type.go @@ -0,0 +1,106 @@ +package codespec + +import "fmt" + +type ElemType int + +const ( + Bool ElemType = iota + Float64 + Int64 + Number + String + Unknown +) + +// type ElemType struct { +// Bool *BoolType `json:"bool,omitempty"` +// Float64 *Float64Type `json:"float64,omitempty"` +// Int64 *Int64Type `json:"int64,omitempty"` +// List *ListType `json:"list,omitempty"` +// Number *NumberType `json:"number,omitempty"` +// String *StringType `json:"string,omitempty"` +// } + +// type BoolType struct{} +// type Float64Type struct{} +// type Int64Type struct{} +// type StringType struct{} + +// type NumberType struct{} +// type ListType struct { +// ElementType ElemType `json:"element_type"` +// } +// type SetType struct { +// ElementType ElemType `json:"element_type"` +// } + +// // type ObjectType struct{} // TODO +// type MapType struct { +// ElementType ElemType `json:"element_type"` +// } + +func (s *APISpecSchema) buildElementType() (ElemType, error) { + switch s.Type { + case OASTypeString: + return String, nil + case OASTypeBoolean: + return Bool, nil + case OASTypeInteger: + return Int64, nil + case OASTypeNumber: + return Number, nil + case OASTypeArray, OASTypeObject: + return Unknown, nil // ignoring because complex element types unsupported + default: + return Unknown, fmt.Errorf("invalid schema type '%s'", s.Type) + } +} + +func (s *APISpecSchema) buildArrayElementType() (ElemType, error) { + if !s.Schema.Items.IsA() { + return Unknown, fmt.Errorf("invalid array type for nested elem array, doesn't have a schema") + } + + itemSchema, err := BuildSchema(s.Schema.Items.A) + if err != nil { + return Unknown, err + } + + elemType, err := itemSchema.buildElementType() + if err != nil { + return Unknown, err + } + + return elemType, nil +} + +// func (s *APISpecSchema) buildStringElementType() (ElemType, error) { +// return ElemType{ +// String: &StringType{}, +// }, nil +// } + +// func (s *APISpecSchema) buildIntegerElementType() (ElemType, error) { +// return ElemType{ +// Int64: &Int64Type{}, +// }, nil +// } + +// func (s *APISpecSchema) buildBoolElementType() (ElemType, error) { +// return ElemType{ +// Bool: &BoolType{}, +// }, nil +// } + +// func (s *APISpecSchema) buildNumberElementType() (ElemType, error) { +// if s.Schema.Format == OASFormatDouble || s.Schema.Format == OASFormatFloat { +// return ElemType{ +// Float64: &Float64Type{}, +// }, nil +// } + +// return ElemType{ +// Number: &NumberType{}, +// }, nil +// } diff --git a/tools/codegen/codespec/model.go b/tools/codegen/codespec/model.go index ccb754892c..abdb21aab2 100644 --- a/tools/codegen/codespec/model.go +++ b/tools/codegen/codespec/model.go @@ -1,15 +1,5 @@ package codespec -type ElemType int - -const ( - Bool ElemType = iota - Float64 - Int64 - Number - String -) - type Model struct { Resources []Resource } diff --git a/tools/codegen/codespec/testdata/api-spec.yml b/tools/codegen/codespec/testdata/api-spec.yml index f4b70687af..f5b773545a 100644 --- a/tools/codegen/codespec/testdata/api-spec.yml +++ b/tools/codegen/codespec/testdata/api-spec.yml @@ -36,7 +36,7 @@ tags: paths: "/api/atlas/v2/groups/{groupId}/testResource": delete: - description: Test Resource disable operation + description: DELETE API description operationId: deleteTestResourceConfiguration parameters: - $ref: "#/components/parameters/groupId" @@ -70,7 +70,7 @@ paths: tags: - Test Resource patch: - description: Updates the project level settings for the Test Resource feature. + description: PATCH API description operationId: updateTestResourceConfiguration parameters: - $ref: "#/components/parameters/groupId" @@ -94,8 +94,7 @@ paths: tags: - Test Resource post: - description: Configures the project level settings for the Test Resource - feature. + description: POST API description operationId: createTestResourceConfiguration parameters: - $ref: "#/components/parameters/groupId" @@ -118,6 +117,159 @@ paths: summary: Enable the Test Resource feature for a project tags: - Test Resource + "/api/atlas/v2/groups/{groupId}/clusters/{clusterName}/nestedTestResource": + delete: + description: DELETE API description + operationId: deleteNestedTestResource + parameters: + - $ref: "#/components/parameters/groupId" + - description: Path param test description + in: path + name: clusterName + required: true + schema: + type: string + maxLength: 64 + minLength: 1 + pattern: ^([a-zA-Z0-9][a-zA-Z0-9-]*)?[a-zA-Z0-9]+$ + responses: + "204": + content: + application/vnd.atlas.2024-05-30+json: + schema: + $ref: "#/components/schemas/NoBody" + x-xgen-version: 2024-05-30 + description: This endpoint does not return a response body. + "400": + $ref: "#/components/responses/badRequest" + "404": + $ref: "#/components/responses/notFound" + "409": + $ref: "#/components/responses/conflict" + "500": + $ref: "#/components/responses/internalServerError" + security: + - DigestAuth: [] + summary: Delete Search Nodes + tags: + - Atlas Search + get: + description: GET API description + operationId: getNestedTestResource + parameters: + - $ref: "#/components/parameters/groupId" + - description: Path param test description + in: path + name: clusterName + required: true + schema: + type: string + maxLength: 64 + minLength: 1 + pattern: ^([a-zA-Z0-9][a-zA-Z0-9-]*)?[a-zA-Z0-9]+$ + responses: + "200": + content: + application/vnd.atlas.2024-05-30+json: + schema: + $ref: "#/components/schemas/NestedTestResourceResponse" + x-xgen-version: 2024-05-30 + description: OK + "400": + $ref: "#/components/responses/badRequest" + "404": + $ref: "#/components/responses/notFound" + "500": + $ref: "#/components/responses/internalServerError" + security: + - DigestAuth: [] + summary: Return Search Nodes + tags: + - Atlas Search + patch: + description: PATCH API description + operationId: updateNestedTestResource + parameters: + - $ref: "#/components/parameters/groupId" + - description: Path param test description + in: path + name: clusterName + required: true + schema: + type: string + maxLength: 64 + minLength: 1 + pattern: ^([a-zA-Z0-9][a-zA-Z0-9-]*)?[a-zA-Z0-9]+$ + requestBody: + content: + application/vnd.atlas.2024-05-30+json: + schema: + $ref: "#/components/schemas/NestedTestResourceRequest" + description: Updates the Search Nodes for the specified cluster. + required: true + responses: + "200": + content: + application/vnd.atlas.2024-05-30+json: + schema: + $ref: "#/components/schemas/NestedTestResourceResponse" + x-xgen-version: 2024-05-30 + description: OK + "400": + $ref: "#/components/responses/badRequest" + "404": + $ref: "#/components/responses/notFound" + "409": + $ref: "#/components/responses/conflict" + "500": + $ref: "#/components/responses/internalServerError" + security: + - DigestAuth: [] + summary: Update Search Nodes + tags: + - Atlas Search + post: + description: POST API description + operationId: createNestedTestResource + parameters: + - $ref: "#/components/parameters/groupId" + - description: Path param test description + in: path + name: clusterName + required: true + schema: + type: string + maxLength: 64 + minLength: 1 + pattern: ^([a-zA-Z0-9][a-zA-Z0-9-]*)?[a-zA-Z0-9]+$ + requestBody: + content: + application/vnd.atlas.2024-05-30+json: + schema: + $ref: "#/components/schemas/NestedTestResourceRequest" + description: Creates Search Nodes for the specified cluster. + required: true + responses: + "201": + content: + application/vnd.atlas.2024-05-30+json: + schema: + $ref: "#/components/schemas/NestedTestResourceResponse" + x-xgen-version: 2024-05-30 + description: Created + "400": + $ref: "#/components/responses/badRequest" + "404": + $ref: "#/components/responses/notFound" + "409": + $ref: "#/components/responses/conflict" + "500": + $ref: "#/components/responses/internalServerError" + security: + - DigestAuth: [] + summary: Create Search Nodes + tags: + - Atlas Search components: parameters: groupId: @@ -135,8 +287,93 @@ components: responses: accepted: description: Accepted. + badRequest: + content: + application/json: + example: + detail: (This is just an example, the exception may not be related to this + endpoint) No provider AWS exists. + error: 400 + errorCode: VALIDATION_ERROR + reason: Bad Request + schema: + $ref: "#/components/schemas/ApiError" + description: Bad Request. + conflict: + content: + application/json: + example: + detail: "(This is just an example, the exception may not be related to this + endpoint) Cannot delete organization link while there is active + migration in following project ids: 60c4fd418ebe251047c50554" + error: 409 + errorCode: CANNOT_DELETE_ORG_ACTIVE_LIVE_MIGRATION_ATLAS_ORG_LINK + reason: Conflict + schema: + $ref: "#/components/schemas/ApiError" + description: Conflict. + forbidden: + content: + application/json: + example: + detail: (This is just an example, the exception may not be related to this + endpoint) + error: 403 + errorCode: CANNOT_CHANGE_GROUP_NAME + reason: Forbidden + schema: + $ref: "#/components/schemas/ApiError" + description: Forbidden. + gone: + content: + application/json: + example: + detail: This happens when a resource is marked for sunset and the sunset date is + in the past. + error: 410 + errorCode: VERSION_GONE + reason: Gone + schema: + $ref: "#/components/schemas/ApiError" + description: Gone. + internalServerError: + content: + application/json: + example: + detail: (This is just an example, the exception may not be related to this + endpoint) + error: 500 + errorCode: UNEXPECTED_ERROR + reason: Internal Server Error + schema: + $ref: "#/components/schemas/ApiError" + description: Internal Server Error. + methodNotAllowed: + content: + application/json: + example: + detail: (This is just an example, the exception may not be related to this + endpoint) + error: 405 + errorCode: ATLAS_BACKUP_CANCEL_SHARD_RESTORE_JOB_NOT_ALLOWED + reason: Method Not Allowed + schema: + $ref: "#/components/schemas/ApiError" + description: Method Not Allowed. noBody: description: This endpoint does not return a response body. + notFound: + content: + application/json: + example: + detail: (This is just an example, the exception may not be related to this + endpoint) Cannot find resource AWS + error: 404 + errorCode: RESOURCE_NOT_FOUND + reason: Not Found + schema: + $ref: "#/components/schemas/ApiError" + description: Not Found. schemas: CreateTestResourceRequest: type: object @@ -234,4 +471,119 @@ components: relationship between this resource and another API resource. This URL often begins with `https://cloud.mongodb.com/api/atlas`. example: self - \ No newline at end of file + NestedTestResourceResponse: + type: object + properties: + groupId: + type: string + description: Path param test description + example: 32b6e34b3d91647abb20e7b8 + maxLength: 24 + minLength: 24 + pattern: ^([a-f0-9]{24})$ + readOnly: true + id: + type: string + description: Test field description + example: 32b6e34b3d91647abb20e7b8 + maxLength: 24 + minLength: 24 + pattern: ^([a-f0-9]{24})$ + readOnly: true + nestedObjectArrayAttr: + type: array + description: Test field description + items: + $ref: "#/components/schemas/NestedObjectAttr" + readOnly: true + listPrimitiveStringAttr: + type: array + description: Test field description + items: + type: string + uniqueItems: true + strComputedAttr: + type: string + description: Test field description + readOnly: true + NestedObjectAttr: + type: object + properties: + innerStrAttr: + type: string + description: Test field description + innerNumAttr: + type: integer + format: int32 + description: Test field description + example: 2 + maximum: 32 + minimum: 2 + listPrimitiveStringAttr: + type: array + description: Test field description + items: + type: string + uniqueItems: true + required: + - innerStrAttr + - innerNumAttr + NestedTestResourceRequest: + type: object + properties: + nestedObjectArrayAttr: + type: array + description: Test field description + items: + $ref: "#/components/schemas/NestedObjectAttr" + maxItems: 1 + minItems: 1 + required: + - nestedObjectArrayAttr + ApiError: + type: object + properties: + badRequestDetail: + $ref: "#/components/schemas/BadRequestDetail" + detail: + type: string + description: Describes the specific conditions or reasons that cause each type + of error. + error: + type: integer + format: int32 + description: HTTP status code returned with this error. + externalDocs: + url: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status + errorCode: + type: string + description: Application error code returned with this error. + parameters: + type: array + description: Parameters used to give more information about the error. + items: {} + reason: + type: string + description: Application error message returned with this error. + BadRequestDetail: + type: object + description: Bad request detail. + properties: + fields: + type: array + description: Describes all violations in a client request. + items: + $ref: "#/components/schemas/FieldViolation" + NoBody: + type: object + description: Endpoint does not return a response body. + FieldViolation: + type: object + properties: + description: + type: string + description: A description of why the request element is bad. + field: + type: string + description: A path that leads to a field in the request body. + \ No newline at end of file diff --git a/tools/codegen/codespec/testdata/config-nested-schema.yml b/tools/codegen/codespec/testdata/config-nested-schema.yml new file mode 100644 index 0000000000..ac6be492c6 --- /dev/null +++ b/tools/codegen/codespec/testdata/config-nested-schema.yml @@ -0,0 +1,14 @@ +resources: + test_resource_with_nested_attr: + read: + path: /api/atlas/v2/groups/{groupId}/clusters/{clusterName}/nestedTestResource + method: GET + create: + path: /api/atlas/v2/groups/{groupId}/clusters/{clusterName}/nestedTestResource + method: POST + update: + path: /api/atlas/v2/groups/{groupId}/clusters/{clusterName}/nestedTestResource + method: PATCH + delete: + path: /api/atlas/v2/groups/{groupId}/clusters/{clusterName}/nestedTestResource + method: DELETE \ No newline at end of file From cb964657680a8a2d8a1fb2523bcdcd7bde4a91a8 Mon Sep 17 00:00:00 2001 From: Aastha Mahendru <aastha.mahendru@mongodb.com> Date: Tue, 15 Oct 2024 17:33:11 +0100 Subject: [PATCH 02/12] cleanup --- tools/codegen/codespec/api_spec_schema.go | 4 -- tools/codegen/codespec/attribute.go | 25 +------ tools/codegen/codespec/element_type.go | 75 -------------------- tools/codegen/codespec/testdata/api-spec.yml | 57 +-------------- 4 files changed, 4 insertions(+), 157 deletions(-) diff --git a/tools/codegen/codespec/api_spec_schema.go b/tools/codegen/codespec/api_spec_schema.go index a15cc98084..c8d0c44f87 100644 --- a/tools/codegen/codespec/api_spec_schema.go +++ b/tools/codegen/codespec/api_spec_schema.go @@ -57,7 +57,3 @@ func (s *APISpecSchema) IsSensitive() *bool { return &isSensitive } - -func (s *APISpecSchema) IsMap() bool { - return s.Schema.AdditionalProperties != nil && s.Schema.AdditionalProperties.IsA() -} diff --git a/tools/codegen/codespec/attribute.go b/tools/codegen/codespec/attribute.go index 1372ce30e4..81d274b65c 100644 --- a/tools/codegen/codespec/attribute.go +++ b/tools/codegen/codespec/attribute.go @@ -46,7 +46,7 @@ func (s *APISpecSchema) buildResourceAttr(name string, computability ComputedOpt case OASTypeArray: return s.buildArrayAttr(name, computability) case OASTypeObject: - return nil, nil + return nil, nil // TODO: add support for SingleNestedObject and MapAttribute default: return nil, fmt.Errorf("invalid schema type '%s'", s.Type) } @@ -148,14 +148,14 @@ func (s *APISpecSchema) buildBoolAttr(name string, computability ComputedOptiona func (s *APISpecSchema) buildArrayAttr(name string, computability ComputedOptionalRequired) (*Attribute, error) { if !s.Schema.Items.IsA() { - return nil, fmt.Errorf("invalid array items property, doesn't have a schema: %s", name) + return nil, fmt.Errorf("invalid array items property, schema doesn't exist: %s", name) } itemSchema, err := BuildSchema(s.Schema.Items.A) if err != nil { return nil, fmt.Errorf("error while building nested schema: %s", name) } - if itemSchema.Type == OASTypeObject { + if itemSchema.Type == OASTypeObject { // TODO: add support for Set and SetNested Attributes objectAttributes, err := buildResourceAttrs(itemSchema) if err != nil { return nil, fmt.Errorf("error while building nested schema: %s", name) @@ -181,24 +181,6 @@ func (s *APISpecSchema) buildArrayAttr(name string, computability ComputedOption return nil, fmt.Errorf("error while building nested schema: %s", name) } - // if s.Format == util.TF_format_set { - // result := &attrmapper.ResourceSetAttribute{ - // Name: name, - // SetAttribute: resource.SetAttribute{ - // ElementType: elemType, - // ComputedOptionalRequired: computability, - // DeprecationMessage: s.GetDeprecationMessage(), - // Description: s.GetDescription(), - // }, - // } - - // if computability != schema.Computed { - // result.Validators = s.GetSetValidators() - // } - - // return result, nil - // } - result := &Attribute{ Name: terraformAttrName(name), ComputedOptionalRequired: computability, @@ -206,7 +188,6 @@ func (s *APISpecSchema) buildArrayAttr(name string, computability ComputedOption Description: s.GetDescription(), List: &ListAttribute{ ElementType: elemType, - // Default: , }, } diff --git a/tools/codegen/codespec/element_type.go b/tools/codegen/codespec/element_type.go index eac553e1f2..c27dada213 100644 --- a/tools/codegen/codespec/element_type.go +++ b/tools/codegen/codespec/element_type.go @@ -13,33 +13,6 @@ const ( Unknown ) -// type ElemType struct { -// Bool *BoolType `json:"bool,omitempty"` -// Float64 *Float64Type `json:"float64,omitempty"` -// Int64 *Int64Type `json:"int64,omitempty"` -// List *ListType `json:"list,omitempty"` -// Number *NumberType `json:"number,omitempty"` -// String *StringType `json:"string,omitempty"` -// } - -// type BoolType struct{} -// type Float64Type struct{} -// type Int64Type struct{} -// type StringType struct{} - -// type NumberType struct{} -// type ListType struct { -// ElementType ElemType `json:"element_type"` -// } -// type SetType struct { -// ElementType ElemType `json:"element_type"` -// } - -// // type ObjectType struct{} // TODO -// type MapType struct { -// ElementType ElemType `json:"element_type"` -// } - func (s *APISpecSchema) buildElementType() (ElemType, error) { switch s.Type { case OASTypeString: @@ -56,51 +29,3 @@ func (s *APISpecSchema) buildElementType() (ElemType, error) { return Unknown, fmt.Errorf("invalid schema type '%s'", s.Type) } } - -func (s *APISpecSchema) buildArrayElementType() (ElemType, error) { - if !s.Schema.Items.IsA() { - return Unknown, fmt.Errorf("invalid array type for nested elem array, doesn't have a schema") - } - - itemSchema, err := BuildSchema(s.Schema.Items.A) - if err != nil { - return Unknown, err - } - - elemType, err := itemSchema.buildElementType() - if err != nil { - return Unknown, err - } - - return elemType, nil -} - -// func (s *APISpecSchema) buildStringElementType() (ElemType, error) { -// return ElemType{ -// String: &StringType{}, -// }, nil -// } - -// func (s *APISpecSchema) buildIntegerElementType() (ElemType, error) { -// return ElemType{ -// Int64: &Int64Type{}, -// }, nil -// } - -// func (s *APISpecSchema) buildBoolElementType() (ElemType, error) { -// return ElemType{ -// Bool: &BoolType{}, -// }, nil -// } - -// func (s *APISpecSchema) buildNumberElementType() (ElemType, error) { -// if s.Schema.Format == OASFormatDouble || s.Schema.Format == OASFormatFloat { -// return ElemType{ -// Float64: &Float64Type{}, -// }, nil -// } - -// return ElemType{ -// Number: &NumberType{}, -// }, nil -// } diff --git a/tools/codegen/codespec/testdata/api-spec.yml b/tools/codegen/codespec/testdata/api-spec.yml index f5b773545a..40d96a2e05 100644 --- a/tools/codegen/codespec/testdata/api-spec.yml +++ b/tools/codegen/codespec/testdata/api-spec.yml @@ -144,8 +144,6 @@ paths: $ref: "#/components/responses/badRequest" "404": $ref: "#/components/responses/notFound" - "409": - $ref: "#/components/responses/conflict" "500": $ref: "#/components/responses/internalServerError" security: @@ -219,8 +217,6 @@ paths: $ref: "#/components/responses/badRequest" "404": $ref: "#/components/responses/notFound" - "409": - $ref: "#/components/responses/conflict" "500": $ref: "#/components/responses/internalServerError" security: @@ -261,13 +257,11 @@ paths: $ref: "#/components/responses/badRequest" "404": $ref: "#/components/responses/notFound" - "409": - $ref: "#/components/responses/conflict" "500": $ref: "#/components/responses/internalServerError" security: - DigestAuth: [] - summary: Create Search Nodes + summary: Create Nested Test Resource tags: - Atlas Search components: @@ -299,43 +293,6 @@ components: schema: $ref: "#/components/schemas/ApiError" description: Bad Request. - conflict: - content: - application/json: - example: - detail: "(This is just an example, the exception may not be related to this - endpoint) Cannot delete organization link while there is active - migration in following project ids: 60c4fd418ebe251047c50554" - error: 409 - errorCode: CANNOT_DELETE_ORG_ACTIVE_LIVE_MIGRATION_ATLAS_ORG_LINK - reason: Conflict - schema: - $ref: "#/components/schemas/ApiError" - description: Conflict. - forbidden: - content: - application/json: - example: - detail: (This is just an example, the exception may not be related to this - endpoint) - error: 403 - errorCode: CANNOT_CHANGE_GROUP_NAME - reason: Forbidden - schema: - $ref: "#/components/schemas/ApiError" - description: Forbidden. - gone: - content: - application/json: - example: - detail: This happens when a resource is marked for sunset and the sunset date is - in the past. - error: 410 - errorCode: VERSION_GONE - reason: Gone - schema: - $ref: "#/components/schemas/ApiError" - description: Gone. internalServerError: content: application/json: @@ -348,18 +305,6 @@ components: schema: $ref: "#/components/schemas/ApiError" description: Internal Server Error. - methodNotAllowed: - content: - application/json: - example: - detail: (This is just an example, the exception may not be related to this - endpoint) - error: 405 - errorCode: ATLAS_BACKUP_CANCEL_SHARD_RESTORE_JOB_NOT_ALLOWED - reason: Method Not Allowed - schema: - $ref: "#/components/schemas/ApiError" - description: Method Not Allowed. noBody: description: This endpoint does not return a response body. notFound: From 646179153e0cdde879370503e1b4bc561afa9648 Mon Sep 17 00:00:00 2001 From: Aastha Mahendru <aastha.mahendru@mongodb.com> Date: Tue, 15 Oct 2024 17:36:41 +0100 Subject: [PATCH 03/12] cleanup --- .../api_to_provider_spec_mapper_test.go | 36 +++++++++--------- tools/codegen/codespec/testdata/api-spec.yml | 37 ------------------- 2 files changed, 18 insertions(+), 55 deletions(-) diff --git a/tools/codegen/codespec/api_to_provider_spec_mapper_test.go b/tools/codegen/codespec/api_to_provider_spec_mapper_test.go index a449926a26..a507f960bb 100644 --- a/tools/codegen/codespec/api_to_provider_spec_mapper_test.go +++ b/tools/codegen/codespec/api_to_provider_spec_mapper_test.go @@ -35,53 +35,53 @@ func TestConvertToProviderSpec(t *testing.T) { Schema: &codespec.Schema{ Description: conversion.StringPtr(testResourceDesc), Attributes: codespec.Attributes{ - codespec.Attribute{ + { Name: "bool_default_attr", ComputedOptionalRequired: codespec.ComputedOptional, Bool: &codespec.BoolAttribute{Default: conversion.Pointer(false)}, }, - codespec.Attribute{ + { Name: "count", ComputedOptionalRequired: codespec.Optional, Int64: &codespec.Int64Attribute{}, Description: conversion.StringPtr(testFieldDesc), }, - codespec.Attribute{ + { Name: "create_date", String: &codespec.StringAttribute{}, ComputedOptionalRequired: codespec.Computed, Description: conversion.StringPtr(testFieldDesc), }, - codespec.Attribute{ + { Name: "group_id", ComputedOptionalRequired: codespec.Required, String: &codespec.StringAttribute{}, Description: conversion.StringPtr(testPathParamDesc), }, - codespec.Attribute{ + { Name: "num_double_default_attr", Float64: &codespec.Float64Attribute{Default: conversion.Pointer(2.0)}, ComputedOptionalRequired: codespec.ComputedOptional, }, - codespec.Attribute{ + { Name: "str_computed_attr", ComputedOptionalRequired: codespec.Computed, String: &codespec.StringAttribute{}, Description: conversion.StringPtr(testFieldDesc), }, - codespec.Attribute{ + { Name: "str_req_attr1", ComputedOptionalRequired: codespec.Required, String: &codespec.StringAttribute{}, Description: conversion.StringPtr(testFieldDesc), }, - codespec.Attribute{ + { Name: "str_req_attr2", ComputedOptionalRequired: codespec.Required, String: &codespec.StringAttribute{}, Description: conversion.StringPtr(testFieldDesc), }, - codespec.Attribute{ + { Name: "str_req_attr3", String: &codespec.StringAttribute{}, ComputedOptionalRequired: codespec.Required, @@ -117,25 +117,25 @@ func TestConvertToProviderSpec_nested(t *testing.T) { Schema: &codespec.Schema{ Description: conversion.StringPtr(testResourceDesc), Attributes: codespec.Attributes{ - codespec.Attribute{ + { Name: "cluster_name", ComputedOptionalRequired: codespec.Required, String: &codespec.StringAttribute{}, Description: conversion.StringPtr(testPathParamDesc), }, - codespec.Attribute{ + { Name: "group_id", ComputedOptionalRequired: codespec.Required, String: &codespec.StringAttribute{}, Description: conversion.StringPtr(testPathParamDesc), }, - codespec.Attribute{ + { Name: "id", ComputedOptionalRequired: codespec.Computed, String: &codespec.StringAttribute{}, Description: conversion.StringPtr(testFieldDesc), }, - codespec.Attribute{ + { Name: "list_primitive_string_attr", ComputedOptionalRequired: codespec.Computed, List: &codespec.ListAttribute{ @@ -143,25 +143,25 @@ func TestConvertToProviderSpec_nested(t *testing.T) { }, Description: conversion.StringPtr(testFieldDesc), }, - codespec.Attribute{ + { Name: "nested_object_array_attr", ComputedOptionalRequired: codespec.Required, ListNested: &codespec.ListNestedAttribute{ NestedObject: codespec.NestedAttributeObject{ Attributes: codespec.Attributes{ - codespec.Attribute{ + { Name: "inner_num_attr", ComputedOptionalRequired: codespec.Required, Int64: &codespec.Int64Attribute{}, Description: conversion.StringPtr(testFieldDesc), }, - codespec.Attribute{ + { Name: "inner_str_attr", ComputedOptionalRequired: codespec.Required, String: &codespec.StringAttribute{}, Description: conversion.StringPtr(testFieldDesc), }, - codespec.Attribute{ + { Name: "list_primitive_string_attr", ComputedOptionalRequired: codespec.Optional, List: &codespec.ListAttribute{ @@ -174,7 +174,7 @@ func TestConvertToProviderSpec_nested(t *testing.T) { }, Description: conversion.StringPtr(testFieldDesc), }, - codespec.Attribute{ + { Name: "str_computed_attr", ComputedOptionalRequired: codespec.Computed, String: &codespec.StringAttribute{}, diff --git a/tools/codegen/codespec/testdata/api-spec.yml b/tools/codegen/codespec/testdata/api-spec.yml index 40d96a2e05..29b7a6aeb0 100644 --- a/tools/codegen/codespec/testdata/api-spec.yml +++ b/tools/codegen/codespec/testdata/api-spec.yml @@ -329,17 +329,6 @@ components: strReqAttr2: type: string description: Test field description - links: - type: array - description: List of one or more Uniform Resource Locators (URLs) that point to - API sub-resources, related API resources, or both. RFC 5988 outlines - these relationships. - externalDocs: - description: Web Linking Specification (RFC 5988) - url: https://datatracker.ietf.org/doc/html/rfc5988 - items: - $ref: "#/components/schemas/Link" - readOnly: true strReqAttr3: type: string description: Test field description @@ -372,17 +361,6 @@ components: strReqAttr2: type: string description: Test field description - links: - type: array - description: List of one or more Uniform Resource Locators (URLs) that point to - API sub-resources, related API resources, or both. RFC 5988 outlines - these relationships. - externalDocs: - description: Web Linking Specification (RFC 5988) - url: https://datatracker.ietf.org/doc/html/rfc5988 - items: - $ref: "#/components/schemas/Link" - readOnly: true strReqAttr3: type: string description: Test field description @@ -401,21 +379,6 @@ components: type: number format: double default: 2.0 - Link: - type: object - properties: - href: - type: string - description: Uniform Resource Locator (URL) that points another API resource to - which this response has some relationship. This URL often begins - with `https://cloud.mongodb.com/api/atlas`. - example: https://cloud.mongodb.com/api/atlas - rel: - type: string - description: Uniform Resource Locator (URL) that defines the semantic - relationship between this resource and another API resource. This - URL often begins with `https://cloud.mongodb.com/api/atlas`. - example: self NestedTestResourceResponse: type: object properties: From 16450d62bb4d92b1fba96fbc22e13db23032cb02 Mon Sep 17 00:00:00 2001 From: Aastha Mahendru <aastha.mahendru@mongodb.com> Date: Tue, 15 Oct 2024 17:38:23 +0100 Subject: [PATCH 04/12] minor --- tools/codegen/codespec/merge_attributes.go | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/codegen/codespec/merge_attributes.go b/tools/codegen/codespec/merge_attributes.go index 697cccf465..c722df4f13 100644 --- a/tools/codegen/codespec/merge_attributes.go +++ b/tools/codegen/codespec/merge_attributes.go @@ -2,6 +2,7 @@ package codespec import "sort" +// TODO: update to infer computability of inner nested attributes func mergeAttributes(pathParams, createRequest, createResponse, readResponse Attributes) Attributes { merged := make(map[string]*Attribute) From 18d39e7ac74f0cd96f7eaf2e90f43ed8f38cdbff Mon Sep 17 00:00:00 2001 From: Aastha Mahendru <aastha.mahendru@mongodb.com> Date: Tue, 15 Oct 2024 17:41:17 +0100 Subject: [PATCH 05/12] minor --- tools/codegen/codespec/testdata/api-spec.yml | 72 -------------------- 1 file changed, 72 deletions(-) diff --git a/tools/codegen/codespec/testdata/api-spec.yml b/tools/codegen/codespec/testdata/api-spec.yml index 29b7a6aeb0..3653f8a3a3 100644 --- a/tools/codegen/codespec/testdata/api-spec.yml +++ b/tools/codegen/codespec/testdata/api-spec.yml @@ -140,12 +140,6 @@ paths: $ref: "#/components/schemas/NoBody" x-xgen-version: 2024-05-30 description: This endpoint does not return a response body. - "400": - $ref: "#/components/responses/badRequest" - "404": - $ref: "#/components/responses/notFound" - "500": - $ref: "#/components/responses/internalServerError" security: - DigestAuth: [] summary: Delete Search Nodes @@ -173,12 +167,6 @@ paths: $ref: "#/components/schemas/NestedTestResourceResponse" x-xgen-version: 2024-05-30 description: OK - "400": - $ref: "#/components/responses/badRequest" - "404": - $ref: "#/components/responses/notFound" - "500": - $ref: "#/components/responses/internalServerError" security: - DigestAuth: [] summary: Return Search Nodes @@ -213,12 +201,6 @@ paths: $ref: "#/components/schemas/NestedTestResourceResponse" x-xgen-version: 2024-05-30 description: OK - "400": - $ref: "#/components/responses/badRequest" - "404": - $ref: "#/components/responses/notFound" - "500": - $ref: "#/components/responses/internalServerError" security: - DigestAuth: [] summary: Update Search Nodes @@ -253,12 +235,6 @@ paths: $ref: "#/components/schemas/NestedTestResourceResponse" x-xgen-version: 2024-05-30 description: Created - "400": - $ref: "#/components/responses/badRequest" - "404": - $ref: "#/components/responses/notFound" - "500": - $ref: "#/components/responses/internalServerError" security: - DigestAuth: [] summary: Create Nested Test Resource @@ -281,44 +257,6 @@ components: responses: accepted: description: Accepted. - badRequest: - content: - application/json: - example: - detail: (This is just an example, the exception may not be related to this - endpoint) No provider AWS exists. - error: 400 - errorCode: VALIDATION_ERROR - reason: Bad Request - schema: - $ref: "#/components/schemas/ApiError" - description: Bad Request. - internalServerError: - content: - application/json: - example: - detail: (This is just an example, the exception may not be related to this - endpoint) - error: 500 - errorCode: UNEXPECTED_ERROR - reason: Internal Server Error - schema: - $ref: "#/components/schemas/ApiError" - description: Internal Server Error. - noBody: - description: This endpoint does not return a response body. - notFound: - content: - application/json: - example: - detail: (This is just an example, the exception may not be related to this - endpoint) Cannot find resource AWS - error: 404 - errorCode: RESOURCE_NOT_FOUND - reason: Not Found - schema: - $ref: "#/components/schemas/ApiError" - description: Not Found. schemas: CreateTestResourceRequest: type: object @@ -485,13 +423,3 @@ components: NoBody: type: object description: Endpoint does not return a response body. - FieldViolation: - type: object - properties: - description: - type: string - description: A description of why the request element is bad. - field: - type: string - description: A path that leads to a field in the request body. - \ No newline at end of file From bf4beaf251673066a1c871688d13e9e8cff36267 Mon Sep 17 00:00:00 2001 From: Aastha Mahendru <aastha.mahendru@mongodb.com> Date: Tue, 15 Oct 2024 17:44:37 +0100 Subject: [PATCH 06/12] cleanup --- tools/codegen/codespec/testdata/api-spec.yml | 34 -------------------- 1 file changed, 34 deletions(-) diff --git a/tools/codegen/codespec/testdata/api-spec.yml b/tools/codegen/codespec/testdata/api-spec.yml index 3653f8a3a3..abb140e583 100644 --- a/tools/codegen/codespec/testdata/api-spec.yml +++ b/tools/codegen/codespec/testdata/api-spec.yml @@ -386,40 +386,6 @@ components: minItems: 1 required: - nestedObjectArrayAttr - ApiError: - type: object - properties: - badRequestDetail: - $ref: "#/components/schemas/BadRequestDetail" - detail: - type: string - description: Describes the specific conditions or reasons that cause each type - of error. - error: - type: integer - format: int32 - description: HTTP status code returned with this error. - externalDocs: - url: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status - errorCode: - type: string - description: Application error code returned with this error. - parameters: - type: array - description: Parameters used to give more information about the error. - items: {} - reason: - type: string - description: Application error message returned with this error. - BadRequestDetail: - type: object - description: Bad request detail. - properties: - fields: - type: array - description: Describes all violations in a client request. - items: - $ref: "#/components/schemas/FieldViolation" NoBody: type: object description: Endpoint does not return a response body. From 4705ae02d9532a6aa168b38086aa8b8f39d64221 Mon Sep 17 00:00:00 2001 From: Aastha Mahendru <aastha.mahendru@mongodb.com> Date: Wed, 16 Oct 2024 11:24:09 +0100 Subject: [PATCH 07/12] add support for sets --- .../api_to_provider_spec_mapper_test.go | 8 +++ tools/codegen/codespec/attribute.go | 51 +++++++++++-------- tools/codegen/codespec/element_type.go | 13 +---- tools/codegen/codespec/model.go | 11 ++++ tools/codegen/codespec/testdata/api-spec.yml | 8 ++- 5 files changed, 56 insertions(+), 35 deletions(-) diff --git a/tools/codegen/codespec/api_to_provider_spec_mapper_test.go b/tools/codegen/codespec/api_to_provider_spec_mapper_test.go index a507f960bb..94e033bfd4 100644 --- a/tools/codegen/codespec/api_to_provider_spec_mapper_test.go +++ b/tools/codegen/codespec/api_to_provider_spec_mapper_test.go @@ -174,6 +174,14 @@ func TestConvertToProviderSpec_nested(t *testing.T) { }, Description: conversion.StringPtr(testFieldDesc), }, + { + Name: "set_primitive_string_attr", + ComputedOptionalRequired: codespec.Computed, + Set: &codespec.SetAttribute{ + ElementType: codespec.String, + }, + Description: conversion.StringPtr(testFieldDesc), + }, { Name: "str_computed_attr", ComputedOptionalRequired: codespec.Computed, diff --git a/tools/codegen/codespec/attribute.go b/tools/codegen/codespec/attribute.go index 81d274b65c..3b20f5aaba 100644 --- a/tools/codegen/codespec/attribute.go +++ b/tools/codegen/codespec/attribute.go @@ -150,30 +150,47 @@ func (s *APISpecSchema) buildArrayAttr(name string, computability ComputedOption if !s.Schema.Items.IsA() { return nil, fmt.Errorf("invalid array items property, schema doesn't exist: %s", name) } + itemSchema, err := BuildSchema(s.Schema.Items.A) if err != nil { return nil, fmt.Errorf("error while building nested schema: %s", name) } - if itemSchema.Type == OASTypeObject { // TODO: add support for Set and SetNested Attributes - objectAttributes, err := buildResourceAttrs(itemSchema) - if err != nil { - return nil, fmt.Errorf("error while building nested schema: %s", name) - } + isSet := s.Schema.UniqueItems != nil && *s.Schema.UniqueItems - result := &Attribute{ + createAttribute := func(nestedObject *NestedAttributeObject, elemType ElemType) *Attribute { + attr := &Attribute{ Name: terraformAttrName(name), ComputedOptionalRequired: computability, DeprecationMessage: s.GetDeprecationMessage(), Description: s.GetDescription(), - ListNested: &ListNestedAttribute{ - NestedObject: NestedAttributeObject{ - Attributes: objectAttributes, - }, - }, } - return result, nil + if nestedObject != nil { + if isSet { + attr.SetNested = &SetNestedAttribute{NestedObject: *nestedObject} + } else { + attr.ListNested = &ListNestedAttribute{NestedObject: *nestedObject} + } + } else { + if isSet { + attr.Set = &SetAttribute{ElementType: elemType} + } else { + attr.List = &ListAttribute{ElementType: elemType} + } + } + + return attr + } + + if itemSchema.Type == OASTypeObject { + objectAttributes, err := buildResourceAttrs(itemSchema) + if err != nil { + return nil, fmt.Errorf("error while building nested schema: %s", name) + } + nestedObject := &NestedAttributeObject{Attributes: objectAttributes} + + return createAttribute(nestedObject, Unknown), nil // Using Unknown ElemType as a placeholder for no ElemType } elemType, err := itemSchema.buildElementType() @@ -181,15 +198,7 @@ func (s *APISpecSchema) buildArrayAttr(name string, computability ComputedOption return nil, fmt.Errorf("error while building nested schema: %s", name) } - result := &Attribute{ - Name: terraformAttrName(name), - ComputedOptionalRequired: computability, - DeprecationMessage: s.GetDeprecationMessage(), - Description: s.GetDescription(), - List: &ListAttribute{ - ElementType: elemType, - }, - } + result := createAttribute(nil, elemType) if s.Schema.Default != nil { var staticDefault bool diff --git a/tools/codegen/codespec/element_type.go b/tools/codegen/codespec/element_type.go index c27dada213..1546786211 100644 --- a/tools/codegen/codespec/element_type.go +++ b/tools/codegen/codespec/element_type.go @@ -2,17 +2,6 @@ package codespec import "fmt" -type ElemType int - -const ( - Bool ElemType = iota - Float64 - Int64 - Number - String - Unknown -) - func (s *APISpecSchema) buildElementType() (ElemType, error) { switch s.Type { case OASTypeString: @@ -24,7 +13,7 @@ func (s *APISpecSchema) buildElementType() (ElemType, error) { case OASTypeNumber: return Number, nil case OASTypeArray, OASTypeObject: - return Unknown, nil // ignoring because complex element types unsupported + return String, nil // complex element types are unsupported so this defaults to string for now to provide best effort generation default: return Unknown, fmt.Errorf("invalid schema type '%s'", s.Type) } diff --git a/tools/codegen/codespec/model.go b/tools/codegen/codespec/model.go index abdb21aab2..a0700b91da 100644 --- a/tools/codegen/codespec/model.go +++ b/tools/codegen/codespec/model.go @@ -1,5 +1,16 @@ package codespec +type ElemType int + +const ( + Bool ElemType = iota + Float64 + Int64 + Number + String + Unknown +) + type Model struct { Resources []Resource } diff --git a/tools/codegen/codespec/testdata/api-spec.yml b/tools/codegen/codespec/testdata/api-spec.yml index abb140e583..70903f0334 100644 --- a/tools/codegen/codespec/testdata/api-spec.yml +++ b/tools/codegen/codespec/testdata/api-spec.yml @@ -342,12 +342,17 @@ components: items: $ref: "#/components/schemas/NestedObjectAttr" readOnly: true - listPrimitiveStringAttr: + setPrimitiveStringAttr: type: array description: Test field description items: type: string uniqueItems: true + listPrimitiveStringAttr: + type: array + description: Test field description + items: + type: string strComputedAttr: type: string description: Test field description @@ -370,7 +375,6 @@ components: description: Test field description items: type: string - uniqueItems: true required: - innerStrAttr - innerNumAttr From c0aa200bc14eef58616a5994cd367ee5f4343939 Mon Sep 17 00:00:00 2001 From: Aastha Mahendru <aastha.mahendru@mongodb.com> Date: Wed, 16 Oct 2024 12:21:44 +0100 Subject: [PATCH 08/12] add set format --- tools/codegen/codespec/attribute.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/codegen/codespec/attribute.go b/tools/codegen/codespec/attribute.go index 3b20f5aaba..d8b767efef 100644 --- a/tools/codegen/codespec/attribute.go +++ b/tools/codegen/codespec/attribute.go @@ -156,7 +156,7 @@ func (s *APISpecSchema) buildArrayAttr(name string, computability ComputedOption return nil, fmt.Errorf("error while building nested schema: %s", name) } - isSet := s.Schema.UniqueItems != nil && *s.Schema.UniqueItems + isSet := s.Schema.Format == OASFormatSet || (s.Schema.UniqueItems != nil && *s.Schema.UniqueItems) createAttribute := func(nestedObject *NestedAttributeObject, elemType ElemType) *Attribute { attr := &Attribute{ From 5147a270b071fc583d0629b6633296732c84837a Mon Sep 17 00:00:00 2001 From: Aastha Mahendru <aastha.mahendru@mongodb.com> Date: Wed, 16 Oct 2024 12:21:50 +0100 Subject: [PATCH 09/12] minor --- tools/codegen/codespec/constants.go | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/codegen/codespec/constants.go b/tools/codegen/codespec/constants.go index 12f09506ca..cd41c1b8c0 100644 --- a/tools/codegen/codespec/constants.go +++ b/tools/codegen/codespec/constants.go @@ -10,6 +10,7 @@ const ( OASFormatDouble = "double" OASFormatFloat = "float" OASFormatPassword = "password" + OASFormatSet = "set" OASResponseCodeOK = "200" OASResponseCodeCreated = "201" From 8b03a314a816c870d724d82e67470a36028b6aad Mon Sep 17 00:00:00 2001 From: Aastha Mahendru <aastha.mahendru@mongodb.com> Date: Wed, 16 Oct 2024 15:48:37 +0100 Subject: [PATCH 10/12] add maps and singles nested attr --- .../api_to_provider_spec_mapper_test.go | 79 ++++++++++++++++--- tools/codegen/codespec/attribute.go | 74 ++++++++++++++++- tools/codegen/codespec/testdata/api-spec.yml | 60 ++++++++++---- 3 files changed, 184 insertions(+), 29 deletions(-) diff --git a/tools/codegen/codespec/api_to_provider_spec_mapper_test.go b/tools/codegen/codespec/api_to_provider_spec_mapper_test.go index 94e033bfd4..6f9076b395 100644 --- a/tools/codegen/codespec/api_to_provider_spec_mapper_test.go +++ b/tools/codegen/codespec/api_to_provider_spec_mapper_test.go @@ -129,12 +129,6 @@ func TestConvertToProviderSpec_nested(t *testing.T) { String: &codespec.StringAttribute{}, Description: conversion.StringPtr(testPathParamDesc), }, - { - Name: "id", - ComputedOptionalRequired: codespec.Computed, - String: &codespec.StringAttribute{}, - Description: conversion.StringPtr(testFieldDesc), - }, { Name: "list_primitive_string_attr", ComputedOptionalRequired: codespec.Computed, @@ -144,7 +138,7 @@ func TestConvertToProviderSpec_nested(t *testing.T) { Description: conversion.StringPtr(testFieldDesc), }, { - Name: "nested_object_array_attr", + Name: "nested_object_array_list_attr", ComputedOptionalRequired: codespec.Required, ListNested: &codespec.ListNestedAttribute{ NestedObject: codespec.NestedAttributeObject{ @@ -156,9 +150,28 @@ func TestConvertToProviderSpec_nested(t *testing.T) { Description: conversion.StringPtr(testFieldDesc), }, { - Name: "inner_str_attr", + Name: "list_primitive_string_attr", + ComputedOptionalRequired: codespec.Optional, + List: &codespec.ListAttribute{ + ElementType: codespec.String, + }, + Description: conversion.StringPtr(testFieldDesc), + }, + }, + }, + }, + Description: conversion.StringPtr(testFieldDesc), + }, + { + Name: "nested_object_array_set_attr", + ComputedOptionalRequired: codespec.Computed, + SetNested: &codespec.SetNestedAttribute{ + NestedObject: codespec.NestedAttributeObject{ + Attributes: codespec.Attributes{ + { + Name: "inner_num_attr", ComputedOptionalRequired: codespec.Required, - String: &codespec.StringAttribute{}, + Int64: &codespec.Int64Attribute{}, Description: conversion.StringPtr(testFieldDesc), }, { @@ -183,10 +196,52 @@ func TestConvertToProviderSpec_nested(t *testing.T) { Description: conversion.StringPtr(testFieldDesc), }, { - Name: "str_computed_attr", + Name: "single_nested_attr", ComputedOptionalRequired: codespec.Computed, - String: &codespec.StringAttribute{}, - Description: conversion.StringPtr(testFieldDesc), + SingleNested: &codespec.SingleNestedAttribute{ + NestedObject: codespec.NestedAttributeObject{ + Attributes: codespec.Attributes{ + { + Name: "inner_int_attr", + ComputedOptionalRequired: codespec.Required, + Int64: &codespec.Int64Attribute{}, + Description: conversion.StringPtr(testFieldDesc), + }, + { + Name: "inner_str_attr", + ComputedOptionalRequired: codespec.Required, + String: &codespec.StringAttribute{}, + Description: conversion.StringPtr(testFieldDesc), + }, + }, + }, + }, + Description: conversion.StringPtr(testFieldDesc), + }, + { + Name: "single_nested_attr_with_nested_maps", + ComputedOptionalRequired: codespec.Computed, + SingleNested: &codespec.SingleNestedAttribute{ + NestedObject: codespec.NestedAttributeObject{ + Attributes: codespec.Attributes{ + { + Name: "aws", + ComputedOptionalRequired: codespec.Optional, + Map: &codespec.MapAttribute{ + ElementType: codespec.String, + }, + }, + { + Name: "azure", + ComputedOptionalRequired: codespec.Optional, + Map: &codespec.MapAttribute{ + ElementType: codespec.String, + }, + }, + }, + }, + }, + Description: conversion.StringPtr(testFieldDesc), }, }, }, diff --git a/tools/codegen/codespec/attribute.go b/tools/codegen/codespec/attribute.go index d8b767efef..e6e299decd 100644 --- a/tools/codegen/codespec/attribute.go +++ b/tools/codegen/codespec/attribute.go @@ -46,7 +46,10 @@ func (s *APISpecSchema) buildResourceAttr(name string, computability ComputedOpt case OASTypeArray: return s.buildArrayAttr(name, computability) case OASTypeObject: - return nil, nil // TODO: add support for SingleNestedObject and MapAttribute + if s.Schema.AdditionalProperties != nil { + return s.buildMapAttr(name, computability) + } + return s.buildSingleNestedAttr(name, computability) default: return nil, fmt.Errorf("invalid schema type '%s'", s.Type) } @@ -210,3 +213,72 @@ func (s *APISpecSchema) buildArrayAttr(name string, computability ComputedOption return result, nil } + +func (s *APISpecSchema) buildMapAttr(name string, computability ComputedOptionalRequired) (*Attribute, error) { + // // Maps are detected as `type: object`, with an `additionalProperties` field that is a schema. `additionalProperties` can + // // also be a boolean (which we should ignore and map to an SingleNestedAttribute), so calling functions should call s.IsMap() first. + // if !s.IsMap() { + // return nil, s.SchemaErrorFromProperty(errors.New("invalid map, additionalProperties doesn't have a valid schema"), name) + // } + + mapSchema, err := BuildSchema(s.Schema.AdditionalProperties.A) + if err != nil { + return nil, err + } + + if mapSchema.Type == OASTypeObject { + mapAttributes, err := buildResourceAttrs(mapSchema) + if err != nil { + return nil, err + } + result := &Attribute{ + Name: terraformAttrName(name), + ComputedOptionalRequired: computability, + DeprecationMessage: s.GetDeprecationMessage(), + Description: s.GetDescription(), + MapNested: &MapNestedAttribute{ + NestedObject: NestedAttributeObject{ + Attributes: mapAttributes, + }, + }, + } + + return result, nil + } + + elemType, err := mapSchema.buildElementType() + if err != nil { + return nil, err + } + + result := &Attribute{ + Name: terraformAttrName(name), + ComputedOptionalRequired: computability, + DeprecationMessage: s.GetDeprecationMessage(), + Description: s.GetDescription(), + Map: &MapAttribute{ + ElementType: elemType, + }, + } + + return result, nil +} + +func (s *APISpecSchema) buildSingleNestedAttr(name string, computability ComputedOptionalRequired) (*Attribute, error) { + objectAttributes, err := buildResourceAttrs(s) + if err != nil { + return nil, err + } + + return &Attribute{ + Name: terraformAttrName(name), + ComputedOptionalRequired: computability, + DeprecationMessage: s.GetDeprecationMessage(), + Description: s.GetDescription(), + SingleNested: &SingleNestedAttribute{ + NestedObject: NestedAttributeObject{ + Attributes: objectAttributes, + }, + }, + }, nil +} diff --git a/tools/codegen/codespec/testdata/api-spec.yml b/tools/codegen/codespec/testdata/api-spec.yml index 70903f0334..83d78bdd69 100644 --- a/tools/codegen/codespec/testdata/api-spec.yml +++ b/tools/codegen/codespec/testdata/api-spec.yml @@ -328,20 +328,19 @@ components: minLength: 24 pattern: ^([a-f0-9]{24})$ readOnly: true - id: - type: string + nestedObjectArrayListAttr: + type: array description: Test field description - example: 32b6e34b3d91647abb20e7b8 - maxLength: 24 - minLength: 24 - pattern: ^([a-f0-9]{24})$ + items: + $ref: "#/components/schemas/NestedObjectAttr" readOnly: true - nestedObjectArrayAttr: + nestedObjectArraySetAttr: type: array description: Test field description items: $ref: "#/components/schemas/NestedObjectAttr" readOnly: true + uniqueItems: true setPrimitiveStringAttr: type: array description: Test field description @@ -353,16 +352,43 @@ components: description: Test field description items: type: string - strComputedAttr: - type: string - description: Test field description + singleNestedAttrWithNestedMaps: + $ref: "#/components/schemas/SingleNestedAttrWithNestedMaps" + singleNestedAttr: + $ref: "#/components/schemas/SingleNestedAttr" + SingleNestedAttrWithNestedMaps: + type: object + description: Test field description + properties: + aws: + type: object + additionalProperties: + type: string + readOnly: true readOnly: true - NestedObjectAttr: + azure: + type: object + additionalProperties: + type: string + readOnly: true + readOnly: true + readOnly: true + title: Outbound Control Plane IP Addresses By Cloud Provider + SingleNestedAttr: type: object + description: Test field description properties: - innerStrAttr: - type: string + innerIntAttr: + type: integer description: Test field description + innerStrAttr: + $ref: "#/components/schemas/SimpleStringRefObject" + required: + - innerIntAttr + - innerStrAttr + NestedObjectAttr: + type: object + properties: innerNumAttr: type: integer format: int32 @@ -376,12 +402,11 @@ components: items: type: string required: - - innerStrAttr - innerNumAttr NestedTestResourceRequest: type: object properties: - nestedObjectArrayAttr: + nestedObjectArrayListAttr: type: array description: Test field description items: @@ -389,7 +414,10 @@ components: maxItems: 1 minItems: 1 required: - - nestedObjectArrayAttr + - nestedObjectArrayListAttr + SimpleStringRefObject: + type: string + description: Test field description NoBody: type: object description: Endpoint does not return a response body. From 47e1c29ca56af38ef00b7ed33419b53830d99448 Mon Sep 17 00:00:00 2001 From: Aastha Mahendru <aastha.mahendru@mongodb.com> Date: Wed, 16 Oct 2024 16:36:48 +0100 Subject: [PATCH 11/12] update test o use nested map --- .../codespec/api_to_provider_spec_mapper_test.go | 15 +++++++++++++++ tools/codegen/codespec/testdata/api-spec.yml | 10 ++++++++++ 2 files changed, 25 insertions(+) diff --git a/tools/codegen/codespec/api_to_provider_spec_mapper_test.go b/tools/codegen/codespec/api_to_provider_spec_mapper_test.go index 6f9076b395..16745caad5 100644 --- a/tools/codegen/codespec/api_to_provider_spec_mapper_test.go +++ b/tools/codegen/codespec/api_to_provider_spec_mapper_test.go @@ -187,6 +187,21 @@ func TestConvertToProviderSpec_nested(t *testing.T) { }, Description: conversion.StringPtr(testFieldDesc), }, + { + Name: "nested_object_map_attr", + ComputedOptionalRequired: codespec.Computed, + MapNested: &codespec.MapNestedAttribute{ + NestedObject: codespec.NestedAttributeObject{ + Attributes: codespec.Attributes{ + { + Name: "attr", + ComputedOptionalRequired: codespec.Optional, + String: &codespec.StringAttribute{}, + }, + }, + }, + }, + }, { Name: "set_primitive_string_attr", ComputedOptionalRequired: codespec.Computed, diff --git a/tools/codegen/codespec/testdata/api-spec.yml b/tools/codegen/codespec/testdata/api-spec.yml index 83d78bdd69..62ded9b5d3 100644 --- a/tools/codegen/codespec/testdata/api-spec.yml +++ b/tools/codegen/codespec/testdata/api-spec.yml @@ -356,6 +356,8 @@ components: $ref: "#/components/schemas/SingleNestedAttrWithNestedMaps" singleNestedAttr: $ref: "#/components/schemas/SingleNestedAttr" + nestedObjectMapAttr: + $ref: "#/components/schemas/NestedObjectMapAttr" SingleNestedAttrWithNestedMaps: type: object description: Test field description @@ -421,3 +423,11 @@ components: NoBody: type: object description: Endpoint does not return a response body. + NestedObjectMapAttr: + type: object + additionalProperties: + type: object + properties: + attr: + type: string + From 1150ec44ef1d4a9f32c4844fc9a4405f00e80008 Mon Sep 17 00:00:00 2001 From: Aastha Mahendru <aastha.mahendru@mongodb.com> Date: Wed, 16 Oct 2024 16:59:56 +0100 Subject: [PATCH 12/12] minor --- .../api_to_provider_spec_mapper_test.go | 38 +++++++------- tools/codegen/codespec/attribute.go | 50 +++++++------------ tools/codegen/codespec/testdata/api-spec.yml | 18 +++---- 3 files changed, 47 insertions(+), 59 deletions(-) diff --git a/tools/codegen/codespec/api_to_provider_spec_mapper_test.go b/tools/codegen/codespec/api_to_provider_spec_mapper_test.go index 16745caad5..3caafe6076 100644 --- a/tools/codegen/codespec/api_to_provider_spec_mapper_test.go +++ b/tools/codegen/codespec/api_to_provider_spec_mapper_test.go @@ -138,7 +138,7 @@ func TestConvertToProviderSpec_nested(t *testing.T) { Description: conversion.StringPtr(testFieldDesc), }, { - Name: "nested_object_array_list_attr", + Name: "nested_list_array_attr", ComputedOptionalRequired: codespec.Required, ListNested: &codespec.ListNestedAttribute{ NestedObject: codespec.NestedAttributeObject{ @@ -163,7 +163,22 @@ func TestConvertToProviderSpec_nested(t *testing.T) { Description: conversion.StringPtr(testFieldDesc), }, { - Name: "nested_object_array_set_attr", + Name: "nested_map_object_attr", + ComputedOptionalRequired: codespec.Computed, + MapNested: &codespec.MapNestedAttribute{ + NestedObject: codespec.NestedAttributeObject{ + Attributes: codespec.Attributes{ + { + Name: "attr", + ComputedOptionalRequired: codespec.Optional, + String: &codespec.StringAttribute{}, + }, + }, + }, + }, + }, + { + Name: "nested_set_array_attr", ComputedOptionalRequired: codespec.Computed, SetNested: &codespec.SetNestedAttribute{ NestedObject: codespec.NestedAttributeObject{ @@ -187,21 +202,6 @@ func TestConvertToProviderSpec_nested(t *testing.T) { }, Description: conversion.StringPtr(testFieldDesc), }, - { - Name: "nested_object_map_attr", - ComputedOptionalRequired: codespec.Computed, - MapNested: &codespec.MapNestedAttribute{ - NestedObject: codespec.NestedAttributeObject{ - Attributes: codespec.Attributes{ - { - Name: "attr", - ComputedOptionalRequired: codespec.Optional, - String: &codespec.StringAttribute{}, - }, - }, - }, - }, - }, { Name: "set_primitive_string_attr", ComputedOptionalRequired: codespec.Computed, @@ -240,14 +240,14 @@ func TestConvertToProviderSpec_nested(t *testing.T) { NestedObject: codespec.NestedAttributeObject{ Attributes: codespec.Attributes{ { - Name: "aws", + Name: "map_attr1", ComputedOptionalRequired: codespec.Optional, Map: &codespec.MapAttribute{ ElementType: codespec.String, }, }, { - Name: "azure", + Name: "map_attr2", ComputedOptionalRequired: codespec.Optional, Map: &codespec.MapAttribute{ ElementType: codespec.String, diff --git a/tools/codegen/codespec/attribute.go b/tools/codegen/codespec/attribute.go index e6e299decd..d2444aaf0d 100644 --- a/tools/codegen/codespec/attribute.go +++ b/tools/codegen/codespec/attribute.go @@ -46,7 +46,7 @@ func (s *APISpecSchema) buildResourceAttr(name string, computability ComputedOpt case OASTypeArray: return s.buildArrayAttr(name, computability) case OASTypeObject: - if s.Schema.AdditionalProperties != nil { + if s.Schema.AdditionalProperties != nil && s.Schema.AdditionalProperties.IsA() { return s.buildMapAttr(name, computability) } return s.buildSingleNestedAttr(name, computability) @@ -215,50 +215,38 @@ func (s *APISpecSchema) buildArrayAttr(name string, computability ComputedOption } func (s *APISpecSchema) buildMapAttr(name string, computability ComputedOptionalRequired) (*Attribute, error) { - // // Maps are detected as `type: object`, with an `additionalProperties` field that is a schema. `additionalProperties` can - // // also be a boolean (which we should ignore and map to an SingleNestedAttribute), so calling functions should call s.IsMap() first. - // if !s.IsMap() { - // return nil, s.SchemaErrorFromProperty(errors.New("invalid map, additionalProperties doesn't have a valid schema"), name) - // } - mapSchema, err := BuildSchema(s.Schema.AdditionalProperties.A) if err != nil { return nil, err } + result := &Attribute{ + Name: terraformAttrName(name), + ComputedOptionalRequired: computability, + DeprecationMessage: s.GetDeprecationMessage(), + Description: s.GetDescription(), + } + if mapSchema.Type == OASTypeObject { mapAttributes, err := buildResourceAttrs(mapSchema) if err != nil { return nil, err } - result := &Attribute{ - Name: terraformAttrName(name), - ComputedOptionalRequired: computability, - DeprecationMessage: s.GetDeprecationMessage(), - Description: s.GetDescription(), - MapNested: &MapNestedAttribute{ - NestedObject: NestedAttributeObject{ - Attributes: mapAttributes, - }, + + result.MapNested = &MapNestedAttribute{ + NestedObject: NestedAttributeObject{ + Attributes: mapAttributes, }, } + } else { + elemType, err := mapSchema.buildElementType() + if err != nil { + return nil, err + } - return result, nil - } - - elemType, err := mapSchema.buildElementType() - if err != nil { - return nil, err - } - - result := &Attribute{ - Name: terraformAttrName(name), - ComputedOptionalRequired: computability, - DeprecationMessage: s.GetDeprecationMessage(), - Description: s.GetDescription(), - Map: &MapAttribute{ + result.Map = &MapAttribute{ ElementType: elemType, - }, + } } return result, nil diff --git a/tools/codegen/codespec/testdata/api-spec.yml b/tools/codegen/codespec/testdata/api-spec.yml index 62ded9b5d3..006f0c13d3 100644 --- a/tools/codegen/codespec/testdata/api-spec.yml +++ b/tools/codegen/codespec/testdata/api-spec.yml @@ -328,13 +328,13 @@ components: minLength: 24 pattern: ^([a-f0-9]{24})$ readOnly: true - nestedObjectArrayListAttr: + nestedListArrayAttr: type: array description: Test field description items: $ref: "#/components/schemas/NestedObjectAttr" readOnly: true - nestedObjectArraySetAttr: + nestedSetArrayAttr: type: array description: Test field description items: @@ -356,19 +356,19 @@ components: $ref: "#/components/schemas/SingleNestedAttrWithNestedMaps" singleNestedAttr: $ref: "#/components/schemas/SingleNestedAttr" - nestedObjectMapAttr: - $ref: "#/components/schemas/NestedObjectMapAttr" + nestedMapObjectAttr: + $ref: "#/components/schemas/NestedMapObjectAttr" SingleNestedAttrWithNestedMaps: type: object description: Test field description properties: - aws: + mapAttr1: type: object additionalProperties: type: string readOnly: true readOnly: true - azure: + mapAttr2: type: object additionalProperties: type: string @@ -408,7 +408,7 @@ components: NestedTestResourceRequest: type: object properties: - nestedObjectArrayListAttr: + nestedListArrayAttr: type: array description: Test field description items: @@ -416,14 +416,14 @@ components: maxItems: 1 minItems: 1 required: - - nestedObjectArrayListAttr + - nestedListArrayAttr SimpleStringRefObject: type: string description: Test field description NoBody: type: object description: Endpoint does not return a response body. - NestedObjectMapAttr: + NestedMapObjectAttr: type: object additionalProperties: type: object