Add support for Google Cloud IoT Core registry (#970)

This commit is contained in:
Simon Pizonka 2018-01-24 22:03:09 +01:00 committed by Nathan McKinley
parent c18ac00e8f
commit fec2f0bc02
12 changed files with 6189 additions and 0 deletions

View File

@ -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
}

View File

@ -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(),

View 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
}

View 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)
}

View 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-----

View File

@ -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
}

View File

@ -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)
}
}

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

File diff suppressed because it is too large Load Diff

6
vendor/vendor.json vendored
View File

@ -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",

View 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}
```

View File

@ -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 %>