Skip to content

Commit

Permalink
refactor(fgs/dependency): using auto-gen style to replace old coding
Browse files Browse the repository at this point in the history
  • Loading branch information
Lance52259 committed Jan 27, 2025
1 parent 11aee55 commit b6b4463
Show file tree
Hide file tree
Showing 2 changed files with 204 additions and 78 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,7 @@ func getDependencyVersionFunc(conf *config.Config, state *terraform.ResourceStat
return nil, fmt.Errorf("error creating FunctionGraph v2 client: %s", err)
}

dependId, version, err := fgs.ParseDependVersionResourceId(state.Primary.ID)
if err != nil {
return nil, err
}
return dependencies.GetVersion(client, dependId, version)
return fgs.GetDependencyVersionById(client, state.Primary.ID)
}

func TestAccDependencyVersion_basic(t *testing.T) {
Expand Down
276 changes: 203 additions & 73 deletions huaweicloud/services/fgs/resource_huaweicloud_fgs_dependency_version.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ package fgs
import (
"context"
"fmt"
"log"
"strings"

"github.com/hashicorp/go-multierror"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"

"github.com/chnsz/golangsdk"
"github.com/chnsz/golangsdk/openstack/fgs/v2/dependencies"

"github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/common"
"github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/config"
Expand Down Expand Up @@ -99,39 +99,65 @@ func ResourceDependencyVersion() *schema.Resource {
}
}

func buildDependencyVersionOpts(d *schema.ResourceData) dependencies.DependVersionOpts {
func buildCreateDependencyVersionBodyParams(d *schema.ResourceData) map[string]interface{} {
// Since the ZIP file upload is limited in size and requires encoding, only the OBS type is supported.
// The ZIP file uploading can also be achieved by uploading OBS objects and is more secure.
return dependencies.DependVersionOpts{
Name: d.Get("name").(string),
Runtime: d.Get("runtime").(string),
Description: utils.String(d.Get("description").(string)),
Type: "obs",
Link: d.Get("link").(string),
return map[string]interface{}{
"name": d.Get("name").(string),
"runtime": d.Get("runtime").(string),
"description": utils.ValueIgnoreEmpty(d.Get("description").(string)),
"depend_type": "obs",
"depend_link": d.Get("link").(string),
}
}

func resourceDependencyVersionCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
cfg := meta.(*config.Config)
client, err := cfg.FgsV2Client(cfg.GetRegion(d))
var (
cfg = meta.(*config.Config)
region = cfg.GetRegion(d)
httpUrl = "v2/{project_id}/fgs/dependencies/version"
)

client, err := cfg.NewServiceClient("fgs", region)
if err != nil {
return diag.Errorf("error creating FunctionGraph v2 client: %s", err)
return diag.Errorf("error creating FunctionGraph client: %s", err)
}

createPath := client.Endpoint + httpUrl
createPath = strings.ReplaceAll(createPath, "{project_id}", client.ProjectID)
createOpt := golangsdk.RequestOpts{
KeepResponseBody: true,
MoreHeaders: map[string]string{
"Content-Type": "application/json",
},
JSONBody: utils.RemoveNil(buildCreateDependencyVersionBodyParams(d)),
}

resp, err := dependencies.CreateVersion(client, buildDependencyVersionOpts(d))
requestResp, err := client.Request("POST", createPath, &createOpt)
if err != nil {
return diag.Errorf("error creating custom dependency version: %s", err)
return diag.Errorf("error creating FunctionGraph dependent package version: %s", err)
}
respBody, err := utils.FlattenResponse(requestResp)
if err != nil {
return diag.FromErr(err)
}

dependId := utils.PathSearch("dep_id", respBody, "").(string)
dependVersion := utils.PathSearch("version", respBody, float64(0)).(float64)
if dependId == "" || dependVersion == 0 {
return diag.Errorf("unable to find the dependent package version ID or version from the API response")
}

// Using depend ID and version number as the resource ID.
d.SetId(fmt.Sprintf("%s/%d", resp.DepId, resp.Version))
d.SetId(fmt.Sprintf("%s/%v", dependId, dependVersion))

return resourceDependencyVersionRead(ctx, d, meta)
}

func ParseDependVersionResourceId(resourceId string) (dependId, versionInfo string, err error) {
func parseDependVersionResourceId(resourceId string) (dependId, versionInfo string) {
parts := strings.Split(resourceId, "/")
if len(parts) < 2 {
err = fmt.Errorf("invalid ID format for dependency version resource, it must contain two parts: "+
log.Printf("[ERROR] invalid ID format for dependency version resource, it must contain two parts: "+
"dependency package information and version information, e.g. '<dependency name>/<version number>'. "+
"but the ID that you provided does not meet this requirement '%s'", resourceId)
return
Expand All @@ -141,18 +167,43 @@ func ParseDependVersionResourceId(resourceId string) (dependId, versionInfo stri
return
}

func resourceDependencyVersionRead(_ context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
cfg := meta.(*config.Config)
client, err := cfg.FgsV2Client(cfg.GetRegion(d))
func GetDependencyVersionById(client *golangsdk.ServiceClient, resourceId string) (interface{}, error) {
var (
httpUrl = "v2/{project_id}/fgs/dependencies/{depend_id}/version/{version}"
dependId, dependVersion = parseDependVersionResourceId(resourceId)
)

getPath := client.Endpoint + httpUrl
getPath = strings.ReplaceAll(getPath, "{project_id}", client.ProjectID)
getPath = strings.ReplaceAll(getPath, "{depend_id}", dependId)
getPath = strings.ReplaceAll(getPath, "{version}", dependVersion)
getOpt := golangsdk.RequestOpts{
KeepResponseBody: true,
MoreHeaders: map[string]string{
"Content-Type": "application/json",
},
}

requestResp, err := client.Request("GET", getPath, &getOpt)
if err != nil {
return diag.Errorf("error creating FunctionGraph v2 client: %s", err)
return nil, fmt.Errorf("error creating FunctionGraph application: %s", err)
}
return utils.FlattenResponse(requestResp)
}

func resourceDependencyVersionRead(_ context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
var (
cfg = meta.(*config.Config)
region = cfg.GetRegion(d)
resourceId = d.Id()
)

dependId, version, err := ParseDependVersionResourceId(d.Id())
client, err := cfg.NewServiceClient("fgs", region)
if err != nil {
return diag.FromErr(err)
return diag.Errorf("error creating FunctionGraph client: %s", err)
}
resp, err := dependencies.GetVersion(client, dependId, version)

respBody, err := GetDependencyVersionById(client, resourceId)
if err != nil {
return common.CheckDeletedDiag(d, err, "FunctionGraph dependency version")
}
Expand All @@ -162,15 +213,15 @@ func resourceDependencyVersionRead(_ context.Context, d *schema.ResourceData, me
// If the ReadContext is set this value according to the query result, ForceNew behavior will be triggered the next
// time it is applied.
mErr := multierror.Append(
d.Set("runtime", resp.Runtime),
d.Set("name", resp.Name),
d.Set("description", resp.Description),
d.Set("etag", resp.Etag),
d.Set("size", resp.Size),
d.Set("owner", resp.Owner),
d.Set("version", resp.Version),
d.Set("version_id", resp.ID),
d.Set("dependency_id", resp.DepId),
d.Set("runtime", utils.PathSearch("runtime", respBody, nil)),
d.Set("name", utils.PathSearch("name", respBody, nil)),
d.Set("description", utils.PathSearch("description", respBody, nil)),
d.Set("etag", utils.PathSearch("etag", respBody, nil)),
d.Set("size", utils.PathSearch("size", respBody, nil)),
d.Set("owner", utils.PathSearch("owner", respBody, nil)),
d.Set("version", utils.PathSearch("version", respBody, nil)),
d.Set("version_id", utils.PathSearch("id", respBody, nil)),
d.Set("dependency_id", utils.PathSearch("dep_id", respBody, nil)),
)
if err := mErr.ErrorOrNil(); err != nil {
return diag.Errorf("error setting resource fields of custom dependency version (%s): %s", d.Id(), err)
Expand All @@ -180,79 +231,158 @@ func resourceDependencyVersionRead(_ context.Context, d *schema.ResourceData, me
}

func resourceDependencyVersionDelete(_ context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
cfg := meta.(*config.Config)
client, err := cfg.FgsV2Client(cfg.GetRegion(d))
var (
cfg = meta.(*config.Config)
region = cfg.GetRegion(d)
httpUrl = "v2/{project_id}/fgs/dependencies/{depend_id}/version/{version}"
resourceId = d.Id()
dependId, dependVersion = parseDependVersionResourceId(resourceId)
)

client, err := cfg.NewServiceClient("fgs", region)
if err != nil {
return diag.Errorf("error creating FunctionGraph v2 client: %s", err)
return diag.Errorf("error creating FunctionGraph client: %s", err)
}

dependId, version, err := ParseDependVersionResourceId(d.Id())
if err != nil {
return diag.FromErr(err)
deletePath := client.Endpoint + httpUrl
deletePath = strings.ReplaceAll(deletePath, "{project_id}", client.ProjectID)
deletePath = strings.ReplaceAll(deletePath, "{depend_id}", dependId)
deletePath = strings.ReplaceAll(deletePath, "{version}", dependVersion)
deleteOpt := golangsdk.RequestOpts{
KeepResponseBody: true,
MoreHeaders: map[string]string{
"Content-Type": "application/json",
},
}
err = dependencies.DeleteVersion(client, dependId, version)

_, err = client.Request("DELETE", deletePath, &deleteOpt)
if err != nil {
return common.CheckDeletedDiag(d, err, "error deleting custom dependency version")
}
return nil
}

func getDependencies(client *golangsdk.ServiceClient) ([]interface{}, error) {
var (
httpUrl = "v2/{project_id}/fgs/dependencies?maxitems=100"
marker = 0
)

listPath := client.Endpoint + httpUrl
listPath = strings.ReplaceAll(listPath, "{project_id}", client.ProjectID)
listOpt := golangsdk.RequestOpts{
KeepResponseBody: true,
MoreHeaders: map[string]string{
"Content-Type": "application/json",
},
}

result := make([]interface{}, 0)
for {
listPathWithMarker := fmt.Sprintf("%s&&marker=%v", listPath, marker)
requestResp, err := client.Request("GET", listPathWithMarker, &listOpt)
if err != nil {
return nil, fmt.Errorf("error querying dependent packages: %s", err)
}
respBody, err := utils.FlattenResponse(requestResp)
if err != nil {
return nil, err
}
dependencies := utils.PathSearch("dependencies", respBody, make([]interface{}, 0)).([]interface{})
if len(dependencies) < 1 {
break
}
result = append(result, dependencies...)
marker += len(dependencies)
}

return result, nil
}

func getDependencyVersions(client *golangsdk.ServiceClient, dependId string) ([]interface{}, error) {
var (
httpUrl = "v2/{project_id}/fgs/dependencies/{depend_id}/version?maxitems=100"
marker = 0
)

listPath := client.Endpoint + httpUrl
listPath = strings.ReplaceAll(listPath, "{project_id}", client.ProjectID)
listPath = strings.ReplaceAll(listPath, "{depend_id}", dependId)
listOpt := golangsdk.RequestOpts{
KeepResponseBody: true,
MoreHeaders: map[string]string{
"Content-Type": "application/json",
},
}

result := make([]interface{}, 0)
for {
listPathWithMarker := fmt.Sprintf("%s&&marker=%v", listPath, marker)
requestResp, err := client.Request("GET", listPathWithMarker, &listOpt)
if err != nil {
return nil, fmt.Errorf("error querying dependent package versions: %s", err)
}
respBody, err := utils.FlattenResponse(requestResp)
if err != nil {
return nil, err
}
dependencies := utils.PathSearch("dependencies", respBody, make([]interface{}, 0)).([]interface{})
if len(dependencies) < 1 {
break
}
result = append(result, dependencies...)
marker += len(dependencies)
}

return result, nil
}

// getSpecifiedDependencyVersion is a method that queries the corresponding dependency version based on the entered ID.
// The entered ID can be in the following formats:
// + <depend_id>/<version> (Standard resource ID format)
// + <depend_id>/<version_id>
// + <depend_name>/<version> (All information that can be found through the console)
// + <depend_name>/<version_id>
func getSpecifiedDependencyVersion(client *golangsdk.ServiceClient, resourceId string) (*dependencies.DependencyVersion, error) {
dependInfo, versionInfo, err := ParseDependVersionResourceId(resourceId)
if err != nil {
return nil, err
}
func refreshSpecifiedDependencyVersion(client *golangsdk.ServiceClient, resourceId string) (dependId, dependVersion string, err error) {
dependId, dependVersion = parseDependVersionResourceId(resourceId)

var resultList []interface{}
// If the input dependency package information part is not in UUID format, perform a query to obtain the
// corresponding ID.
if !utils.IsUUID(dependInfo) {
opts := dependencies.ListOpts{
Name: dependInfo,
}
allPages, err := dependencies.List(client, opts).AllPages()
if !utils.IsUUID(dependId) {
resultList, err = getDependencies(client)
if err != nil {
return nil, err
return dependId, dependVersion, err
}
listResp, _ := dependencies.ExtractDependencies(allPages)
if len(listResp.Dependencies) < 1 {
return nil, golangsdk.ErrDefault404{
dependId = utils.PathSearch(fmt.Sprintf("[?name=='%s']|[0].id", dependId), resultList, "").(string)
if dependId == "" {
return dependId, dependVersion, golangsdk.ErrDefault404{
ErrUnexpectedResponseCode: golangsdk.ErrUnexpectedResponseCode{
Body: []byte(fmt.Sprintf("unable to find the dependency package using its name: %s", dependInfo)),
Body: []byte(fmt.Sprintf("unable to find the dependency package using its name: %s", dependId)),
},
}
}
// Make sure the dependInfo content is the dependency ID.
dependInfo = listResp.Dependencies[0].ID
}

// If the input dependency version information part is in UUID format, perform a query to obtain the specified
// version using its ID.
if utils.IsUUID(versionInfo) {
opts := dependencies.ListVersionsOpts{
DependId: dependInfo,
}
listResp, err := dependencies.ListVersions(client, opts)
if utils.IsUUID(dependVersion) {
resultList, err := getDependencyVersions(client, dependId)
if err != nil {
return nil, err
return dependId, dependVersion, err
}
for _, dependVersion := range listResp {
if dependVersion.ID == versionInfo {
return &dependVersion, nil
dependVersion = fmt.Sprint(utils.PathSearch(fmt.Sprintf("[?id=='%s']|[0].version", dependVersion),
resultList, float64(0)).(float64))
if dependVersion == "" {
return dependId, dependVersion, golangsdk.ErrDefault404{
ErrUnexpectedResponseCode: golangsdk.ErrUnexpectedResponseCode{
Body: []byte(fmt.Sprintf("unable to find the dependency package version using its ID: %s", dependVersion)),
},
}
}
return nil, golangsdk.ErrDefault404{
ErrUnexpectedResponseCode: golangsdk.ErrUnexpectedResponseCode{
Body: []byte(fmt.Sprintf("unable to find the dependency package using its ID: %s", versionInfo)),
},
}
}
return dependencies.GetVersion(client, dependInfo, versionInfo)

return dependId, dependVersion, nil
}

func resourceDependencyVersionImportState(_ context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
Expand All @@ -263,11 +393,11 @@ func resourceDependencyVersionImportState(_ context.Context, d *schema.ResourceD
}

// Query the corresponding dependency version based on the user's import ID.
resp, err := getSpecifiedDependencyVersion(client, d.Id())
dependId, dependVersion, err := refreshSpecifiedDependencyVersion(client, d.Id())
if err != nil {
return []*schema.ResourceData{d}, err
}
d.SetId(fmt.Sprintf("%s/%d", resp.DepId, resp.Version))
d.SetId(fmt.Sprintf("%s/%v", dependId, dependVersion))

return []*schema.ResourceData{d}, nil
}

0 comments on commit b6b4463

Please sign in to comment.