Skip to content

Commit

Permalink
Merge branch 'master' into feature/default-to-https
Browse files Browse the repository at this point in the history
  • Loading branch information
jchampne committed Jul 23, 2019
2 parents 887dbea + 2b5959e commit ce10d4e
Show file tree
Hide file tree
Showing 11 changed files with 744 additions and 266 deletions.
14 changes: 10 additions & 4 deletions docs/how_to_subresources.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,14 @@ are formed in such a way that the sub-resource can always be referenced from the

The description of a sub-resource in the OpenAPI document is no different than any other resource and must meet the same [Terraform compliance requirements](https://github.com/dikhan/terraform-provider-openapi/blob/master/docs/how_to.md#terraform-compliant-resource-requirements).

Nevertheless, the sub-resource endpoint path must contain the path parameters referring to the parents where they live under.
For instance, in the following example the ```firewall``` sub-resource lives under the ```cdns``` resource.
If the parent paths are not described in the OpenAPI doc or they are not [Terraform compliant](https://github.com/dikhan/terraform-provider-openapi/blob/master/docs/how_to.md#terraform-compliant-resource-requirements)
then you will not be able to manage the sub-resource in the provider.

Nevertheless, the sub-resource endpoint path must contain the path parameters referring to the parents where they live under and
the path parameters must be named the same.

For instance, in the following example the ```/v1/firewalls/``` sub-resource lives under the ```/v1/cdns/{cdn_id}``` resource and
both the parent and the sub-resource instance paths contain the same path parameter name that refers to the parent ```{cdn_id}```.

````
paths:
Expand All @@ -29,15 +35,15 @@ paths:
201:
...
...
/v1/cdns/{id}:
/v1/cdns/{cdn_id}:
get:
...
put:
...
delete:
....
/v1/cdns/{parent_id}/v1/firewalls:
/v1/cdns/{cdn_id}/v1/firewalls:
post:
parameters:
- name: "parent_id"
Expand Down
8 changes: 3 additions & 5 deletions openapi/openapi_spec_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,9 @@ type SpecResource interface {
shouldIgnoreResource() bool
getResourceOperations() specResourceOperations
getTimeouts() (*specTimeouts, error)
// isSubResource returns true if the resource path is a subresource. Additionally, it will return the list of parent
// resource names and the resource parent names merged in one to facilitate parent names processing.
isSubResource() (bool, []string, string)
// getParentPropertiesNames is responsible to building the parent properties names for a resource that is a subresource
getParentPropertiesNames() []string
// getParentResourceInfo returns a struct populated with relevant parentResourceInfo if the resource is considered
// a subresource; nil otherwise.
getParentResourceInfo() *parentResourceInfo
}

type specTimeouts struct {
Expand Down
19 changes: 19 additions & 0 deletions openapi/openapi_spec_subresource_info.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package openapi

import "fmt"

type parentResourceInfo struct {
parentResourceNames []string
fullParentResourceName string
parentURIs []string
parentInstanceURIs []string
}

// getParentPropertiesNames is responsible to building the parent properties names for a resource that is a subresource
func (info *parentResourceInfo) getParentPropertiesNames() []string {
parentPropertyNames := []string{}
for _, parentName := range info.parentResourceNames {
parentPropertyNames = append(parentPropertyNames, fmt.Sprintf("%s_id", parentName))
}
return parentPropertyNames
}
45 changes: 45 additions & 0 deletions openapi/openapi_spec_subresource_info_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package openapi

import (
"testing"

. "github.com/smartystreets/goconvey/convey"
)

func Test_getParentPropertiesNames(t *testing.T) {
Convey("Given an empty parentResourceInfo", t, func() {
s := &parentResourceInfo{}
Convey("When the method getParentPropertiesNames is called", func() {
p := s.getParentPropertiesNames()
Convey("Then array returned should be empty", func() {
So(p, ShouldBeEmpty)
})
})
})

Convey("Given a parentResourceInfo with empty parentResourceNames", t, func() {
s := &parentResourceInfo{
parentResourceNames: []string{},
}
Convey("When the method getParentPropertiesNames is called", func() {
p := s.getParentPropertiesNames()
Convey("Then array returned should be empty", func() {
So(p, ShouldBeEmpty)
})
})
})

Convey("Given a parentResourceInfo with some parentResourceNames", t, func() {
s := &parentResourceInfo{
parentResourceNames: []string{"cdn_v1", "cdn_v1_firewalls_v2"},
}
Convey("When the method getParentPropertiesNames is called", func() {
p := s.getParentPropertiesNames()
Convey("And the array returned should contain the expected parent names including the id postfix", func() {
So(len(p), ShouldEqual, 2)
So(p[0], ShouldEqual, "cdn_v1_id")
So(p[1], ShouldEqual, "cdn_v1_firewalls_v2_id")
})
})
})
}
16 changes: 6 additions & 10 deletions openapi/openapi_stub_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,16 +70,12 @@ func (s *specStubResource) getHost() (string, error) {
return s.host, nil
}

func (s *specStubResource) isSubResource() (bool, []string, string) {
func (s *specStubResource) getParentResourceInfo() *parentResourceInfo {
subRes := parentResourceInfo{}
if len(s.parentResourceNames) > 0 && s.fullParentResourceName != "" {
return true, s.parentResourceNames, s.fullParentResourceName
subRes.parentResourceNames = s.parentResourceNames
subRes.fullParentResourceName = s.fullParentResourceName
return &subRes
}
return false, []string{}, ""
}

func (s *specStubResource) getParentPropertiesNames() []string {
if len(s.parentPropertyNames) > 0 {
return s.parentPropertyNames
}
return []string{}
return nil
}
63 changes: 32 additions & 31 deletions openapi/openapi_v2_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,9 +151,9 @@ func (o *SpecV2Resource) buildResourceName() (string, error) {
fullResourceName = fmt.Sprintf("%s_%s", resourceName, version)
}

isSubResource, _, fullParentResourceName := o.isSubResource()
if isSubResource {
fullResourceName = fullParentResourceName + "_" + fullResourceName
parentResourceInfo := o.getParentResourceInfo()
if parentResourceInfo != nil {
fullResourceName = parentResourceInfo.fullParentResourceName + "_" + fullResourceName
}
return fullResourceName, nil
}
Expand Down Expand Up @@ -220,35 +220,51 @@ func (o *SpecV2Resource) getResourceOperations() specResourceOperations {
// defined with true value. If so, the resource will not be exposed to the OpenAPI Terraform provider; otherwise it will
// be exposed and users will be able to manage such resource via terraform.
func (o *SpecV2Resource) shouldIgnoreResource() bool {
if extensionExists, ignoreResource := o.RootPathItem.Post.Extensions.GetBool(extTfExcludeResource); extensionExists && ignoreResource {
return true
postOperation := o.RootPathItem.Post
if postOperation != nil {
if postOperation.Extensions != nil {
if extensionExists, ignoreResource := postOperation.Extensions.GetBool(extTfExcludeResource); extensionExists && ignoreResource {
return true
}
}
}
return false
}

func (o *SpecV2Resource) isSubResource() (bool, []string, string) {
func (o *SpecV2Resource) getParentResourceInfo() *parentResourceInfo {
resourceParentRegex, _ := regexp.Compile(resourceParentNameRegex)
parentMatches := resourceParentRegex.FindAllStringSubmatch(o.Path, -1)
if len(parentMatches) > 0 {
// TODO: if path is deemed subreource but is wrongly formatted return an error
// return false, fmt.Errorf("invalid subresource path '%s'", o.Path)
parentResourceNames := []string{}
var parentURI string
var parentInstanceURI string
fullParentResourceName := ""
var parentResourceNames, parentURIs, parentInstanceURIs []string
for _, match := range parentMatches {
//fullMatch := match[0]
//parentPath := match[1]
fullMatch := match[0]
rootPath := match[1]
parentVersion := match[2]
parentResourceName := match[3]
parentURI = parentInstanceURI + rootPath
parentInstanceURI = parentInstanceURI + fullMatch
if parentVersion != "" {
parentResourceName = fmt.Sprintf("%s_%s", parentResourceName, parentVersion)
}
parentResourceNames = append(parentResourceNames, parentResourceName)
fullParentResourceName = fullParentResourceName + parentResourceName + "_"

parentURIs = append(parentURIs, parentURI)
parentInstanceURIs = append(parentInstanceURIs, parentInstanceURI)
}
fullParentResourceName = strings.TrimRight(fullParentResourceName, "_")
return true, parentResourceNames, fullParentResourceName
sub := &parentResourceInfo{
parentResourceNames: parentResourceNames,
fullParentResourceName: fullParentResourceName,
parentURIs: parentURIs,
parentInstanceURIs: parentInstanceURIs,
}
return sub
}
return false, nil, ""
return nil
}

func (o *SpecV2Resource) getResourceSchema() (*specSchemaDefinition, error) {
Expand All @@ -269,9 +285,9 @@ func (o *SpecV2Resource) getSchemaDefinition(schema *spec.Schema) (*specSchemaDe
schemaDefinition.Properties = append(schemaDefinition.Properties, schemaDefinitionProperty)
}

isSubResource, _, _ := o.isSubResource()
if isSubResource {
parentPropertyNames := o.getParentPropertiesNames()
parentResourceInfo := o.getParentResourceInfo()
if parentResourceInfo != nil {
parentPropertyNames := parentResourceInfo.getParentPropertiesNames()
for _, parentPropertyName := range parentPropertyNames {
pr, _ := o.createSchemaDefinitionProperty(parentPropertyName, spec.Schema{SchemaProps: spec.SchemaProps{Type: spec.StringOrArray{"string"}}}, []string{parentPropertyName})
pr.IsParentProperty = true
Expand All @@ -281,21 +297,6 @@ func (o *SpecV2Resource) getSchemaDefinition(schema *spec.Schema) (*specSchemaDe
return schemaDefinition, nil
}

func (o *SpecV2Resource) getParentPropertiesNames() []string {
if o.Path == "" {
return []string{}
}
isSubResource, parentNames, _ := o.isSubResource()
if isSubResource {
parentPropertyNames := []string{}
for _, parentName := range parentNames {
parentPropertyNames = append(parentPropertyNames, fmt.Sprintf("%s_id", parentName))
}
return parentPropertyNames
}
return []string{}
}

func (o *SpecV2Resource) createSchemaDefinitionProperty(propertyName string, property spec.Schema, requiredProperties []string) (*specSchemaDefinitionProperty, error) {
schemaDefinitionProperty := &specSchemaDefinitionProperty{}

Expand Down
Loading

0 comments on commit ce10d4e

Please sign in to comment.