pkg/tfplan2cai/ancestrymanager/ancestryutil.go (110 lines of code) (raw):
package ancestrymanager
import (
"fmt"
"strings"
"github.com/hashicorp/errwrap"
"github.com/hashicorp/terraform-provider-google-beta/google-beta/tpgresource"
transport_tpg "github.com/hashicorp/terraform-provider-google-beta/google-beta/transport"
"google.golang.org/api/googleapi"
)
// assetParent derives a resource's parent from its ancestors.
func assetParent(caiType string, ancestors []string) (string, error) {
if caiType == "" {
return "", fmt.Errorf("asset not provided")
}
switch caiType {
case "cloudresourcemanager.googleapis.com/Folder":
if len(ancestors) > 1 {
parent := ancestors[1]
if strings.HasPrefix(parent, "folders/") || strings.HasPrefix(parent, "organizations/") {
return fmt.Sprintf("//cloudresourcemanager.googleapis.com/%s", ancestors[1]), nil
}
}
if len(ancestors) == 1 && strings.HasPrefix(ancestors[0], "organizations/") {
// organizations/unknown
return fmt.Sprintf("//cloudresourcemanager.googleapis.com/%s", ancestors[0]), nil
}
case "cloudresourcemanager.googleapis.com/Organization":
return "", nil
case "cloudresourcemanager.googleapis.com/Project":
if len(ancestors) < 1 {
return "", fmt.Errorf("unexpected value for ancestors: %s", ancestors)
}
if strings.HasPrefix(ancestors[0], "projects/") {
if len(ancestors) > 1 {
return fmt.Sprintf("//cloudresourcemanager.googleapis.com/%s", ancestors[1]), nil
}
}
return fmt.Sprintf("//cloudresourcemanager.googleapis.com/%s", ancestors[0]), nil
default:
if len(ancestors) < 1 {
return "", fmt.Errorf("unexpected value for ancestors: %s", ancestors)
}
return fmt.Sprintf("//cloudresourcemanager.googleapis.com/%s", ancestors[0]), nil
}
return "", fmt.Errorf("unexpected value for ancestors: %v", ancestors)
}
// ConvertToAncestryPath composes a path containing organization/folder/project
// (i.e. "organization/my-org/folder/my-folder/project/my-prj").
func ConvertToAncestryPath(as []string) string {
var path []string
for i := len(as) - 1; i >= 0; i-- {
path = append(path, as[i])
}
str := strings.Join(path, "/")
return sanitizeAncestryPath(str)
}
func sanitizeAncestryPath(s string) string {
ret := s
// convert back to match existing ancestry path style.
for _, r := range []struct {
old string
new string
}{
{"organizations/", "organization/"},
{"folders/", "folder/"},
{"projects/", "project/"},
} {
ret = strings.ReplaceAll(ret, r.old, r.new)
}
return ret
}
func getProjectFromSchema(projectSchemaField string, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (string, error) {
res, ok := d.GetOk(projectSchemaField)
if ok && projectSchemaField != "" {
return res.(string), nil
}
res, ok = d.GetOk("parent")
if ok && strings.HasPrefix(res.(string), "projects/") {
return res.(string), nil
}
if config.Project != "" {
return config.Project, nil
}
return "", fmt.Errorf("required field '%s' is not set, you may use --project=my-project to provide a default project to resolve the issue", projectSchemaField)
}
// getOrganizationFromResource reads org_id field from terraform data.
func getOrganizationFromResource(tfData tpgresource.TerraformResourceData) (string, bool) {
orgID, ok := tfData.GetOk("org_id")
if ok {
return orgID.(string), ok
}
orgID, ok = tfData.GetOk("parent")
if ok && strings.HasPrefix(orgID.(string), "organizations/") {
return orgID.(string), ok
}
return "", false
}
// getFolderFromResource reads folder_id, folder, parent field from terraform data.
func getFolderFromResource(tfData tpgresource.TerraformResourceData) (string, bool) {
folderID, ok := tfData.GetOk("folder_id")
if ok {
return folderID.(string), ok
}
folderID, ok = tfData.GetOk("folder")
if ok {
return folderID.(string), ok
}
folderID, ok = tfData.GetOk("parent")
if ok && strings.HasPrefix(folderID.(string), "folders/") {
return folderID.(string), ok
}
return "", false
}
// isGoogleApiErrorWithCode cheks if the error code is of given type or not.
func isGoogleApiErrorWithCode(err error, errCode int) bool {
gerr, ok := errwrap.GetType(err, &googleapi.Error{}).(*googleapi.Error)
return ok && gerr != nil && gerr.Code == errCode
}