2017-09-28 19:02:39 +00:00
package google
import (
"fmt"
"regexp"
)
2017-10-10 16:53:57 +00:00
const (
2017-10-13 18:05:22 +00:00
globalLinkTemplate = "projects/%s/global/%s/%s"
globalLinkBasePattern = "projects/(.+)/global/%s/(.+)"
zonalLinkTemplate = "projects/%s/zones/%s/%s/%s"
zonalLinkBasePattern = "projects/(.+)/zones/(.+)/%s/(.+)"
zonalPartialLinkBasePattern = "zones/(.+)/%s/(.+)"
2017-11-14 00:05:16 +00:00
organizationLinkTemplate = "organizations/%s/%s/%s"
organizationBasePattern = "organizations/(.+)/%s/(.+)"
2017-10-10 16:53:57 +00:00
)
// ------------------------------------------------------------
// Field helpers
// ------------------------------------------------------------
func ParseNetworkFieldValue ( network string , d TerraformResourceData , config * Config ) ( * GlobalFieldValue , error ) {
return parseGlobalFieldValue ( "networks" , network , "project" , d , config , true )
}
2017-09-28 19:02:39 +00:00
2017-10-13 18:02:42 +00:00
func ParseSslCertificateFieldValue ( sslCertificate string , d TerraformResourceData , config * Config ) ( * GlobalFieldValue , error ) {
return parseGlobalFieldValue ( "sslCertificates" , sslCertificate , "project" , d , config , false )
}
2017-11-08 17:11:17 +00:00
func ParseHttpHealthCheckFieldValue ( healthCheck string , d TerraformResourceData , config * Config ) ( * GlobalFieldValue , error ) {
return parseGlobalFieldValue ( "httpHealthChecks" , healthCheck , "project" , d , config , false )
}
2017-10-23 20:26:59 +00:00
func ParseDiskFieldValue ( disk string , d TerraformResourceData , config * Config ) ( * ZonalFieldValue , error ) {
return parseZonalFieldValue ( "disks" , disk , "project" , "zone" , d , config , false )
}
2017-11-14 00:05:16 +00:00
func ParseOrganizationCustomRoleName ( role string ) ( * OrganizationFieldValue , error ) {
return parseOrganizationFieldValue ( "roles" , role , false )
}
2017-10-10 16:53:57 +00:00
// ------------------------------------------------------------
// Base helpers used to create helpers for specific fields.
// ------------------------------------------------------------
2017-09-28 19:02:39 +00:00
2017-10-10 16:53:57 +00:00
type GlobalFieldValue struct {
2017-09-28 19:02:39 +00:00
Project string
Name string
2017-10-10 16:53:57 +00:00
resourceType string
}
func ( f GlobalFieldValue ) RelativeLink ( ) string {
if len ( f . Name ) == 0 {
return ""
}
return fmt . Sprintf ( globalLinkTemplate , f . Project , f . resourceType , f . Name )
2017-09-28 19:02:39 +00:00
}
2017-10-13 18:05:22 +00:00
// Parses a global field supporting 5 different formats:
// - https://www.googleapis.com/compute/ANY_VERSION/projects/{my_project}/global/{resource_type}/{resource_name}
// - projects/{my_project}/global/{resource_type}/{resource_name}
// - global/{resource_type}/{resource_name}
// - resource_name
2017-10-10 16:53:57 +00:00
// - "" (empty string). RelativeLink() returns empty if isEmptyValid is true.
2017-10-13 18:05:22 +00:00
//
// If the project is not specified, it first tries to get the project from the `projectSchemaField` and then fallback on the default project.
2017-10-10 16:53:57 +00:00
func parseGlobalFieldValue ( resourceType , fieldValue , projectSchemaField string , d TerraformResourceData , config * Config , isEmptyValid bool ) ( * GlobalFieldValue , error ) {
if len ( fieldValue ) == 0 {
if isEmptyValid {
return & GlobalFieldValue { resourceType : resourceType } , nil
}
return nil , fmt . Errorf ( "The global field for resource %s cannot be empty" , resourceType )
}
r := regexp . MustCompile ( fmt . Sprintf ( globalLinkBasePattern , resourceType ) )
2017-10-13 18:05:22 +00:00
if parts := r . FindStringSubmatch ( fieldValue ) ; parts != nil {
2017-10-10 16:53:57 +00:00
return & GlobalFieldValue {
2017-09-28 19:02:39 +00:00
Project : parts [ 1 ] ,
Name : parts [ 2 ] ,
2017-10-10 16:53:57 +00:00
resourceType : resourceType ,
} , nil
2017-09-28 19:02:39 +00:00
}
2017-10-10 16:53:57 +00:00
project , err := getProjectFromSchema ( projectSchemaField , d , config )
if err != nil {
return nil , err
2017-09-28 19:02:39 +00:00
}
2017-10-10 16:53:57 +00:00
return & GlobalFieldValue {
Project : project ,
Name : GetResourceNameFromSelfLink ( fieldValue ) ,
resourceType : resourceType ,
} , nil
2017-09-28 19:02:39 +00:00
}
2017-10-13 18:05:22 +00:00
type ZonalFieldValue struct {
Project string
Zone string
Name string
resourceType string
}
func ( f ZonalFieldValue ) RelativeLink ( ) string {
if len ( f . Name ) == 0 {
return ""
}
return fmt . Sprintf ( zonalLinkTemplate , f . Project , f . Zone , f . resourceType , f . Name )
}
// Parses a zonal field supporting 5 different formats:
// - https://www.googleapis.com/compute/ANY_VERSION/projects/{my_project}/zones/{zone}/{resource_type}/{resource_name}
// - projects/{my_project}/zones/{zone}/{resource_type}/{resource_name}
// - zones/{zone}/{resource_type}/{resource_name}
// - resource_name
// - "" (empty string). RelativeLink() returns empty if isEmptyValid is true.
//
// If the project is not specified, it first tries to get the project from the `projectSchemaField` and then fallback on the default project.
// If the zone is not specified, it takes the value of `zoneSchemaField`.
func parseZonalFieldValue ( resourceType , fieldValue , projectSchemaField , zoneSchemaField string , d TerraformResourceData , config * Config , isEmptyValid bool ) ( * ZonalFieldValue , error ) {
if len ( fieldValue ) == 0 {
if isEmptyValid {
return & ZonalFieldValue { resourceType : resourceType } , nil
}
return nil , fmt . Errorf ( "The zonal field for resource %s cannot be empty." , resourceType )
}
r := regexp . MustCompile ( fmt . Sprintf ( zonalLinkBasePattern , resourceType ) )
if parts := r . FindStringSubmatch ( fieldValue ) ; parts != nil {
return & ZonalFieldValue {
Project : parts [ 1 ] ,
Zone : parts [ 2 ] ,
Name : parts [ 3 ] ,
resourceType : resourceType ,
} , nil
}
project , err := getProjectFromSchema ( projectSchemaField , d , config )
if err != nil {
return nil , err
}
r = regexp . MustCompile ( fmt . Sprintf ( zonalPartialLinkBasePattern , resourceType ) )
if parts := r . FindStringSubmatch ( fieldValue ) ; parts != nil {
return & ZonalFieldValue {
Project : project ,
Zone : parts [ 1 ] ,
Name : parts [ 2 ] ,
resourceType : resourceType ,
} , nil
}
if len ( zoneSchemaField ) == 0 {
return nil , fmt . Errorf ( "Invalid field format. Got '%s', expected format '%s'" , fieldValue , fmt . Sprintf ( globalLinkTemplate , "{project}" , resourceType , "{name}" ) )
}
zone , ok := d . GetOk ( zoneSchemaField )
if ! ok {
return nil , fmt . Errorf ( "A zone must be specified" )
}
return & ZonalFieldValue {
Project : project ,
Zone : zone . ( string ) ,
Name : GetResourceNameFromSelfLink ( fieldValue ) ,
resourceType : resourceType ,
} , nil
}
2017-10-10 16:53:57 +00:00
func getProjectFromSchema ( projectSchemaField string , d TerraformResourceData , config * Config ) ( string , error ) {
res , ok := d . GetOk ( projectSchemaField )
if ! ok || len ( projectSchemaField ) == 0 {
if config . Project != "" {
return config . Project , nil
}
return "" , fmt . Errorf ( "project: required field is not set" )
2017-10-06 16:33:42 +00:00
}
2017-10-10 16:53:57 +00:00
return res . ( string ) , nil
2017-09-28 19:02:39 +00:00
}
2017-11-14 00:05:16 +00:00
type OrganizationFieldValue struct {
OrgId string
Name string
resourceType string
}
func ( f OrganizationFieldValue ) RelativeLink ( ) string {
if len ( f . Name ) == 0 {
return ""
}
return fmt . Sprintf ( organizationLinkTemplate , f . OrgId , f . resourceType , f . Name )
}
// Parses an organization field with the following formats:
// - organizations/{my_organizations}/{resource_type}/{resource_name}
func parseOrganizationFieldValue ( resourceType , fieldValue string , isEmptyValid bool ) ( * OrganizationFieldValue , error ) {
if len ( fieldValue ) == 0 {
if isEmptyValid {
return & OrganizationFieldValue { resourceType : resourceType } , nil
}
return nil , fmt . Errorf ( "The organization field for resource %s cannot be empty" , resourceType )
}
r := regexp . MustCompile ( fmt . Sprintf ( organizationBasePattern , resourceType ) )
if parts := r . FindStringSubmatch ( fieldValue ) ; parts != nil {
return & OrganizationFieldValue {
OrgId : parts [ 1 ] ,
Name : parts [ 2 ] ,
resourceType : resourceType ,
} , nil
}
return nil , fmt . Errorf ( "Invalid field format. Got '%s', expected format '%s'" , fieldValue , fmt . Sprintf ( organizationLinkTemplate , "{org_id}" , resourceType , "{name}" ) )
}