mirror of
https://github.com/letic/terraform-provider-google.git
synced 2024-07-06 02:02:43 +00:00
Add support for Google Cloud IoT Core registry (#970)
This commit is contained in:
parent
c18ac00e8f
commit
fec2f0bc02
|
@ -19,6 +19,7 @@ import (
|
||||||
"google.golang.org/api/bigquery/v2"
|
"google.golang.org/api/bigquery/v2"
|
||||||
"google.golang.org/api/cloudbilling/v1"
|
"google.golang.org/api/cloudbilling/v1"
|
||||||
"google.golang.org/api/cloudfunctions/v1"
|
"google.golang.org/api/cloudfunctions/v1"
|
||||||
|
"google.golang.org/api/cloudiot/v1"
|
||||||
"google.golang.org/api/cloudkms/v1"
|
"google.golang.org/api/cloudkms/v1"
|
||||||
"google.golang.org/api/cloudresourcemanager/v1"
|
"google.golang.org/api/cloudresourcemanager/v1"
|
||||||
resourceManagerV2Beta1 "google.golang.org/api/cloudresourcemanager/v2beta1"
|
resourceManagerV2Beta1 "google.golang.org/api/cloudresourcemanager/v2beta1"
|
||||||
|
@ -71,6 +72,7 @@ type Config struct {
|
||||||
clientServiceMan *servicemanagement.APIService
|
clientServiceMan *servicemanagement.APIService
|
||||||
clientBigQuery *bigquery.Service
|
clientBigQuery *bigquery.Service
|
||||||
clientCloudFunctions *cloudfunctions.Service
|
clientCloudFunctions *cloudfunctions.Service
|
||||||
|
clientCloudIoT *cloudiot.Service
|
||||||
|
|
||||||
bigtableClientFactory *BigtableClientFactory
|
bigtableClientFactory *BigtableClientFactory
|
||||||
}
|
}
|
||||||
|
@ -294,6 +296,13 @@ func (c *Config) loadAndValidate() error {
|
||||||
}
|
}
|
||||||
c.clientDataproc.UserAgent = userAgent
|
c.clientDataproc.UserAgent = userAgent
|
||||||
|
|
||||||
|
log.Printf("[INFO] Instantiating Google Cloud IoT Core Client...")
|
||||||
|
c.clientCloudIoT, err = cloudiot.New(client)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
c.clientCloudIoT.UserAgent = userAgent
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -90,6 +90,7 @@ func Provider() terraform.ResourceProvider {
|
||||||
"google_bigtable_instance": resourceBigtableInstance(),
|
"google_bigtable_instance": resourceBigtableInstance(),
|
||||||
"google_bigtable_table": resourceBigtableTable(),
|
"google_bigtable_table": resourceBigtableTable(),
|
||||||
"google_cloudfunctions_function": resourceCloudFunctionsFunction(),
|
"google_cloudfunctions_function": resourceCloudFunctionsFunction(),
|
||||||
|
"google_cloudiot_registry": resourceCloudIoTRegistry(),
|
||||||
"google_compute_autoscaler": resourceComputeAutoscaler(),
|
"google_compute_autoscaler": resourceComputeAutoscaler(),
|
||||||
"google_compute_address": resourceComputeAddress(),
|
"google_compute_address": resourceComputeAddress(),
|
||||||
"google_compute_backend_bucket": resourceComputeBackendBucket(),
|
"google_compute_backend_bucket": resourceComputeBackendBucket(),
|
||||||
|
|
371
google/resource_cloudiot_registry.go
Normal file
371
google/resource_cloudiot_registry.go
Normal file
|
@ -0,0 +1,371 @@
|
||||||
|
package google
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
|
"github.com/hashicorp/terraform/helper/validation"
|
||||||
|
"google.golang.org/api/cloudiot/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
mqttEnabled = "MQTT_ENABLED"
|
||||||
|
mqttDisabled = "MQTT_DISABLED"
|
||||||
|
httpEnabled = "HTTP_ENABLED"
|
||||||
|
httpDisabled = "HTTP_DISABLED"
|
||||||
|
x509CertificatePEM = "X509_CERTIFICATE_PEM"
|
||||||
|
)
|
||||||
|
|
||||||
|
func resourceCloudIoTRegistry() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
Create: resourceCloudIoTRegistryCreate,
|
||||||
|
Update: resourceCloudIoTRegistryUpdate,
|
||||||
|
Read: resourceCloudIoTRegistryRead,
|
||||||
|
Delete: resourceCloudIoTRegistryDelete,
|
||||||
|
|
||||||
|
Importer: &schema.ResourceImporter{
|
||||||
|
State: resourceCloudIoTRegistryStateImporter,
|
||||||
|
},
|
||||||
|
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"name": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
ValidateFunc: validateCloudIoTID,
|
||||||
|
},
|
||||||
|
"project": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
"region": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
"event_notification_config": &schema.Schema{
|
||||||
|
Type: schema.TypeMap,
|
||||||
|
Optional: true,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"pubsub_topic_name": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
DiffSuppressFunc: compareSelfLinkOrResourceName,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"state_notification_config": &schema.Schema{
|
||||||
|
Type: schema.TypeMap,
|
||||||
|
Optional: true,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"pubsub_topic_name": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
DiffSuppressFunc: compareSelfLinkOrResourceName,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"mqtt_config": &schema.Schema{
|
||||||
|
Type: schema.TypeMap,
|
||||||
|
Optional: true,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"mqtt_enabled_state": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ValidateFunc: validation.StringInSlice(
|
||||||
|
[]string{mqttEnabled, mqttDisabled}, false),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"http_config": &schema.Schema{
|
||||||
|
Type: schema.TypeMap,
|
||||||
|
Optional: true,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"http_enabled_state": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ValidateFunc: validation.StringInSlice(
|
||||||
|
[]string{httpEnabled, httpDisabled}, false),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"credentials": &schema.Schema{
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Optional: true,
|
||||||
|
MaxItems: 10,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"public_key_certificate": &schema.Schema{
|
||||||
|
Type: schema.TypeMap,
|
||||||
|
Optional: true,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"format": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ValidateFunc: validation.StringInSlice(
|
||||||
|
[]string{x509CertificatePEM}, false),
|
||||||
|
},
|
||||||
|
"certificate": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildEventNotificationConfig(config map[string]interface{}) *cloudiot.EventNotificationConfig {
|
||||||
|
if v, ok := config["pubsub_topic_name"]; ok {
|
||||||
|
return &cloudiot.EventNotificationConfig{
|
||||||
|
PubsubTopicName: v.(string),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildStateNotificationConfig(config map[string]interface{}) *cloudiot.StateNotificationConfig {
|
||||||
|
if v, ok := config["pubsub_topic_name"]; ok {
|
||||||
|
return &cloudiot.StateNotificationConfig{
|
||||||
|
PubsubTopicName: v.(string),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildMqttConfig(config map[string]interface{}) *cloudiot.MqttConfig {
|
||||||
|
if v, ok := config["mqtt_enabled_state"]; ok {
|
||||||
|
return &cloudiot.MqttConfig{
|
||||||
|
MqttEnabledState: v.(string),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildHttpConfig(config map[string]interface{}) *cloudiot.HttpConfig {
|
||||||
|
if v, ok := config["http_enabled_state"]; ok {
|
||||||
|
return &cloudiot.HttpConfig{
|
||||||
|
HttpEnabledState: v.(string),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildPublicKeyCertificate(certificate map[string]interface{}) *cloudiot.PublicKeyCertificate {
|
||||||
|
cert := &cloudiot.PublicKeyCertificate{
|
||||||
|
Format: certificate["format"].(string),
|
||||||
|
Certificate: certificate["certificate"].(string),
|
||||||
|
}
|
||||||
|
return cert
|
||||||
|
}
|
||||||
|
|
||||||
|
func expandCredentials(credentials []interface{}) []*cloudiot.RegistryCredential {
|
||||||
|
certificates := make([]*cloudiot.RegistryCredential, len(credentials))
|
||||||
|
for i, raw := range credentials {
|
||||||
|
cred := raw.(map[string]interface{})
|
||||||
|
certificates[i] = &cloudiot.RegistryCredential{
|
||||||
|
PublicKeyCertificate: buildPublicKeyCertificate(cred["public_key_certificate"].(map[string]interface{})),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return certificates
|
||||||
|
}
|
||||||
|
|
||||||
|
func createDeviceRegistry(d *schema.ResourceData) *cloudiot.DeviceRegistry {
|
||||||
|
deviceRegistry := &cloudiot.DeviceRegistry{}
|
||||||
|
if v, ok := d.GetOk("event_notification_config"); ok {
|
||||||
|
deviceRegistry.EventNotificationConfigs = make([]*cloudiot.EventNotificationConfig, 1, 1)
|
||||||
|
deviceRegistry.EventNotificationConfigs[0] = buildEventNotificationConfig(v.(map[string]interface{}))
|
||||||
|
}
|
||||||
|
if v, ok := d.GetOk("state_notification_config"); ok {
|
||||||
|
deviceRegistry.StateNotificationConfig = buildStateNotificationConfig(v.(map[string]interface{}))
|
||||||
|
}
|
||||||
|
if v, ok := d.GetOk("mqtt_config"); ok {
|
||||||
|
deviceRegistry.MqttConfig = buildMqttConfig(v.(map[string]interface{}))
|
||||||
|
}
|
||||||
|
if v, ok := d.GetOk("http_config"); ok {
|
||||||
|
deviceRegistry.HttpConfig = buildHttpConfig(v.(map[string]interface{}))
|
||||||
|
}
|
||||||
|
if v, ok := d.GetOk("credentials"); ok {
|
||||||
|
deviceRegistry.Credentials = expandCredentials(v.([]interface{}))
|
||||||
|
}
|
||||||
|
return deviceRegistry
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceCloudIoTRegistryCreate(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
config := meta.(*Config)
|
||||||
|
project, err := getProject(d, config)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
region, err := getRegion(d, config)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
deviceRegistry := createDeviceRegistry(d)
|
||||||
|
deviceRegistry.Id = d.Get("name").(string)
|
||||||
|
parent := fmt.Sprintf("projects/%s/locations/%s", project, region)
|
||||||
|
registryId := fmt.Sprintf("%s/registries/%s", parent, deviceRegistry.Id)
|
||||||
|
d.SetId(registryId)
|
||||||
|
|
||||||
|
_, err = config.clientCloudIoT.Projects.Locations.Registries.Create(parent, deviceRegistry).Do()
|
||||||
|
if err != nil {
|
||||||
|
d.SetId("")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return resourceCloudIoTRegistryRead(d, meta)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceCloudIoTRegistryUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
config := meta.(*Config)
|
||||||
|
updateMask := make([]string, 0, 5)
|
||||||
|
hasChanged := false
|
||||||
|
deviceRegistry := &cloudiot.DeviceRegistry{}
|
||||||
|
|
||||||
|
d.Partial(true)
|
||||||
|
|
||||||
|
if d.HasChange("event_notification_config") {
|
||||||
|
hasChanged = true
|
||||||
|
updateMask = append(updateMask, "event_notification_config")
|
||||||
|
if v, ok := d.GetOk("event_notification_config"); ok {
|
||||||
|
deviceRegistry.EventNotificationConfigs = make([]*cloudiot.EventNotificationConfig, 1, 1)
|
||||||
|
deviceRegistry.EventNotificationConfigs[0] = buildEventNotificationConfig(v.(map[string]interface{}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if d.HasChange("state_notification_config") {
|
||||||
|
hasChanged = true
|
||||||
|
updateMask = append(updateMask, "state_notification_config")
|
||||||
|
if v, ok := d.GetOk("state_notification_config"); ok {
|
||||||
|
deviceRegistry.StateNotificationConfig = buildStateNotificationConfig(v.(map[string]interface{}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if d.HasChange("mqtt_config") {
|
||||||
|
hasChanged = true
|
||||||
|
updateMask = append(updateMask, "mqtt_config")
|
||||||
|
if v, ok := d.GetOk("mqtt_config"); ok {
|
||||||
|
deviceRegistry.MqttConfig = buildMqttConfig(v.(map[string]interface{}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if d.HasChange("http_config") {
|
||||||
|
hasChanged = true
|
||||||
|
updateMask = append(updateMask, "http_config")
|
||||||
|
if v, ok := d.GetOk("http_config"); ok {
|
||||||
|
deviceRegistry.HttpConfig = buildHttpConfig(v.(map[string]interface{}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if d.HasChange("credentials") {
|
||||||
|
hasChanged = true
|
||||||
|
updateMask = append(updateMask, "credentials")
|
||||||
|
if v, ok := d.GetOk("credentials"); ok {
|
||||||
|
deviceRegistry.Credentials = expandCredentials(v.([]interface{}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if hasChanged {
|
||||||
|
_, err := config.clientCloudIoT.Projects.Locations.Registries.Patch(d.Id(),
|
||||||
|
deviceRegistry).UpdateMask(strings.Join(updateMask, ",")).Do()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error updating registry %s: %s", d.Get("name").(string), err)
|
||||||
|
}
|
||||||
|
for _, updateMaskItem := range updateMask {
|
||||||
|
d.SetPartial(updateMaskItem)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
d.Partial(false)
|
||||||
|
return resourceCloudIoTRegistryRead(d, meta)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceCloudIoTRegistryRead(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
config := meta.(*Config)
|
||||||
|
name := d.Id()
|
||||||
|
res, err := config.clientCloudIoT.Projects.Locations.Registries.Get(name).Do()
|
||||||
|
if err != nil {
|
||||||
|
return handleNotFoundError(err, d, fmt.Sprintf("Registry %q", name))
|
||||||
|
}
|
||||||
|
|
||||||
|
d.Set("name", res.Id)
|
||||||
|
|
||||||
|
if len(res.EventNotificationConfigs) > 0 {
|
||||||
|
eventConfig := map[string]string{"pubsub_topic_name": res.EventNotificationConfigs[0].PubsubTopicName}
|
||||||
|
d.Set("event_notification_config", eventConfig)
|
||||||
|
} else {
|
||||||
|
d.Set("event_notification_config", nil)
|
||||||
|
}
|
||||||
|
pubsubTopicName := res.StateNotificationConfig.PubsubTopicName
|
||||||
|
if pubsubTopicName != "" {
|
||||||
|
d.Set("state_notification_config",
|
||||||
|
map[string]string{"pubsub_topic_name": pubsubTopicName})
|
||||||
|
} else {
|
||||||
|
d.Set("state_notification_config", nil)
|
||||||
|
}
|
||||||
|
// If no config exist for mqtt or http config default values are omitted.
|
||||||
|
mqttState := res.MqttConfig.MqttEnabledState
|
||||||
|
_, hasMqttConfig := d.GetOk("mqtt_config")
|
||||||
|
if mqttState != mqttEnabled || hasMqttConfig {
|
||||||
|
d.Set("mqtt_config",
|
||||||
|
map[string]string{"mqtt_enabled_state": mqttState})
|
||||||
|
}
|
||||||
|
httpState := res.HttpConfig.HttpEnabledState
|
||||||
|
_, hasHttpConfig := d.GetOk("http_config")
|
||||||
|
if httpState != httpEnabled || hasHttpConfig {
|
||||||
|
d.Set("http_config",
|
||||||
|
map[string]string{"http_enabled_state": httpState})
|
||||||
|
}
|
||||||
|
|
||||||
|
credentials := make([]map[string]interface{}, len(res.Credentials))
|
||||||
|
for i, item := range res.Credentials {
|
||||||
|
pubcert := make(map[string]interface{})
|
||||||
|
pubcert["format"] = item.PublicKeyCertificate.Format
|
||||||
|
pubcert["certificate"] = item.PublicKeyCertificate.Certificate
|
||||||
|
credentials[i] = make(map[string]interface{})
|
||||||
|
credentials[i]["public_key_certificate"] = pubcert
|
||||||
|
}
|
||||||
|
d.Set("credentials", credentials)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceCloudIoTRegistryDelete(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
config := meta.(*Config)
|
||||||
|
name := d.Id()
|
||||||
|
call := config.clientCloudIoT.Projects.Locations.Registries.Delete(name)
|
||||||
|
_, err := call.Do()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
d.SetId("")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceCloudIoTRegistryStateImporter(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
|
||||||
|
r, _ := regexp.Compile("^projects/(.+)/locations/(.+)/registries/(.+)$")
|
||||||
|
if !r.MatchString(d.Id()) {
|
||||||
|
return nil, fmt.Errorf("Invalid registry specifier. " +
|
||||||
|
"Expecting: projects/{project}/locations/{region}/registries/{name}")
|
||||||
|
}
|
||||||
|
parms := r.FindAllStringSubmatch(d.Id(), -1)[0]
|
||||||
|
project := parms[1]
|
||||||
|
region := parms[2]
|
||||||
|
name := parms[3]
|
||||||
|
|
||||||
|
id := fmt.Sprintf("projects/%s/locations/%s/registries/%s", project, region, name)
|
||||||
|
d.Set("project", project)
|
||||||
|
d.Set("region", region)
|
||||||
|
d.SetId(id)
|
||||||
|
return []*schema.ResourceData{d}, nil
|
||||||
|
}
|
166
google/resource_cloudiot_registry_test.go
Normal file
166
google/resource_cloudiot_registry_test.go
Normal file
|
@ -0,0 +1,166 @@
|
||||||
|
package google
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/acctest"
|
||||||
|
"github.com/hashicorp/terraform/helper/resource"
|
||||||
|
"github.com/hashicorp/terraform/terraform"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAccCloudIoTRegistryCreate_basic(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
registryName := fmt.Sprintf("psregistry-test-%s", acctest.RandString(10))
|
||||||
|
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccCheckCloudIoTRegistryDestroy,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccCloudIoTRegistry_basic(registryName),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCloudIoTRegistryExists(
|
||||||
|
"google_cloudiot_registry.foobar"),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAccCloudIoTRegistryCreate_extended(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
registryName := fmt.Sprintf("psregistry-test-%s", acctest.RandString(10))
|
||||||
|
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccCheckCloudIoTRegistryDestroy,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccCloudIoTRegistry_extended(registryName),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCloudIoTRegistryExists(
|
||||||
|
"google_cloudiot_registry.foobar"),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAccCloudIoTRegistryUpdate(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
registryName := fmt.Sprintf("psregistry-test-%s", acctest.RandString(10))
|
||||||
|
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccCheckCloudIoTRegistryDestroy,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccCloudIoTRegistry_basic(registryName),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCloudIoTRegistryExists(
|
||||||
|
"google_cloudiot_registry.foobar"),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccCloudIoTRegistry_extended(registryName),
|
||||||
|
},
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccCloudIoTRegistry_basic(registryName),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckCloudIoTRegistryDestroy(s *terraform.State) error {
|
||||||
|
for _, rs := range s.RootModule().Resources {
|
||||||
|
if rs.Type != "google_cloudiot_registry" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
config := testAccProvider.Meta().(*Config)
|
||||||
|
registry, _ := config.clientCloudIoT.Projects.Locations.Registries.Get(rs.Primary.ID).Do()
|
||||||
|
if registry != nil {
|
||||||
|
return fmt.Errorf("Registry still present")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCloudIoTRegistryExists(n string) resource.TestCheckFunc {
|
||||||
|
return func(s *terraform.State) error {
|
||||||
|
rs, ok := s.RootModule().Resources[n]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Not found: %s", n)
|
||||||
|
}
|
||||||
|
if rs.Primary.ID == "" {
|
||||||
|
return fmt.Errorf("No ID is set")
|
||||||
|
}
|
||||||
|
config := testAccProvider.Meta().(*Config)
|
||||||
|
_, err := config.clientCloudIoT.Projects.Locations.Registries.Get(rs.Primary.ID).Do()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Registry does not exist")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCloudIoTRegistry_basic(registryName string) string {
|
||||||
|
return fmt.Sprintf(`
|
||||||
|
resource "google_cloudiot_registry" "foobar" {
|
||||||
|
name = "%s"
|
||||||
|
}`, registryName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCloudIoTRegistry_extended(registryName string) string {
|
||||||
|
return fmt.Sprintf(`
|
||||||
|
resource "google_project_iam_binding" "cloud-iot-iam-binding" {
|
||||||
|
members = ["serviceAccount:cloud-iot@system.gserviceaccount.com"]
|
||||||
|
role = "roles/pubsub.publisher"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "google_pubsub_topic" "default-devicestatus" {
|
||||||
|
name = "psregistry-test-devicestatus-%s"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "google_pubsub_topic" "default-telemetry" {
|
||||||
|
name = "psregistry-test-telemetry-%s"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "google_cloudiot_registry" "foobar" {
|
||||||
|
depends_on = ["google_project_iam_binding.cloud-iot-iam-binding"]
|
||||||
|
|
||||||
|
name = "psregistry-test-%s"
|
||||||
|
|
||||||
|
event_notification_config = {
|
||||||
|
pubsub_topic_name = "${google_pubsub_topic.default-devicestatus.id}"
|
||||||
|
}
|
||||||
|
|
||||||
|
state_notification_config = {
|
||||||
|
pubsub_topic_name = "${google_pubsub_topic.default-telemetry.id}"
|
||||||
|
}
|
||||||
|
|
||||||
|
http_config = {
|
||||||
|
http_enabled_state = "HTTP_DISABLED"
|
||||||
|
}
|
||||||
|
|
||||||
|
mqtt_config = {
|
||||||
|
mqtt_enabled_state = "MQTT_DISABLED"
|
||||||
|
}
|
||||||
|
|
||||||
|
credentials = [
|
||||||
|
{
|
||||||
|
"public_key_certificate" = {
|
||||||
|
format = "X509_CERTIFICATE_PEM"
|
||||||
|
certificate = "${file("test-fixtures/rsa_cert.pem")}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
`, acctest.RandString(10), acctest.RandString(10), registryName)
|
||||||
|
}
|
17
google/test-fixtures/rsa_cert.pem
Normal file
17
google/test-fixtures/rsa_cert.pem
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIICoDCCAYgCCQDzZ6R7RYs0sTANBgkqhkiG9w0BAQsFADARMQ8wDQYDVQQDDAZ1
|
||||||
|
bnVzZWQwIBcNMTgwMTIwMTA0OTIzWhgPNDc1NTEyMTgxMDQ5MjNaMBExDzANBgNV
|
||||||
|
BAMMBnVudXNlZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMXX/5jI
|
||||||
|
tvxpst1mFVKVXfyu5S5AOQF+i/ny6Ef+h8py8y42XfsE2AAPSTE3JCIgWemw7NQ/
|
||||||
|
xnTQ3f6b7/6+ZsdM4/hoiedwYV8X3LVPB9NRnKe82OHUhzo1psVMJVvHtE3GsD/V
|
||||||
|
i40ki/L4Xs64E2GJqQfrkgeNfIyCeKev64fR5aMazqOw1cNrVe34mY3L1hgXpn7e
|
||||||
|
SnO0oqnV86pTh+jTT8EKgo9AI7/QuJbPWpJhnj1/Fm8i3DdCdpQqloX9Fc4f6whA
|
||||||
|
XlZ2tkma0PsBraxMua5GPglJ7m3RabQIoyAW+4hEYAcu7U0wIhCK+C8WTNgEYZaK
|
||||||
|
zvp8vK6vOgBIjE0CAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAvVXus7dLikEAM6+I
|
||||||
|
6xeN7aHEMJRR0h2rigLiYjfl8R9zG/zxUPUunWPAYaKvWOFviXcX/KqpjDqIIeWx
|
||||||
|
Gm0yNfyalHq476nRCf/0t9AH5X4Qy0KJSW5KfhQLG9X2z/UiJxwHKCwaWZtEEzPu
|
||||||
|
mGqvwhNXUOL/GuAZCJWPdWrUGM4kHHz3kw5v3UPNS2xA7yMtN9N1b8/pkTQ77XNk
|
||||||
|
DA4wngA5zc7Ae72SJDrY8XXqLfL4Nagkrn6AOhGK3/Ewvca6hkThMcHI0WF2AqFo
|
||||||
|
mo3iGUJzR5lOUx+4RiEBC5NNEZsE9GMNEiu8kYvCAS0FMKYmxFPGx1U/kiOeeuIw
|
||||||
|
W3sOEA==
|
||||||
|
-----END CERTIFICATE-----
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"net"
|
"net"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -18,6 +19,7 @@ const (
|
||||||
SubnetworkLinkRegex = "projects/(" + ProjectRegex + ")/regions/(" + RegionRegex + ")/subnetworks/(" + SubnetworkRegex + ")$"
|
SubnetworkLinkRegex = "projects/(" + ProjectRegex + ")/regions/(" + RegionRegex + ")/subnetworks/(" + SubnetworkRegex + ")$"
|
||||||
|
|
||||||
RFC1035NameTemplate = "[a-z](?:[-a-z0-9]{%d,%d}[a-z0-9])"
|
RFC1035NameTemplate = "[a-z](?:[-a-z0-9]{%d,%d}[a-z0-9])"
|
||||||
|
CloudIoTIdRegex = "^[a-zA-Z][-a-zA-Z0-9._+~%]{2,254}$"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -115,3 +117,16 @@ func validateIpCidrRange(v interface{}, k string) (warnings []string, errors []e
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func validateCloudIoTID(v interface{}, k string) (warnings []string, errors []error) {
|
||||||
|
value := v.(string)
|
||||||
|
if strings.HasPrefix(value, "goog") {
|
||||||
|
errors = append(errors, fmt.Errorf(
|
||||||
|
"%q (%q) can not start with \"goog\"", k, value))
|
||||||
|
}
|
||||||
|
if !regexp.MustCompile(CloudIoTIdRegex).MatchString(value) {
|
||||||
|
errors = append(errors, fmt.Errorf(
|
||||||
|
"%q (%q) doesn't match regexp %q", k, value, CloudIoTIdRegex))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/hashicorp/terraform/helper/schema"
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -183,3 +184,27 @@ func TestProjectRegex(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestValidateCloudIoTID(t *testing.T) {
|
||||||
|
x := []StringValidationTestCase{
|
||||||
|
// No errors
|
||||||
|
{TestName: "basic", Value: "foobar"},
|
||||||
|
{TestName: "with numbers", Value: "foobar123"},
|
||||||
|
{TestName: "short", Value: "foo"},
|
||||||
|
{TestName: "long", Value: "foobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoo"},
|
||||||
|
{TestName: "has a hyphen", Value: "foo-bar"},
|
||||||
|
|
||||||
|
// With errors
|
||||||
|
{TestName: "empty", Value: "", ExpectError: true},
|
||||||
|
{TestName: "starts with a goog", Value: "googfoobar", ExpectError: true},
|
||||||
|
{TestName: "starts with a number", Value: "1foobar", ExpectError: true},
|
||||||
|
{TestName: "has an slash", Value: "foo/bar", ExpectError: true},
|
||||||
|
{TestName: "has an backslash", Value: "foo\bar", ExpectError: true},
|
||||||
|
{TestName: "too long", Value: strings.Repeat("f", 260), ExpectError: true},
|
||||||
|
}
|
||||||
|
|
||||||
|
es := testStringValidationCases(x, validateCloudIoTID)
|
||||||
|
if len(es) > 0 {
|
||||||
|
t.Errorf("Failed to validate CloudIoT ID names: %v", es)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
1311
vendor/google.golang.org/api/cloudiot/v1/cloudiot-api.json
generated
vendored
Normal file
1311
vendor/google.golang.org/api/cloudiot/v1/cloudiot-api.json
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
4143
vendor/google.golang.org/api/cloudiot/v1/cloudiot-gen.go
generated
vendored
Normal file
4143
vendor/google.golang.org/api/cloudiot/v1/cloudiot-gen.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
6
vendor/vendor.json
vendored
6
vendor/vendor.json
vendored
|
@ -1249,6 +1249,12 @@
|
||||||
"revision": "f4694fe510ef1f58a08157aa15e795ffea4d4766",
|
"revision": "f4694fe510ef1f58a08157aa15e795ffea4d4766",
|
||||||
"revisionTime": "2017-12-15T00:04:04Z"
|
"revisionTime": "2017-12-15T00:04:04Z"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"checksumSHA1": "uLifIDdJHnoBlTG0G4T6DGSB9l4=",
|
||||||
|
"path": "google.golang.org/api/cloudiot/v1",
|
||||||
|
"revision": "37df4fabefb044819e927f44b8487d4cd926d06c",
|
||||||
|
"revisionTime": "2018-01-12T00:03:42Z"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "/cYz9AiKwLEO61OdoLnKi2uiOeQ=",
|
"checksumSHA1": "/cYz9AiKwLEO61OdoLnKi2uiOeQ=",
|
||||||
"path": "google.golang.org/api/cloudkms/v1",
|
"path": "google.golang.org/api/cloudkms/v1",
|
||||||
|
|
116
website/docs/r/cloudiot_registry.html.markdown
Normal file
116
website/docs/r/cloudiot_registry.html.markdown
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
---
|
||||||
|
layout: "google"
|
||||||
|
page_title: "Google: google_cloudiot_registry"
|
||||||
|
sidebar_current: "docs-google-cloudiot-registry-x"
|
||||||
|
description: |-
|
||||||
|
Creates a device registry in Google's Cloud IoT Core platform
|
||||||
|
---
|
||||||
|
|
||||||
|
# google\cloudiot\_registry
|
||||||
|
|
||||||
|
Creates a device registry in Google's Cloud IoT Core platform. For more information see
|
||||||
|
[the official documentation](https://cloud.google.com/iot/docs/) and
|
||||||
|
[API](https://cloud.google.com/iot/docs/reference/rest/v1/projects.locations.registries).
|
||||||
|
|
||||||
|
|
||||||
|
## Example Usage
|
||||||
|
|
||||||
|
```hcl
|
||||||
|
resource "google_pubsub_topic" "default-devicestatus" {
|
||||||
|
name = "default-devicestatus"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "google_pubsub_topic" "default-telemetry" {
|
||||||
|
name = "default-telemetry"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "google_cloudiot_registry" "default-registry" {
|
||||||
|
name = "default-registry"
|
||||||
|
|
||||||
|
event_notification_config = {
|
||||||
|
pubsub_topic_name = "${google_pubsub_topic.default-devicestatus.id}"
|
||||||
|
}
|
||||||
|
|
||||||
|
state_notification_config = {
|
||||||
|
pubsub_topic_name = "${google_pubsub_topic.default-telemetry.id}"
|
||||||
|
}
|
||||||
|
|
||||||
|
http_config = {
|
||||||
|
http_enabled_state = "HTTP_ENABLED"
|
||||||
|
}
|
||||||
|
|
||||||
|
mqtt_config = {
|
||||||
|
mqtt_enabled_state = "MQTT_ENABLED"
|
||||||
|
}
|
||||||
|
|
||||||
|
credentials = [
|
||||||
|
{
|
||||||
|
public_key_certificate = {
|
||||||
|
format = "X509_CERTIFICATE_PEM"
|
||||||
|
certificate = "${file("rsa_cert.pem")}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Argument Reference
|
||||||
|
|
||||||
|
The following arguments are supported:
|
||||||
|
|
||||||
|
* `name` - (Required) A unique name for the resource, required by device registry.
|
||||||
|
Changing this forces a new resource to be created.
|
||||||
|
|
||||||
|
- - -
|
||||||
|
|
||||||
|
* `project` - (Optional) The project in which the resource belongs. If it is not provided, the provider project is used.
|
||||||
|
|
||||||
|
* `region` - (Optional) The Region in which the created address should reside. If it is not provided, the provider region is used.
|
||||||
|
|
||||||
|
* `event_notification_config` - (Optional) A PubSub topics to publish device events. Structure is documented below.
|
||||||
|
|
||||||
|
* `state_notification_config` - (Optional) A PubSub topic to publish device state updates. Structure is documented below.
|
||||||
|
|
||||||
|
* `mqtt_config` - (Optional) Activate or deactivate MQTT. Structure is documented below.
|
||||||
|
* `http_config` - (Optional) Activate or deactivate HTTP. Structure is documented below.
|
||||||
|
|
||||||
|
* `credentials` - (Optional) List of public key certificates to authenticate devices. Structure is documented below.
|
||||||
|
|
||||||
|
|
||||||
|
The `event_notification_config` block supports:
|
||||||
|
|
||||||
|
* `pubsub_topic_name` - (Required) PubSub topic name to publish device events.
|
||||||
|
|
||||||
|
The `state_notification_config` block supports:
|
||||||
|
|
||||||
|
* `pubsub_topic_name` - (Required) PubSub topic name to publish device state updates.
|
||||||
|
|
||||||
|
The `mqtt_config` block supports:
|
||||||
|
|
||||||
|
* `mqtt_enabled_state` - (Required) The field allows `MQTT_ENABLED` or `MQTT_DISABLED`.
|
||||||
|
|
||||||
|
The `http_config` block supports:
|
||||||
|
|
||||||
|
* `http_enabled_state` - (Required) The field allows `HTTP_ENABLED` or `HTTP_DISABLED`.
|
||||||
|
|
||||||
|
The `credentials` block supports:
|
||||||
|
|
||||||
|
* `public_key_certificate` - (Required) The certificate format and data.
|
||||||
|
|
||||||
|
The `public_key_certificate` block supports:
|
||||||
|
|
||||||
|
* `format` - (Required) The field allows only `X509_CERTIFICATE_PEM`.
|
||||||
|
* `certificate` - (Required) The certificate data.
|
||||||
|
|
||||||
|
|
||||||
|
## Attributes Reference
|
||||||
|
|
||||||
|
Only the arguments listed above are exposed as attributes.
|
||||||
|
|
||||||
|
## Import
|
||||||
|
|
||||||
|
A device registry can be imported using the `name`, e.g.
|
||||||
|
|
||||||
|
```
|
||||||
|
$ terraform import google_cloudiot_registry.default-registry projects/{project}/locations/{region}/registries/{name}
|
||||||
|
```
|
|
@ -546,6 +546,15 @@
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
<li<%= sidebar_current("docs-google-cloudiot") %>>
|
||||||
|
<a href="#">Google Cloud IoT Core</a>
|
||||||
|
<ul class="nav nav-visible">
|
||||||
|
<li<%= sidebar_current("docs-google-cloudiot-registry-x") %>>
|
||||||
|
<a href="/docs/providers/google/r/cloudiot_registry.html">google_cloudiot_registry</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user