Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Resource import into state implementation #157

Merged
merged 1 commit into from
Nov 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions assets/terraform/internal/provider/func_create_import_id.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package provider

import (
"context"
"encoding/base64"
"fmt"

"github.com/hashicorp/terraform-plugin-framework/function"
"github.com/hashicorp/terraform-plugin-framework/types"
)

var (
_ function.Function = &ImportStateCreator{}
)

type ImportStateCreator struct{}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: Would you consider rename the struct for better alignement with the purpose of the function described in the definition section of it?


func NewCreateImportIdFunction() function.Function {
return &ImportStateCreator{}
}

func (o *ImportStateCreator) Metadata(ctx context.Context, req function.MetadataRequest, resp *function.MetadataResponse) {
resp.Name = "generate_import_id"
}

func (o *ImportStateCreator) Definition(ctx context.Context, req function.DefinitionRequest, resp *function.DefinitionResponse) {
resp.Definition = function.Definition{
Summary: "Generate Import ID",
Description: "Generate Import ID for the given resource that can be used to import resources into the state.",

Parameters: []function.Parameter{
function.StringParameter{
Name: "resource_asn",
Description: "Name of the resource",
},
function.DynamicParameter{
Name: "resource_data",
Description: "Resource data",
},
},
Return: function.StringReturn{},
}
}

func (o *ImportStateCreator) Run(ctx context.Context, req function.RunRequest, resp *function.RunResponse) {
var resourceAsn string
var dynamicResource types.Dynamic

resp.Error = function.ConcatFuncErrors(resp.Error, req.Arguments.Get(ctx, &resourceAsn, &dynamicResource))
if resp.Error != nil {
return
}

var resource types.Object
switch value := dynamicResource.UnderlyingValue().(type) {
case types.Object:
resource = value
default:
resp.Error = function.ConcatFuncErrors(resp.Error, function.NewArgumentFuncError(1, fmt.Sprintf("Wrong resource type: must be an object")))
return
}

var data []byte

if resourceFuncs, found := resourceFuncMap[resourceAsn]; !found {
resp.Error = function.ConcatFuncErrors(resp.Error, function.NewArgumentFuncError(0, fmt.Sprintf("Unsupported resource type: %s'", resourceAsn)))
return
} else {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: the else branch can be skipped since the previous conditional contains return. This may require to have a unique name for the error returned by resourceFuncs.CreateImportId which also eliminates need for error variable declaration.

var err error
data, err = resourceFuncs.CreateImportId(ctx, resource)
if err != nil {
resp.Error = function.ConcatFuncErrors(resp.Error, function.NewFuncError(err.Error()))
return
}

}

result := base64.StdEncoding.EncodeToString(data)
resp.Error = function.ConcatFuncErrors(resp.Error, resp.Result.Set(ctx, result))
}
174 changes: 0 additions & 174 deletions assets/terraform/internal/provider/tfid.go

This file was deleted.

15 changes: 13 additions & 2 deletions pkg/commands/codegen/codegen.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ func (c *Command) Execute() error {
}
var resourceList []string
var dataSourceList []string
specMetadata := make(map[string]properties.TerraformProviderSpecMetadata)

for _, specPath := range c.specs {
log.Printf("Parsing %s...\n", specPath)
Expand Down Expand Up @@ -126,13 +127,18 @@ func (c *Command) Execute() error {
}

terraformGenerator := generate.NewCreator(config.Output.TerraformProvider, c.templatePath, spec)
dataSources, resources, err := terraformGenerator.RenderTerraformProviderFile(spec, resourceTyp)
dataSources, resources, partialNames, err := terraformGenerator.RenderTerraformProviderFile(spec, resourceTyp)
if err != nil {
return fmt.Errorf("error rendering Terraform provider file for %s - %s", specPath, err)
}

resourceList = append(resourceList, resources...)
dataSourceList = append(dataSourceList, dataSources...)

for k, v := range partialNames {
specMetadata[k] = v
}

}

