mirror of
https://github.com/letic/terraform-provider-google.git
synced 2024-07-01 07:42:40 +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/cloudbilling/v1"
|
||||
"google.golang.org/api/cloudfunctions/v1"
|
||||
"google.golang.org/api/cloudiot/v1"
|
||||
"google.golang.org/api/cloudkms/v1"
|
||||
"google.golang.org/api/cloudresourcemanager/v1"
|
||||
resourceManagerV2Beta1 "google.golang.org/api/cloudresourcemanager/v2beta1"
|
||||
|
@ -71,6 +72,7 @@ type Config struct {
|
|||
clientServiceMan *servicemanagement.APIService
|
||||
clientBigQuery *bigquery.Service
|
||||
clientCloudFunctions *cloudfunctions.Service
|
||||
clientCloudIoT *cloudiot.Service
|
||||
|
||||
bigtableClientFactory *BigtableClientFactory
|
||||
}
|
||||
|
@ -294,6 +296,13 @@ func (c *Config) loadAndValidate() error {
|
|||
}
|
||||
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
|
||||
}
|
||||
|
||||
|
|
|
@ -90,6 +90,7 @@ func Provider() terraform.ResourceProvider {
|
|||
"google_bigtable_instance": resourceBigtableInstance(),
|
||||
"google_bigtable_table": resourceBigtableTable(),
|
||||
"google_cloudfunctions_function": resourceCloudFunctionsFunction(),
|
||||
"google_cloudiot_registry": resourceCloudIoTRegistry(),
|
||||
"google_compute_autoscaler": resourceComputeAutoscaler(),
|
||||
"google_compute_address": resourceComputeAddress(),
|
||||
"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"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -18,6 +19,7 @@ const (
|
|||
SubnetworkLinkRegex = "projects/(" + ProjectRegex + ")/regions/(" + RegionRegex + ")/subnetworks/(" + SubnetworkRegex + ")$"
|
||||
|
||||
RFC1035NameTemplate = "[a-z](?:[-a-z0-9]{%d,%d}[a-z0-9])"
|
||||
CloudIoTIdRegex = "^[a-zA-Z][-a-zA-Z0-9._+~%]{2,254}$"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -115,3 +117,16 @@ func validateIpCidrRange(v interface{}, k string) (warnings []string, errors []e
|
|||
}
|
||||
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"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"regexp"
|
||||
"strings"
|
||||
"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",
|
||||
"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=",
|
||||
"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>
|
||||
</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>
|
||||
</div>
|
||||
<% end %>
|
||||
|
|
Loading…
Reference in New Issue
Block a user