2017-10-27 16:40:01 +00:00
package google
import (
"fmt"
"log"
"regexp"
"strings"
2018-08-17 21:33:27 +00:00
"time"
2018-04-19 21:30:20 +00:00
"github.com/hashicorp/terraform/helper/schema"
"google.golang.org/api/cloudkms/v1"
2017-10-27 16:40:01 +00:00
)
func resourceKmsKeyRing ( ) * schema . Resource {
return & schema . Resource {
Create : resourceKmsKeyRingCreate ,
Read : resourceKmsKeyRingRead ,
Delete : resourceKmsKeyRingDelete ,
Importer : & schema . ResourceImporter {
State : resourceKmsKeyRingImportState ,
} ,
Schema : map [ string ] * schema . Schema {
2018-12-14 20:51:11 +00:00
"name" : {
2017-10-27 16:40:01 +00:00
Type : schema . TypeString ,
Required : true ,
ForceNew : true ,
} ,
2018-12-14 20:51:11 +00:00
"location" : {
2017-10-27 16:40:01 +00:00
Type : schema . TypeString ,
Required : true ,
ForceNew : true ,
} ,
2018-12-14 20:51:11 +00:00
"project" : {
2017-10-27 16:40:01 +00:00
Type : schema . TypeString ,
Optional : true ,
2017-11-28 00:32:20 +00:00
Computed : true ,
2017-10-27 16:40:01 +00:00
ForceNew : true ,
} ,
2018-12-14 20:51:11 +00:00
"self_link" : {
2018-08-17 21:33:27 +00:00
Type : schema . TypeString ,
Computed : true ,
} ,
2017-10-27 16:40:01 +00:00
} ,
}
}
type kmsKeyRingId struct {
Project string
Location string
Name string
}
func ( s * kmsKeyRingId ) keyRingId ( ) string {
return fmt . Sprintf ( "projects/%s/locations/%s/keyRings/%s" , s . Project , s . Location , s . Name )
}
func ( s * kmsKeyRingId ) parentId ( ) string {
return fmt . Sprintf ( "projects/%s/locations/%s" , s . Project , s . Location )
}
func ( s * kmsKeyRingId ) terraformId ( ) string {
return fmt . Sprintf ( "%s/%s/%s" , s . Project , s . Location , s . Name )
}
func resourceKmsKeyRingCreate ( d * schema . ResourceData , meta interface { } ) error {
config := meta . ( * Config )
project , err := getProject ( d , config )
if err != nil {
return err
}
keyRingId := & kmsKeyRingId {
Project : project ,
Location : d . Get ( "location" ) . ( string ) ,
Name : d . Get ( "name" ) . ( string ) ,
}
2018-08-17 21:33:27 +00:00
// This resource is often created just after a project, and requires
// billing support, which is eventually consistent. We attempt to
// wait on billing support in the project resource, but we can't
// always get it right - this retry fixes a lot of flaky tests we were
// noticing.
err = retryTimeDuration ( func ( ) error {
keyRing , err := config . clientKms . Projects . Locations . KeyRings . Create ( keyRingId . parentId ( ) , & cloudkms . KeyRing { } ) . KeyRingId ( keyRingId . Name ) . Do ( )
2017-10-27 16:40:01 +00:00
2018-08-17 21:33:27 +00:00
if err != nil {
return fmt . Errorf ( "Error creating KeyRing: %s" , err )
}
2017-10-27 16:40:01 +00:00
2018-08-17 21:33:27 +00:00
log . Printf ( "[DEBUG] Created KeyRing %s" , keyRing . Name )
2017-10-27 16:40:01 +00:00
2018-08-17 21:33:27 +00:00
d . SetId ( keyRingId . keyRingId ( ) )
return nil
2018-12-15 02:16:33 +00:00
} , 30 * time . Second )
2018-08-17 21:33:27 +00:00
if err != nil {
return err
}
2017-10-27 16:40:01 +00:00
return resourceKmsKeyRingRead ( d , meta )
}
func resourceKmsKeyRingRead ( d * schema . ResourceData , meta interface { } ) error {
config := meta . ( * Config )
2017-11-28 00:32:20 +00:00
project , err := getProject ( d , config )
if err != nil {
return err
}
2017-10-27 16:40:01 +00:00
keyRingId , err := parseKmsKeyRingId ( d . Id ( ) , config )
if err != nil {
return err
}
log . Printf ( "[DEBUG] Executing read for KMS KeyRing %s" , keyRingId . keyRingId ( ) )
2018-08-17 21:33:27 +00:00
keyRing , err := config . clientKms . Projects . Locations . KeyRings . Get ( keyRingId . keyRingId ( ) ) . Do ( )
2017-10-27 16:40:01 +00:00
if err != nil {
return fmt . Errorf ( "Error reading KeyRing: %s" , err )
}
2017-11-28 00:32:20 +00:00
d . Set ( "project" , project )
2018-08-17 21:33:27 +00:00
d . Set ( "self_link" , keyRing . Name )
2017-11-28 00:32:20 +00:00
2017-10-27 16:40:01 +00:00
return nil
}
/ *
Because KMS KeyRing resources cannot be deleted on GCP , we are only going to remove it from state .
Re - creation of this resource through Terraform will produce an error .
* /
func resourceKmsKeyRingDelete ( d * schema . ResourceData , meta interface { } ) error {
config := meta . ( * Config )
keyRingId , err := parseKmsKeyRingId ( d . Id ( ) , config )
if err != nil {
return err
}
log . Printf ( "[WARNING] KMS KeyRing resources cannot be deleted from GCP. This KeyRing %s will be removed from Terraform state, but will still be present on the server." , keyRingId . keyRingId ( ) )
d . SetId ( "" )
return nil
}
func parseKmsKeyRingId ( id string , config * Config ) ( * kmsKeyRingId , error ) {
parts := strings . Split ( id , "/" )
2018-08-14 18:48:08 +00:00
keyRingIdRegex := regexp . MustCompile ( "^(" + ProjectRegex + ")/([a-z0-9-])+/([a-zA-Z0-9_-]{1,63})$" )
2017-10-27 16:40:01 +00:00
keyRingIdWithoutProjectRegex := regexp . MustCompile ( "^([a-z0-9-])+/([a-zA-Z0-9_-]{1,63})$" )
2018-08-14 18:48:08 +00:00
keyRingRelativeLinkRegex := regexp . MustCompile ( "^projects/(" + ProjectRegex + ")/locations/([a-z0-9-]+)/keyRings/([a-zA-Z0-9_-]{1,63})$" )
2017-10-27 16:40:01 +00:00
if keyRingIdRegex . MatchString ( id ) {
return & kmsKeyRingId {
Project : parts [ 0 ] ,
Location : parts [ 1 ] ,
Name : parts [ 2 ] ,
} , nil
}
if keyRingIdWithoutProjectRegex . MatchString ( id ) {
if config . Project == "" {
return nil , fmt . Errorf ( "The default project for the provider must be set when using the `{location}/{keyRingName}` id format." )
}
return & kmsKeyRingId {
Project : config . Project ,
Location : parts [ 0 ] ,
Name : parts [ 1 ] ,
} , nil
}
2018-04-19 21:30:20 +00:00
if parts := keyRingRelativeLinkRegex . FindStringSubmatch ( id ) ; parts != nil {
return & kmsKeyRingId {
Project : parts [ 1 ] ,
Location : parts [ 2 ] ,
Name : parts [ 3 ] ,
} , nil
}
2017-10-27 16:40:01 +00:00
return nil , fmt . Errorf ( "Invalid KeyRing id format, expecting `{projectId}/{locationId}/{keyRingName}` or `{locationId}/{keyRingName}.`" )
}
func resourceKmsKeyRingImportState ( d * schema . ResourceData , meta interface { } ) ( [ ] * schema . ResourceData , error ) {
config := meta . ( * Config )
keyRingId , err := parseKmsKeyRingId ( d . Id ( ) , config )
if err != nil {
return nil , err
}
d . Set ( "name" , keyRingId . Name )
d . Set ( "location" , keyRingId . Location )
if config . Project != keyRingId . Project {
d . Set ( "project" , keyRingId . Project )
}
2018-04-19 21:30:20 +00:00
d . SetId ( keyRingId . keyRingId ( ) )
2017-10-27 16:40:01 +00:00
return [ ] * schema . ResourceData { d } , nil
}