if pluralVariant {
Expand All @@ -149,13 +155,17 @@ func (c *Command) Execute() error {
}

terraformGenerator := generate.NewCreator(config.Output.TerraformProvider, c.templatePath, spec)
dataSources, resources, err := terraformGenerator.RenderTerraformProviderFile(spec, resourceTyp)
dataSources, resources, partialNames, err := terraformGenerator.RenderTerraformProviderFile(spec, resourceTyp)
if err != nil {
return fmt.Errorf("error rendering Terraform provider file for %s - %s", specPath, err)
}

resourceList = append(resourceList, resources...)
dataSourceList = append(dataSourceList, dataSources...)

for k, v := range partialNames {
specMetadata[k] = v
}
}
} else if c.commandType == properties.CommandTypeSDK && !spec.GoSdkSkip {
generator := generate.NewCreator(config.Output.GoSdk, c.templatePath, spec)
Expand All @@ -173,6 +183,7 @@ func (c *Command) Execute() error {
newProviderObject := properties.NewTerraformProviderFile(providerSpec.Name)
newProviderObject.DataSources = append(newProviderObject.DataSources, dataSourceList...)
newProviderObject.Resources = append(newProviderObject.Resources, resourceList...)
newProviderObject.SpecMetadata = specMetadata

terraformGenerator := generate.NewCreator(config.Output.TerraformProvider, c.templatePath, providerSpec)
err = terraformGenerator.RenderTerraformProvider(newProviderObject, providerSpec, config.TerraformProviderConfig)
Expand Down
14 changes: 7 additions & 7 deletions pkg/generate/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ func (c *Creator) RenderTemplate() error {
}

// RenderTerraformProviderFile generates a Go file for a Terraform provider based on the provided TerraformProviderFile and Normalization arguments.
func (c *Creator) RenderTerraformProviderFile(spec *properties.Normalization, typ properties.ResourceType) ([]string, []string, error) {
func (c *Creator) RenderTerraformProviderFile(spec *properties.Normalization, typ properties.ResourceType) ([]string, []string, map[string]properties.TerraformProviderSpecMetadata, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: we may benefit from separating the successful return data from the error data here. One of the way is to have a dedicated struct as follows:

type RenderArtifacts struct {
	dataSources  []string
	resources    []string
	partialsMetadata map[string]properties.TerraformProviderSpecMetadata
}

func (c *Creator) RenderTerraformProviderFile(spec *properties.Normalization, typ properties.ResourceType) (*RenderArtifacts, error) {
    ...
}

The change can also improve the function's return statements such as return nil, nil, nil, err in several places by making the manipulation of return data more structured and convenient along the way.

var name string
switch typ {
case properties.ResourceUuidPlural:
Expand All @@ -72,19 +72,19 @@ func (c *Creator) RenderTerraformProviderFile(spec *properties.Normalization, ty
tfp := terraform_provider.GenerateTerraformProvider{}

if err := tfp.GenerateTerraformDataSource(typ, spec, terraformProvider); err != nil {
return nil, nil, err
return nil, nil, nil, err
}

if err := tfp.GenerateTerraformResource(typ, spec, terraformProvider); err != nil {
return nil, nil, err
return nil, nil, nil, err
}

if err := tfp.GenerateCommonCode(typ, spec, terraformProvider); err != nil {
return nil, nil, err
return nil, nil, nil, err
}

if err := tfp.GenerateTerraformProviderFile(spec, terraformProvider); err != nil {
return nil, nil, err
return nil, nil, nil, err
}

var filePath string
Expand All @@ -100,10 +100,10 @@ func (c *Creator) RenderTerraformProviderFile(spec *properties.Normalization, ty
}

if err := c.writeFormattedContentToFile(filePath, terraformProvider.Code.String()); err != nil {
return nil, nil, err
return nil, nil, nil, err
}

return terraformProvider.DataSources, terraformProvider.Resources, nil
return terraformProvider.DataSources, terraformProvider.Resources, terraformProvider.SpecMetadata, nil
}

// RenderTerraformProvider generates and writes a Terraform provider file.
Expand Down
Loading