diff --git a/.travis.yml b/.travis.yml index 83247c3b..88dc4eec 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,7 @@ dist: trusty -sudo: false +sudo: required +services: +- docker language: go go: - 1.9.1 @@ -16,6 +18,7 @@ script: - make test - make vendor-status - make vet +- make website-test branches: only: diff --git a/CHANGELOG.md b/CHANGELOG.md index a8bf755e..544bd336 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,28 @@ -## 1.10.1 (Unreleased) +## 1.11.1 (Unreleased) IMPROVEMENTS: -* compute: Add `public_ptr_domain_name` to `google_compute_instance`. [GH-1349] +* compute: Autogenerate `google_vpn_gateway` [GH-1409] + +## 1.11.0 (May 01, 2018) + +IMPROVEMENTS: +* compute: Add `public_ptr_domain_name` to `google_compute_instance`. ([#1349](https://github.com/terraform-providers/terraform-provider-google/issues/1349)) +* compute: Autogenerate `google_compute_global_address`. ([#1379](https://github.com/terraform-providers/terraform-provider-google/issues/1379)) +* compute: Autogenerate `google_compute_target_http_proxy`. ([#1391](https://github.com/terraform-providers/terraform-provider-google/issues/1391)) +* compute: Autogenerate `google_compute_target_http_proxy`. ([#1373](https://github.com/terraform-providers/terraform-provider-google/issues/1373)) +* compute: Simplify autogenerated code for `google_compute_target_http_proxy` and `google_compute_target_ssl_proxy`. ([#1395](https://github.com/terraform-providers/terraform-provider-google/issues/1395)) +* compute: Use partial state setting in `google_compute_target_http_proxy` and `google_compute_target_ssl_proxy` to better handle mid-update errors. ([#1392](https://github.com/terraform-providers/terraform-provider-google/issues/1392)) +* compute: Use the v1 API for `google_compute_address` ([#1384](https://github.com/terraform-providers/terraform-provider-google/issues/1384)) +* compute: Properly detect when `public_ptr_domain_name` isn't set. ([#1383](https://github.com/terraform-providers/terraform-provider-google/issues/1383)) +* compute: Use the v1 API for `google_compute_ssl_policy` ([#1368](https://github.com/terraform-providers/terraform-provider-google/issues/1368)) +* container: Add `issue_client_certificate` to `google_container_cluster`. ([#1396](https://github.com/terraform-providers/terraform-provider-google/issues/1396)) +* container: Support regional clusters for node pools. ([#1320](https://github.com/terraform-providers/terraform-provider-google/issues/1320)) +* all: List of resources is now partially auto-generated ([#1397](https://github.com/terraform-providers/terraform-provider-google/issues/1397)] [[#1402](https://github.com/terraform-providers/terraform-provider-google/issues/1402)) + +BUG FIXES: +* iam: expand the validation for service accounts to include App Engine and compute default service accounts ([#1390](https://github.com/terraform-providers/terraform-provider-google/issues/1390)) +* sql: Increase timeouts ([#1381](https://github.com/terraform-providers/terraform-provider-google/issues/1381)) +* website: fix broken layouts ([#1405](https://github.com/terraform-providers/terraform-provider-google/issues/1405)) ## 1.10.0 (April 20, 2018) diff --git a/GNUmakefile b/GNUmakefile index c9eacb45..25c295eb 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -1,5 +1,7 @@ TEST?=$$(go list ./... |grep -v 'vendor') GOFMT_FILES?=$$(find . -name '*.go' |grep -v vendor) +WEBSITE_REPO=github.com/hashicorp/terraform-website +PKG_NAME=google default: build @@ -38,10 +40,24 @@ vendor-status: test-compile: @if [ "$(TEST)" = "./..." ]; then \ echo "ERROR: Set TEST to a specific package. For example,"; \ - echo " make test-compile TEST=./aws"; \ + echo " make test-compile TEST=./$(PKG_NAME)"; \ exit 1; \ fi go test -c $(TEST) $(TESTARGS) -.PHONY: build test testacc vet fmt fmtcheck errcheck vendor-status test-compile +website: +ifeq (,$(wildcard $(GOPATH)/src/$(WEBSITE_REPO))) + echo "$(WEBSITE_REPO) not found in your GOPATH (necessary for layouts and assets), get-ting..." + git clone https://$(WEBSITE_REPO) $(GOPATH)/src/$(WEBSITE_REPO) +endif + @$(MAKE) -C $(GOPATH)/src/$(WEBSITE_REPO) website-provider PROVIDER_PATH=$(shell pwd) PROVIDER_NAME=$(PKG_NAME) + +website-test: +ifeq (,$(wildcard $(GOPATH)/src/$(WEBSITE_REPO))) + echo "$(WEBSITE_REPO) not found in your GOPATH (necessary for layouts and assets), get-ting..." + git clone https://$(WEBSITE_REPO) $(GOPATH)/src/$(WEBSITE_REPO) +endif + @$(MAKE) -C $(GOPATH)/src/$(WEBSITE_REPO) website-provider-test PROVIDER_PATH=$(shell pwd) PROVIDER_NAME=$(PKG_NAME) + +.PHONY: build test testacc vet fmt fmtcheck errcheck vendor-status test-compile website website-test diff --git a/google/data_source_google_container_cluster_test.go b/google/data_source_google_container_cluster_test.go index 8437ed97..bb29b471 100644 --- a/google/data_source_google_container_cluster_test.go +++ b/google/data_source_google_container_cluster_test.go @@ -59,6 +59,7 @@ func testAccDataSourceGoogleContainerClusterCheck(dataSourceName string, resourc "master_auth", "master_auth.0.password", "master_auth.0.username", + "master_auth.0.client_certificate_config.0.issue_client_certificate", "master_auth.0.client_certificate", "master_auth.0.client_key", "master_auth.0.cluster_ca_certificate", diff --git a/google/provider.go b/google/provider.go index 16dad36d..52e793c5 100644 --- a/google/provider.go +++ b/google/provider.go @@ -93,133 +93,130 @@ func Provider() terraform.ResourceProvider { "google_compute_backend_service": dataSourceGoogleComputeBackendService(), }, - ResourcesMap: map[string]*schema.Resource{ - "google_bigquery_dataset": resourceBigQueryDataset(), - "google_bigquery_table": resourceBigQueryTable(), - "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(), - "google_compute_backend_service": resourceComputeBackendService(), - "google_compute_disk": resourceComputeDisk(), - "google_compute_snapshot": resourceComputeSnapshot(), - "google_compute_firewall": resourceComputeFirewall(), - "google_compute_forwarding_rule": resourceComputeForwardingRule(), - "google_compute_global_address": resourceComputeGlobalAddress(), - "google_compute_global_forwarding_rule": resourceComputeGlobalForwardingRule(), - "google_compute_health_check": resourceComputeHealthCheck(), - "google_compute_http_health_check": resourceComputeHttpHealthCheck(), - "google_compute_https_health_check": resourceComputeHttpsHealthCheck(), - "google_compute_image": resourceComputeImage(), - "google_compute_instance": resourceComputeInstance(), - "google_compute_instance_group": resourceComputeInstanceGroup(), - "google_compute_instance_group_manager": resourceComputeInstanceGroupManager(), - "google_compute_instance_template": resourceComputeInstanceTemplate(), - "google_compute_network": resourceComputeNetwork(), - "google_compute_network_peering": resourceComputeNetworkPeering(), - "google_compute_project_metadata": resourceComputeProjectMetadata(), - "google_compute_project_metadata_item": resourceComputeProjectMetadataItem(), - "google_compute_region_autoscaler": resourceComputeRegionAutoscaler(), - "google_compute_region_backend_service": resourceComputeRegionBackendService(), - "google_compute_region_instance_group_manager": resourceComputeRegionInstanceGroupManager(), - "google_compute_route": resourceComputeRoute(), - "google_compute_router": resourceComputeRouter(), - "google_compute_router_interface": resourceComputeRouterInterface(), - "google_compute_router_peer": resourceComputeRouterPeer(), - "google_compute_security_policy": resourceComputeSecurityPolicy(), - "google_compute_shared_vpc_host_project": resourceComputeSharedVpcHostProject(), - "google_compute_shared_vpc_service_project": resourceComputeSharedVpcServiceProject(), - "google_compute_ssl_certificate": resourceComputeSslCertificate(), - "google_compute_ssl_policy": resourceComputeSslPolicy(), - "google_compute_subnetwork": resourceComputeSubnetwork(), - "google_compute_subnetwork_iam_binding": ResourceIamBindingWithImport(IamComputeSubnetworkSchema, NewComputeSubnetworkIamUpdater, ComputeSubnetworkIdParseFunc), - "google_compute_subnetwork_iam_member": ResourceIamMemberWithImport(IamComputeSubnetworkSchema, NewComputeSubnetworkIamUpdater, ComputeSubnetworkIdParseFunc), - "google_compute_subnetwork_iam_policy": ResourceIamPolicyWithImport(IamComputeSubnetworkSchema, NewComputeSubnetworkIamUpdater, ComputeSubnetworkIdParseFunc), - "google_compute_target_http_proxy": resourceComputeTargetHttpProxy(), - "google_compute_target_https_proxy": resourceComputeTargetHttpsProxy(), - "google_compute_target_tcp_proxy": resourceComputeTargetTcpProxy(), - "google_compute_target_ssl_proxy": resourceComputeTargetSslProxy(), - "google_compute_target_pool": resourceComputeTargetPool(), - "google_compute_url_map": resourceComputeUrlMap(), - "google_compute_vpn_gateway": resourceComputeVpnGateway(), - "google_compute_vpn_tunnel": resourceComputeVpnTunnel(), - "google_container_cluster": resourceContainerCluster(), - "google_container_node_pool": resourceContainerNodePool(), - "google_dataflow_job": resourceDataflowJob(), - "google_dataproc_cluster": resourceDataprocCluster(), - "google_dataproc_job": resourceDataprocJob(), - "google_dns_managed_zone": resourceDnsManagedZone(), - "google_dns_record_set": resourceDnsRecordSet(), - "google_endpoints_service": resourceEndpointsService(), - "google_folder": resourceGoogleFolder(), - "google_folder_iam_binding": ResourceIamBindingWithImport(IamFolderSchema, NewFolderIamUpdater, FolderIdParseFunc), - "google_folder_iam_member": ResourceIamMemberWithImport(IamFolderSchema, NewFolderIamUpdater, FolderIdParseFunc), - "google_folder_iam_policy": ResourceIamPolicyWithImport(IamFolderSchema, NewFolderIamUpdater, FolderIdParseFunc), - "google_folder_organization_policy": resourceGoogleFolderOrganizationPolicy(), - "google_logging_billing_account_sink": resourceLoggingBillingAccountSink(), - "google_logging_organization_sink": resourceLoggingOrganizationSink(), - "google_logging_folder_sink": resourceLoggingFolderSink(), - "google_logging_project_sink": resourceLoggingProjectSink(), - "google_kms_key_ring": resourceKmsKeyRing(), - "google_kms_key_ring_iam_binding": ResourceIamBindingWithImport(IamKmsKeyRingSchema, NewKmsKeyRingIamUpdater, KeyRingIdParseFunc), - "google_kms_key_ring_iam_member": ResourceIamMemberWithImport(IamKmsKeyRingSchema, NewKmsKeyRingIamUpdater, KeyRingIdParseFunc), - "google_kms_key_ring_iam_policy": ResourceIamPolicyWithImport(IamKmsKeyRingSchema, NewKmsKeyRingIamUpdater, KeyRingIdParseFunc), - "google_kms_crypto_key": resourceKmsCryptoKey(), - "google_kms_crypto_key_iam_binding": ResourceIamBindingWithImport(IamKmsCryptoKeySchema, NewKmsCryptoKeyIamUpdater, CryptoIdParseFunc), - "google_kms_crypto_key_iam_member": ResourceIamMemberWithImport(IamKmsCryptoKeySchema, NewKmsCryptoKeyIamUpdater, CryptoIdParseFunc), - "google_sourcerepo_repository": resourceSourceRepoRepository(), - "google_spanner_instance": resourceSpannerInstance(), - "google_spanner_database": resourceSpannerDatabase(), - "google_spanner_database_iam_binding": ResourceIamBindingWithImport(IamSpannerDatabaseSchema, NewSpannerDatabaseIamUpdater, SpannerDatabaseIdParseFunc), - "google_spanner_database_iam_member": ResourceIamMemberWithImport(IamSpannerDatabaseSchema, NewSpannerDatabaseIamUpdater, SpannerDatabaseIdParseFunc), - "google_spanner_database_iam_policy": ResourceIamPolicyWithImport(IamSpannerDatabaseSchema, NewSpannerDatabaseIamUpdater, SpannerDatabaseIdParseFunc), - "google_sql_database": resourceSqlDatabase(), - "google_sql_database_instance": resourceSqlDatabaseInstance(), - "google_sql_user": resourceSqlUser(), - "google_organization_iam_binding": ResourceIamBindingWithImport(IamOrganizationSchema, NewOrganizationIamUpdater, OrgIdParseFunc), - "google_organization_iam_custom_role": resourceGoogleOrganizationIamCustomRole(), - "google_organization_iam_member": ResourceIamMemberWithImport(IamOrganizationSchema, NewOrganizationIamUpdater, OrgIdParseFunc), - "google_organization_iam_policy": ResourceIamPolicyWithImport(IamOrganizationSchema, NewOrganizationIamUpdater, OrgIdParseFunc), - "google_organization_policy": resourceGoogleOrganizationPolicy(), - "google_project": resourceGoogleProject(), - "google_project_iam_policy": resourceGoogleProjectIamPolicy(), - "google_project_iam_binding": ResourceIamBindingWithImport(IamProjectSchema, NewProjectIamUpdater, ProjectIdParseFunc), - "google_project_iam_member": ResourceIamMemberWithImport(IamProjectSchema, NewProjectIamUpdater, ProjectIdParseFunc), - "google_project_service": resourceGoogleProjectService(), - "google_project_iam_custom_role": resourceGoogleProjectIamCustomRole(), - "google_project_organization_policy": resourceGoogleProjectOrganizationPolicy(), - "google_project_usage_export_bucket": resourceProjectUsageBucket(), - "google_project_services": resourceGoogleProjectServices(), - "google_pubsub_topic": resourcePubsubTopic(), - "google_pubsub_topic_iam_binding": ResourceIamBindingWithImport(IamPubsubTopicSchema, NewPubsubTopicIamUpdater, PubsubTopicIdParseFunc), - "google_pubsub_topic_iam_member": ResourceIamMemberWithImport(IamPubsubTopicSchema, NewPubsubTopicIamUpdater, PubsubTopicIdParseFunc), - "google_pubsub_topic_iam_policy": ResourceIamPolicyWithImport(IamPubsubTopicSchema, NewPubsubTopicIamUpdater, PubsubTopicIdParseFunc), - "google_pubsub_subscription": resourcePubsubSubscription(), - "google_pubsub_subscription_iam_binding": ResourceIamBindingWithImport(IamPubsubSubscriptionSchema, NewPubsubSubscriptionIamUpdater, PubsubSubscriptionIdParseFunc), - "google_pubsub_subscription_iam_member": ResourceIamMemberWithImport(IamPubsubSubscriptionSchema, NewPubsubSubscriptionIamUpdater, PubsubSubscriptionIdParseFunc), - "google_pubsub_subscription_iam_policy": ResourceIamPolicyWithImport(IamPubsubSubscriptionSchema, NewPubsubSubscriptionIamUpdater, PubsubSubscriptionIdParseFunc), - "google_runtimeconfig_config": resourceRuntimeconfigConfig(), - "google_runtimeconfig_variable": resourceRuntimeconfigVariable(), - "google_service_account": resourceGoogleServiceAccount(), - "google_service_account_iam_binding": ResourceIamBindingWithImport(IamServiceAccountSchema, NewServiceAccountIamUpdater, ServiceAccountIdParseFunc), - "google_service_account_iam_member": ResourceIamMemberWithImport(IamServiceAccountSchema, NewServiceAccountIamUpdater, ServiceAccountIdParseFunc), - "google_service_account_iam_policy": ResourceIamPolicyWithImport(IamServiceAccountSchema, NewServiceAccountIamUpdater, ServiceAccountIdParseFunc), - "google_service_account_key": resourceGoogleServiceAccountKey(), - "google_storage_bucket": resourceStorageBucket(), - "google_storage_bucket_acl": resourceStorageBucketAcl(), - // Legacy roles such as roles/storage.legacyBucketReader are automatically added - // when creating a bucket. For this reason, it is better not to add the authoritative - // google_storage_bucket_iam_policy resource. - "google_storage_bucket_iam_binding": ResourceIamBinding(IamStorageBucketSchema, NewStorageBucketIamUpdater), - "google_storage_bucket_iam_member": ResourceIamMember(IamStorageBucketSchema, NewStorageBucketIamUpdater), - "google_storage_bucket_object": resourceStorageBucketObject(), - "google_storage_object_acl": resourceStorageObjectAcl(), - "google_storage_default_object_acl": resourceStorageDefaultObjectAcl(), - "google_storage_notification": resourceStorageNotification(), - }, + ResourcesMap: mergeResourceMaps( + GeneratedComputeResourcesMap, + map[string]*schema.Resource{ + "google_bigquery_dataset": resourceBigQueryDataset(), + "google_bigquery_table": resourceBigQueryTable(), + "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_service": resourceComputeBackendService(), + "google_compute_disk": resourceComputeDisk(), + "google_compute_snapshot": resourceComputeSnapshot(), + "google_compute_firewall": resourceComputeFirewall(), + "google_compute_forwarding_rule": resourceComputeForwardingRule(), + "google_compute_global_forwarding_rule": resourceComputeGlobalForwardingRule(), + "google_compute_health_check": resourceComputeHealthCheck(), + "google_compute_image": resourceComputeImage(), + "google_compute_instance": resourceComputeInstance(), + "google_compute_instance_group": resourceComputeInstanceGroup(), + "google_compute_instance_group_manager": resourceComputeInstanceGroupManager(), + "google_compute_instance_template": resourceComputeInstanceTemplate(), + "google_compute_network": resourceComputeNetwork(), + "google_compute_network_peering": resourceComputeNetworkPeering(), + "google_compute_project_metadata": resourceComputeProjectMetadata(), + "google_compute_project_metadata_item": resourceComputeProjectMetadataItem(), + "google_compute_region_autoscaler": resourceComputeRegionAutoscaler(), + "google_compute_region_backend_service": resourceComputeRegionBackendService(), + "google_compute_region_instance_group_manager": resourceComputeRegionInstanceGroupManager(), + "google_compute_route": resourceComputeRoute(), + "google_compute_router": resourceComputeRouter(), + "google_compute_router_interface": resourceComputeRouterInterface(), + "google_compute_router_peer": resourceComputeRouterPeer(), + "google_compute_security_policy": resourceComputeSecurityPolicy(), + "google_compute_shared_vpc_host_project": resourceComputeSharedVpcHostProject(), + "google_compute_shared_vpc_service_project": resourceComputeSharedVpcServiceProject(), + "google_compute_ssl_certificate": resourceComputeSslCertificate(), + "google_compute_ssl_policy": resourceComputeSslPolicy(), + "google_compute_subnetwork": resourceComputeSubnetwork(), + "google_compute_subnetwork_iam_binding": ResourceIamBindingWithImport(IamComputeSubnetworkSchema, NewComputeSubnetworkIamUpdater, ComputeSubnetworkIdParseFunc), + "google_compute_subnetwork_iam_member": ResourceIamMemberWithImport(IamComputeSubnetworkSchema, NewComputeSubnetworkIamUpdater, ComputeSubnetworkIdParseFunc), + "google_compute_subnetwork_iam_policy": ResourceIamPolicyWithImport(IamComputeSubnetworkSchema, NewComputeSubnetworkIamUpdater, ComputeSubnetworkIdParseFunc), + "google_compute_target_https_proxy": resourceComputeTargetHttpsProxy(), + "google_compute_target_tcp_proxy": resourceComputeTargetTcpProxy(), + "google_compute_target_pool": resourceComputeTargetPool(), + "google_compute_url_map": resourceComputeUrlMap(), + "google_compute_vpn_gateway": resourceComputeVpnGateway(), + "google_compute_vpn_tunnel": resourceComputeVpnTunnel(), + "google_container_cluster": resourceContainerCluster(), + "google_container_node_pool": resourceContainerNodePool(), + "google_dataflow_job": resourceDataflowJob(), + "google_dataproc_cluster": resourceDataprocCluster(), + "google_dataproc_job": resourceDataprocJob(), + "google_dns_managed_zone": resourceDnsManagedZone(), + "google_dns_record_set": resourceDnsRecordSet(), + "google_endpoints_service": resourceEndpointsService(), + "google_folder": resourceGoogleFolder(), + "google_folder_iam_binding": ResourceIamBindingWithImport(IamFolderSchema, NewFolderIamUpdater, FolderIdParseFunc), + "google_folder_iam_member": ResourceIamMemberWithImport(IamFolderSchema, NewFolderIamUpdater, FolderIdParseFunc), + "google_folder_iam_policy": ResourceIamPolicyWithImport(IamFolderSchema, NewFolderIamUpdater, FolderIdParseFunc), + "google_folder_organization_policy": resourceGoogleFolderOrganizationPolicy(), + "google_logging_billing_account_sink": resourceLoggingBillingAccountSink(), + "google_logging_organization_sink": resourceLoggingOrganizationSink(), + "google_logging_folder_sink": resourceLoggingFolderSink(), + "google_logging_project_sink": resourceLoggingProjectSink(), + "google_kms_key_ring": resourceKmsKeyRing(), + "google_kms_key_ring_iam_binding": ResourceIamBindingWithImport(IamKmsKeyRingSchema, NewKmsKeyRingIamUpdater, KeyRingIdParseFunc), + "google_kms_key_ring_iam_member": ResourceIamMemberWithImport(IamKmsKeyRingSchema, NewKmsKeyRingIamUpdater, KeyRingIdParseFunc), + "google_kms_key_ring_iam_policy": ResourceIamPolicyWithImport(IamKmsKeyRingSchema, NewKmsKeyRingIamUpdater, KeyRingIdParseFunc), + "google_kms_crypto_key": resourceKmsCryptoKey(), + "google_kms_crypto_key_iam_binding": ResourceIamBindingWithImport(IamKmsCryptoKeySchema, NewKmsCryptoKeyIamUpdater, CryptoIdParseFunc), + "google_kms_crypto_key_iam_member": ResourceIamMemberWithImport(IamKmsCryptoKeySchema, NewKmsCryptoKeyIamUpdater, CryptoIdParseFunc), + "google_sourcerepo_repository": resourceSourceRepoRepository(), + "google_spanner_instance": resourceSpannerInstance(), + "google_spanner_database": resourceSpannerDatabase(), + "google_spanner_database_iam_binding": ResourceIamBindingWithImport(IamSpannerDatabaseSchema, NewSpannerDatabaseIamUpdater, SpannerDatabaseIdParseFunc), + "google_spanner_database_iam_member": ResourceIamMemberWithImport(IamSpannerDatabaseSchema, NewSpannerDatabaseIamUpdater, SpannerDatabaseIdParseFunc), + "google_spanner_database_iam_policy": ResourceIamPolicyWithImport(IamSpannerDatabaseSchema, NewSpannerDatabaseIamUpdater, SpannerDatabaseIdParseFunc), + "google_sql_database": resourceSqlDatabase(), + "google_sql_database_instance": resourceSqlDatabaseInstance(), + "google_sql_user": resourceSqlUser(), + "google_organization_iam_binding": ResourceIamBindingWithImport(IamOrganizationSchema, NewOrganizationIamUpdater, OrgIdParseFunc), + "google_organization_iam_custom_role": resourceGoogleOrganizationIamCustomRole(), + "google_organization_iam_member": ResourceIamMemberWithImport(IamOrganizationSchema, NewOrganizationIamUpdater, OrgIdParseFunc), + "google_organization_iam_policy": ResourceIamPolicyWithImport(IamOrganizationSchema, NewOrganizationIamUpdater, OrgIdParseFunc), + "google_organization_policy": resourceGoogleOrganizationPolicy(), + "google_project": resourceGoogleProject(), + "google_project_iam_policy": resourceGoogleProjectIamPolicy(), + "google_project_iam_binding": ResourceIamBindingWithImport(IamProjectSchema, NewProjectIamUpdater, ProjectIdParseFunc), + "google_project_iam_member": ResourceIamMemberWithImport(IamProjectSchema, NewProjectIamUpdater, ProjectIdParseFunc), + "google_project_service": resourceGoogleProjectService(), + "google_project_iam_custom_role": resourceGoogleProjectIamCustomRole(), + "google_project_organization_policy": resourceGoogleProjectOrganizationPolicy(), + "google_project_usage_export_bucket": resourceProjectUsageBucket(), + "google_project_services": resourceGoogleProjectServices(), + "google_pubsub_topic": resourcePubsubTopic(), + "google_pubsub_topic_iam_binding": ResourceIamBindingWithImport(IamPubsubTopicSchema, NewPubsubTopicIamUpdater, PubsubTopicIdParseFunc), + "google_pubsub_topic_iam_member": ResourceIamMemberWithImport(IamPubsubTopicSchema, NewPubsubTopicIamUpdater, PubsubTopicIdParseFunc), + "google_pubsub_topic_iam_policy": ResourceIamPolicyWithImport(IamPubsubTopicSchema, NewPubsubTopicIamUpdater, PubsubTopicIdParseFunc), + "google_pubsub_subscription": resourcePubsubSubscription(), + "google_pubsub_subscription_iam_binding": ResourceIamBindingWithImport(IamPubsubSubscriptionSchema, NewPubsubSubscriptionIamUpdater, PubsubSubscriptionIdParseFunc), + "google_pubsub_subscription_iam_member": ResourceIamMemberWithImport(IamPubsubSubscriptionSchema, NewPubsubSubscriptionIamUpdater, PubsubSubscriptionIdParseFunc), + "google_pubsub_subscription_iam_policy": ResourceIamPolicyWithImport(IamPubsubSubscriptionSchema, NewPubsubSubscriptionIamUpdater, PubsubSubscriptionIdParseFunc), + "google_runtimeconfig_config": resourceRuntimeconfigConfig(), + "google_runtimeconfig_variable": resourceRuntimeconfigVariable(), + "google_service_account": resourceGoogleServiceAccount(), + "google_service_account_iam_binding": ResourceIamBindingWithImport(IamServiceAccountSchema, NewServiceAccountIamUpdater, ServiceAccountIdParseFunc), + "google_service_account_iam_member": ResourceIamMemberWithImport(IamServiceAccountSchema, NewServiceAccountIamUpdater, ServiceAccountIdParseFunc), + "google_service_account_iam_policy": ResourceIamPolicyWithImport(IamServiceAccountSchema, NewServiceAccountIamUpdater, ServiceAccountIdParseFunc), + "google_service_account_key": resourceGoogleServiceAccountKey(), + "google_storage_bucket": resourceStorageBucket(), + "google_storage_bucket_acl": resourceStorageBucketAcl(), + // Legacy roles such as roles/storage.legacyBucketReader are automatically added + // when creating a bucket. For this reason, it is better not to add the authoritative + // google_storage_bucket_iam_policy resource. + "google_storage_bucket_iam_binding": ResourceIamBinding(IamStorageBucketSchema, NewStorageBucketIamUpdater), + "google_storage_bucket_iam_member": ResourceIamMember(IamStorageBucketSchema, NewStorageBucketIamUpdater), + "google_storage_bucket_object": resourceStorageBucketObject(), + "google_storage_object_acl": resourceStorageObjectAcl(), + "google_storage_default_object_acl": resourceStorageDefaultObjectAcl(), + "google_storage_notification": resourceStorageNotification(), + }, + ), ConfigureFunc: providerConfigure, } diff --git a/google/provider_compute_gen.go b/google/provider_compute_gen.go new file mode 100644 index 00000000..7718a0c4 --- /dev/null +++ b/google/provider_compute_gen.go @@ -0,0 +1,29 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file in +// .github/CONTRIBUTING.md. +// +// ---------------------------------------------------------------------------- + +package google + +import "github.com/hashicorp/terraform/helper/schema" + +var GeneratedComputeResourcesMap = map[string]*schema.Resource{ + "google_compute_backend_bucket": resourceComputeBackendBucket(), + "google_compute_global_address": resourceComputeGlobalAddress(), + "google_compute_http_health_check": resourceComputeHttpHealthCheck(), + "google_compute_https_health_check": resourceComputeHttpsHealthCheck(), + "google_compute_target_http_proxy": resourceComputeTargetHttpProxy(), + "google_compute_target_https_proxy": resourceComputeTargetHttpsProxy(), + "google_compute_target_ssl_proxy": resourceComputeTargetSslProxy(), + "google_compute_target_tcp_proxy": resourceComputeTargetTcpProxy(), + "google_compute_vpn_gateway": resourceComputeVpnGateway(), +} diff --git a/google/resource_compute_backend_bucket.go b/google/resource_compute_backend_bucket.go index 59753747..19b18e7a 100644 --- a/google/resource_compute_backend_bucket.go +++ b/google/resource_compute_backend_bucket.go @@ -140,7 +140,7 @@ func resourceComputeBackendBucketCreate(d *schema.ResourceData, meta interface{} if waitErr != nil { // The resource didn't actually create d.SetId("") - return waitErr + return fmt.Errorf("Error waiting to create BackendBucket: %s", waitErr) } return resourceComputeBackendBucketRead(d, meta) @@ -163,14 +163,27 @@ func resourceComputeBackendBucketRead(d *schema.ResourceData, meta interface{}) if err != nil { return handleNotFoundError(err, d, fmt.Sprintf("ComputeBackendBucket %q", d.Id())) } - - d.Set("bucket_name", flattenComputeBackendBucketBucketName(res["bucketName"])) - d.Set("creation_timestamp", flattenComputeBackendBucketCreationTimestamp(res["creationTimestamp"])) - d.Set("description", flattenComputeBackendBucketDescription(res["description"])) - d.Set("enable_cdn", flattenComputeBackendBucketEnableCdn(res["enableCdn"])) - d.Set("name", flattenComputeBackendBucketName(res["name"])) - d.Set("self_link", res["selfLink"]) - d.Set("project", project) + if err := d.Set("bucket_name", flattenComputeBackendBucketBucketName(res["bucketName"])); err != nil { + return fmt.Errorf("Error reading BackendBucket: %s", err) + } + if err := d.Set("creation_timestamp", flattenComputeBackendBucketCreationTimestamp(res["creationTimestamp"])); err != nil { + return fmt.Errorf("Error reading BackendBucket: %s", err) + } + if err := d.Set("description", flattenComputeBackendBucketDescription(res["description"])); err != nil { + return fmt.Errorf("Error reading BackendBucket: %s", err) + } + if err := d.Set("enable_cdn", flattenComputeBackendBucketEnableCdn(res["enableCdn"])); err != nil { + return fmt.Errorf("Error reading BackendBucket: %s", err) + } + if err := d.Set("name", flattenComputeBackendBucketName(res["name"])); err != nil { + return fmt.Errorf("Error reading BackendBucket: %s", err) + } + if err := d.Set("self_link", res["selfLink"]); err != nil { + return fmt.Errorf("Error reading BackendBucket: %s", err) + } + if err := d.Set("project", project); err != nil { + return fmt.Errorf("Error reading BackendBucket: %s", err) + } return nil } diff --git a/google/resource_compute_global_address.go b/google/resource_compute_global_address.go index 2d2edb22..5f7d4045 100644 --- a/google/resource_compute_global_address.go +++ b/google/resource_compute_global_address.go @@ -1,13 +1,27 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file in +// .github/CONTRIBUTING.md. +// +// ---------------------------------------------------------------------------- + package google import ( "fmt" "log" + "time" "github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/helper/validation" - - "google.golang.org/api/compute/v1" + compute "google.golang.org/api/compute/v1" ) func resourceComputeGlobalAddress() *schema.Resource { @@ -15,37 +29,48 @@ func resourceComputeGlobalAddress() *schema.Resource { Create: resourceComputeGlobalAddressCreate, Read: resourceComputeGlobalAddressRead, Delete: resourceComputeGlobalAddressDelete, + Importer: &schema.ResourceImporter{ - State: schema.ImportStatePassthrough, + State: resourceComputeGlobalAddressImport, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(240 * time.Second), + Delete: schema.DefaultTimeout(240 * time.Second), }, Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Required: true, ForceNew: true, }, - - "ip_version": &schema.Schema{ + "description": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "ip_version": { Type: schema.TypeString, Optional: true, ForceNew: true, ValidateFunc: validation.StringInSlice([]string{"IPV4", "IPV6", ""}, false), }, - - "project": &schema.Schema{ + "address": { + Type: schema.TypeString, + Computed: true, + }, + "creation_timestamp": { + Type: schema.TypeString, + Computed: true, + }, + "project": { Type: schema.TypeString, Optional: true, Computed: true, ForceNew: true, }, - - "address": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - }, - - "self_link": &schema.Schema{ + "self_link": { Type: schema.TypeString, Computed: true, }, @@ -61,24 +86,58 @@ func resourceComputeGlobalAddressCreate(d *schema.ResourceData, meta interface{} return err } - // Build the address parameter - addr := &compute.Address{ - Name: d.Get("name").(string), - IpVersion: d.Get("ip_version").(string), - } - - op, err := config.clientCompute.GlobalAddresses.Insert(project, addr).Do() - if err != nil { - return fmt.Errorf("Error creating address: %s", err) - } - - // It probably maybe worked, so store the ID now - d.SetId(addr.Name) - - err = computeSharedOperationWait(config.clientCompute, op, project, "Creating Global Address") + descriptionProp, err := expandComputeGlobalAddressDescription(d.Get("description"), d, config) if err != nil { return err } + nameProp, err := expandComputeGlobalAddressName(d.Get("name"), d, config) + if err != nil { + return err + } + ipVersionProp, err := expandComputeGlobalAddressIpVersion(d.Get("ip_version"), d, config) + if err != nil { + return err + } + + obj := map[string]interface{}{ + "description": descriptionProp, + "name": nameProp, + "ipVersion": ipVersionProp, + } + + url, err := replaceVars(d, config, "https://www.googleapis.com/compute/v1/projects/{{project}}/global/addresses") + if err != nil { + return err + } + + log.Printf("[DEBUG] Creating new GlobalAddress: %#v", obj) + res, err := Post(config, url, obj) + if err != nil { + return fmt.Errorf("Error creating GlobalAddress: %s", err) + } + + // Store the ID now + id, err := replaceVars(d, config, "{{name}}") + if err != nil { + return fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + op := &compute.Operation{} + err = Convert(res, op) + if err != nil { + return err + } + + waitErr := computeOperationWaitTime( + config.clientCompute, op, project, "Creating GlobalAddress", + int(d.Timeout(schema.TimeoutCreate).Minutes())) + + if waitErr != nil { + // The resource didn't actually create + d.SetId("") + return fmt.Errorf("Error waiting to create GlobalAddress: %s", waitErr) + } return resourceComputeGlobalAddressRead(d, meta) } @@ -91,16 +150,36 @@ func resourceComputeGlobalAddressRead(d *schema.ResourceData, meta interface{}) return err } - addr, err := config.clientCompute.GlobalAddresses.Get(project, d.Id()).Do() + url, err := replaceVars(d, config, "https://www.googleapis.com/compute/v1/projects/{{project}}/global/addresses/{{name}}") if err != nil { - return handleNotFoundError(err, d, fmt.Sprintf("Global Address %q", d.Get("name").(string))) + return err } - d.Set("name", addr.Name) - d.Set("ip_version", addr.IpVersion) - d.Set("address", addr.Address) - d.Set("project", project) - d.Set("self_link", ConvertSelfLinkToV1(addr.SelfLink)) + res, err := Get(config, url) + if err != nil { + return handleNotFoundError(err, d, fmt.Sprintf("ComputeGlobalAddress %q", d.Id())) + } + if err := d.Set("address", flattenComputeGlobalAddressAddress(res["address"])); err != nil { + return fmt.Errorf("Error reading GlobalAddress: %s", err) + } + if err := d.Set("creation_timestamp", flattenComputeGlobalAddressCreationTimestamp(res["creationTimestamp"])); err != nil { + return fmt.Errorf("Error reading GlobalAddress: %s", err) + } + if err := d.Set("description", flattenComputeGlobalAddressDescription(res["description"])); err != nil { + return fmt.Errorf("Error reading GlobalAddress: %s", err) + } + if err := d.Set("name", flattenComputeGlobalAddressName(res["name"])); err != nil { + return fmt.Errorf("Error reading GlobalAddress: %s", err) + } + if err := d.Set("ip_version", flattenComputeGlobalAddressIpVersion(res["ipVersion"])); err != nil { + return fmt.Errorf("Error reading GlobalAddress: %s", err) + } + if err := d.Set("self_link", res["selfLink"]); err != nil { + return fmt.Errorf("Error reading GlobalAddress: %s", err) + } + if err := d.Set("project", project); err != nil { + return fmt.Errorf("Error reading GlobalAddress: %s", err) + } return nil } @@ -113,18 +192,76 @@ func resourceComputeGlobalAddressDelete(d *schema.ResourceData, meta interface{} return err } - // Delete the address - log.Printf("[DEBUG] address delete request") - op, err := config.clientCompute.GlobalAddresses.Delete(project, d.Id()).Do() - if err != nil { - return fmt.Errorf("Error deleting address: %s", err) - } - - err = computeSharedOperationWait(config.clientCompute, op, project, "Deleting Global Address") + url, err := replaceVars(d, config, "https://www.googleapis.com/compute/v1/projects/{{project}}/global/addresses/{{name}}") + if err != nil { + return err + } + + log.Printf("[DEBUG] Deleting GlobalAddress %q", d.Id()) + res, err := Delete(config, url) + if err != nil { + return fmt.Errorf("Error deleting GlobalAddress %q: %s", d.Id(), err) + } + + op := &compute.Operation{} + err = Convert(res, op) + if err != nil { + return err + } + + err = computeOperationWaitTime( + config.clientCompute, op, project, "Deleting GlobalAddress", + int(d.Timeout(schema.TimeoutDelete).Minutes())) + if err != nil { return err } - d.SetId("") return nil } + +func resourceComputeGlobalAddressImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + config := meta.(*Config) + parseImportId([]string{"projects/(?P[^/]+)/global/addresses/(?P[^/]+)", "(?P[^/]+)/(?P[^/]+)", "(?P[^/]+)"}, d, config) + + // Replace import id for the resource id + id, err := replaceVars(d, config, "{{name}}") + if err != nil { + return nil, fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + return []*schema.ResourceData{d}, nil +} + +func flattenComputeGlobalAddressAddress(v interface{}) interface{} { + return v +} + +func flattenComputeGlobalAddressCreationTimestamp(v interface{}) interface{} { + return v +} + +func flattenComputeGlobalAddressDescription(v interface{}) interface{} { + return v +} + +func flattenComputeGlobalAddressName(v interface{}) interface{} { + return v +} + +func flattenComputeGlobalAddressIpVersion(v interface{}) interface{} { + return v +} + +func expandComputeGlobalAddressDescription(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeGlobalAddressName(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeGlobalAddressIpVersion(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} diff --git a/google/resource_compute_global_address_test.go b/google/resource_compute_global_address_test.go index d5e5290d..c93d724c 100644 --- a/google/resource_compute_global_address_test.go +++ b/google/resource_compute_global_address_test.go @@ -144,6 +144,7 @@ func testAccComputeGlobalAddress_basic() string { return fmt.Sprintf(` resource "google_compute_global_address" "foobar" { name = "address-test-%s" + description = "Created for Terraform acceptance testing" }`, acctest.RandString(10)) } @@ -151,6 +152,7 @@ func testAccComputeGlobalAddress_ipv6() string { return fmt.Sprintf(` resource "google_compute_global_address" "foobar" { name = "address-test-%s" + description = "Created for Terraform acceptance testing" ip_version = "IPV6" }`, acctest.RandString(10)) } diff --git a/google/resource_compute_http_health_check.go b/google/resource_compute_http_health_check.go index a0c3b2fc..83cb94c7 100644 --- a/google/resource_compute_http_health_check.go +++ b/google/resource_compute_http_health_check.go @@ -191,7 +191,7 @@ func resourceComputeHttpHealthCheckCreate(d *schema.ResourceData, meta interface if waitErr != nil { // The resource didn't actually create d.SetId("") - return waitErr + return fmt.Errorf("Error waiting to create HttpHealthCheck: %s", waitErr) } return resourceComputeHttpHealthCheckRead(d, meta) @@ -214,19 +214,42 @@ func resourceComputeHttpHealthCheckRead(d *schema.ResourceData, meta interface{} if err != nil { return handleNotFoundError(err, d, fmt.Sprintf("ComputeHttpHealthCheck %q", d.Id())) } - - d.Set("check_interval_sec", flattenComputeHttpHealthCheckCheckIntervalSec(res["checkIntervalSec"])) - d.Set("creation_timestamp", flattenComputeHttpHealthCheckCreationTimestamp(res["creationTimestamp"])) - d.Set("description", flattenComputeHttpHealthCheckDescription(res["description"])) - d.Set("healthy_threshold", flattenComputeHttpHealthCheckHealthyThreshold(res["healthyThreshold"])) - d.Set("host", flattenComputeHttpHealthCheckHost(res["host"])) - d.Set("name", flattenComputeHttpHealthCheckName(res["name"])) - d.Set("port", flattenComputeHttpHealthCheckPort(res["port"])) - d.Set("request_path", flattenComputeHttpHealthCheckRequestPath(res["requestPath"])) - d.Set("timeout_sec", flattenComputeHttpHealthCheckTimeoutSec(res["timeoutSec"])) - d.Set("unhealthy_threshold", flattenComputeHttpHealthCheckUnhealthyThreshold(res["unhealthyThreshold"])) - d.Set("self_link", res["selfLink"]) - d.Set("project", project) + if err := d.Set("check_interval_sec", flattenComputeHttpHealthCheckCheckIntervalSec(res["checkIntervalSec"])); err != nil { + return fmt.Errorf("Error reading HttpHealthCheck: %s", err) + } + if err := d.Set("creation_timestamp", flattenComputeHttpHealthCheckCreationTimestamp(res["creationTimestamp"])); err != nil { + return fmt.Errorf("Error reading HttpHealthCheck: %s", err) + } + if err := d.Set("description", flattenComputeHttpHealthCheckDescription(res["description"])); err != nil { + return fmt.Errorf("Error reading HttpHealthCheck: %s", err) + } + if err := d.Set("healthy_threshold", flattenComputeHttpHealthCheckHealthyThreshold(res["healthyThreshold"])); err != nil { + return fmt.Errorf("Error reading HttpHealthCheck: %s", err) + } + if err := d.Set("host", flattenComputeHttpHealthCheckHost(res["host"])); err != nil { + return fmt.Errorf("Error reading HttpHealthCheck: %s", err) + } + if err := d.Set("name", flattenComputeHttpHealthCheckName(res["name"])); err != nil { + return fmt.Errorf("Error reading HttpHealthCheck: %s", err) + } + if err := d.Set("port", flattenComputeHttpHealthCheckPort(res["port"])); err != nil { + return fmt.Errorf("Error reading HttpHealthCheck: %s", err) + } + if err := d.Set("request_path", flattenComputeHttpHealthCheckRequestPath(res["requestPath"])); err != nil { + return fmt.Errorf("Error reading HttpHealthCheck: %s", err) + } + if err := d.Set("timeout_sec", flattenComputeHttpHealthCheckTimeoutSec(res["timeoutSec"])); err != nil { + return fmt.Errorf("Error reading HttpHealthCheck: %s", err) + } + if err := d.Set("unhealthy_threshold", flattenComputeHttpHealthCheckUnhealthyThreshold(res["unhealthyThreshold"])); err != nil { + return fmt.Errorf("Error reading HttpHealthCheck: %s", err) + } + if err := d.Set("self_link", res["selfLink"]); err != nil { + return fmt.Errorf("Error reading HttpHealthCheck: %s", err) + } + if err := d.Set("project", project); err != nil { + return fmt.Errorf("Error reading HttpHealthCheck: %s", err) + } return nil } diff --git a/google/resource_compute_https_health_check.go b/google/resource_compute_https_health_check.go index 8692240f..1f82451d 100644 --- a/google/resource_compute_https_health_check.go +++ b/google/resource_compute_https_health_check.go @@ -191,7 +191,7 @@ func resourceComputeHttpsHealthCheckCreate(d *schema.ResourceData, meta interfac if waitErr != nil { // The resource didn't actually create d.SetId("") - return waitErr + return fmt.Errorf("Error waiting to create HttpsHealthCheck: %s", waitErr) } return resourceComputeHttpsHealthCheckRead(d, meta) @@ -214,19 +214,42 @@ func resourceComputeHttpsHealthCheckRead(d *schema.ResourceData, meta interface{ if err != nil { return handleNotFoundError(err, d, fmt.Sprintf("ComputeHttpsHealthCheck %q", d.Id())) } - - d.Set("check_interval_sec", flattenComputeHttpsHealthCheckCheckIntervalSec(res["checkIntervalSec"])) - d.Set("creation_timestamp", flattenComputeHttpsHealthCheckCreationTimestamp(res["creationTimestamp"])) - d.Set("description", flattenComputeHttpsHealthCheckDescription(res["description"])) - d.Set("healthy_threshold", flattenComputeHttpsHealthCheckHealthyThreshold(res["healthyThreshold"])) - d.Set("host", flattenComputeHttpsHealthCheckHost(res["host"])) - d.Set("name", flattenComputeHttpsHealthCheckName(res["name"])) - d.Set("port", flattenComputeHttpsHealthCheckPort(res["port"])) - d.Set("request_path", flattenComputeHttpsHealthCheckRequestPath(res["requestPath"])) - d.Set("timeout_sec", flattenComputeHttpsHealthCheckTimeoutSec(res["timeoutSec"])) - d.Set("unhealthy_threshold", flattenComputeHttpsHealthCheckUnhealthyThreshold(res["unhealthyThreshold"])) - d.Set("self_link", res["selfLink"]) - d.Set("project", project) + if err := d.Set("check_interval_sec", flattenComputeHttpsHealthCheckCheckIntervalSec(res["checkIntervalSec"])); err != nil { + return fmt.Errorf("Error reading HttpsHealthCheck: %s", err) + } + if err := d.Set("creation_timestamp", flattenComputeHttpsHealthCheckCreationTimestamp(res["creationTimestamp"])); err != nil { + return fmt.Errorf("Error reading HttpsHealthCheck: %s", err) + } + if err := d.Set("description", flattenComputeHttpsHealthCheckDescription(res["description"])); err != nil { + return fmt.Errorf("Error reading HttpsHealthCheck: %s", err) + } + if err := d.Set("healthy_threshold", flattenComputeHttpsHealthCheckHealthyThreshold(res["healthyThreshold"])); err != nil { + return fmt.Errorf("Error reading HttpsHealthCheck: %s", err) + } + if err := d.Set("host", flattenComputeHttpsHealthCheckHost(res["host"])); err != nil { + return fmt.Errorf("Error reading HttpsHealthCheck: %s", err) + } + if err := d.Set("name", flattenComputeHttpsHealthCheckName(res["name"])); err != nil { + return fmt.Errorf("Error reading HttpsHealthCheck: %s", err) + } + if err := d.Set("port", flattenComputeHttpsHealthCheckPort(res["port"])); err != nil { + return fmt.Errorf("Error reading HttpsHealthCheck: %s", err) + } + if err := d.Set("request_path", flattenComputeHttpsHealthCheckRequestPath(res["requestPath"])); err != nil { + return fmt.Errorf("Error reading HttpsHealthCheck: %s", err) + } + if err := d.Set("timeout_sec", flattenComputeHttpsHealthCheckTimeoutSec(res["timeoutSec"])); err != nil { + return fmt.Errorf("Error reading HttpsHealthCheck: %s", err) + } + if err := d.Set("unhealthy_threshold", flattenComputeHttpsHealthCheckUnhealthyThreshold(res["unhealthyThreshold"])); err != nil { + return fmt.Errorf("Error reading HttpsHealthCheck: %s", err) + } + if err := d.Set("self_link", res["selfLink"]); err != nil { + return fmt.Errorf("Error reading HttpsHealthCheck: %s", err) + } + if err := d.Set("project", project); err != nil { + return fmt.Errorf("Error reading HttpsHealthCheck: %s", err) + } return nil } diff --git a/google/resource_compute_target_http_proxy.go b/google/resource_compute_target_http_proxy.go index 14501dff..07ab1bc7 100644 --- a/google/resource_compute_target_http_proxy.go +++ b/google/resource_compute_target_http_proxy.go @@ -1,57 +1,77 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file in +// .github/CONTRIBUTING.md. +// +// ---------------------------------------------------------------------------- + package google import ( "fmt" "log" "strconv" + "time" "github.com/hashicorp/terraform/helper/schema" - "google.golang.org/api/compute/v1" + compute "google.golang.org/api/compute/v1" ) func resourceComputeTargetHttpProxy() *schema.Resource { return &schema.Resource{ Create: resourceComputeTargetHttpProxyCreate, Read: resourceComputeTargetHttpProxyRead, - Delete: resourceComputeTargetHttpProxyDelete, Update: resourceComputeTargetHttpProxyUpdate, + Delete: resourceComputeTargetHttpProxyDelete, Importer: &schema.ResourceImporter{ - State: schema.ImportStatePassthrough, + State: resourceComputeTargetHttpProxyImport, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(240 * time.Second), + Update: schema.DefaultTimeout(240 * time.Second), + Delete: schema.DefaultTimeout(240 * time.Second), }, Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Required: true, ForceNew: true, }, - - "url_map": &schema.Schema{ + "url_map": { Type: schema.TypeString, Required: true, - DiffSuppressFunc: compareSelfLinkRelativePaths, + DiffSuppressFunc: compareSelfLinkOrResourceName, }, - - "description": &schema.Schema{ + "description": { Type: schema.TypeString, Optional: true, ForceNew: true, }, - - "proxy_id": &schema.Schema{ + "creation_timestamp": { Type: schema.TypeString, Computed: true, }, - - "project": &schema.Schema{ + "proxy_id": { + Type: schema.TypeInt, + Computed: true, + }, + "project": { Type: schema.TypeString, Optional: true, Computed: true, ForceNew: true, }, - - "self_link": &schema.Schema{ + "self_link": { Type: schema.TypeString, Computed: true, }, @@ -67,61 +87,59 @@ func resourceComputeTargetHttpProxyCreate(d *schema.ResourceData, meta interface return err } - proxy := &compute.TargetHttpProxy{ - Name: d.Get("name").(string), - UrlMap: d.Get("url_map").(string), + descriptionProp, err := expandComputeTargetHttpProxyDescription(d.Get("description"), d, config) + if err != nil { + return err + } + nameProp, err := expandComputeTargetHttpProxyName(d.Get("name"), d, config) + if err != nil { + return err + } + urlMapProp, err := expandComputeTargetHttpProxyUrlMap(d.Get("url_map"), d, config) + if err != nil { + return err } - if v, ok := d.GetOk("description"); ok { - proxy.Description = v.(string) + obj := map[string]interface{}{ + "description": descriptionProp, + "name": nameProp, + "urlMap": urlMapProp, } - log.Printf("[DEBUG] TargetHttpProxy insert request: %#v", proxy) - op, err := config.clientCompute.TargetHttpProxies.Insert( - project, proxy).Do() + url, err := replaceVars(d, config, "https://www.googleapis.com/compute/v1/projects/{{project}}/global/targetHttpProxies") + if err != nil { + return err + } + + log.Printf("[DEBUG] Creating new TargetHttpProxy: %#v", obj) + res, err := Post(config, url, obj) if err != nil { return fmt.Errorf("Error creating TargetHttpProxy: %s", err) } - err = computeOperationWait(config.clientCompute, op, project, "Creating Target Http Proxy") + // Store the ID now + id, err := replaceVars(d, config, "{{name}}") + if err != nil { + return fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + op := &compute.Operation{} + err = Convert(res, op) if err != nil { return err } - d.SetId(proxy.Name) + waitErr := computeOperationWaitTime( + config.clientCompute, op, project, "Creating TargetHttpProxy", + int(d.Timeout(schema.TimeoutCreate).Minutes())) - return resourceComputeTargetHttpProxyRead(d, meta) -} - -func resourceComputeTargetHttpProxyUpdate(d *schema.ResourceData, meta interface{}) error { - config := meta.(*Config) - - project, err := getProject(d, config) - if err != nil { - return err + if waitErr != nil { + // The resource didn't actually create + d.SetId("") + return fmt.Errorf("Error waiting to create TargetHttpProxy: %s", waitErr) } - d.Partial(true) - - if d.HasChange("url_map") { - url_map := d.Get("url_map").(string) - url_map_ref := &compute.UrlMapReference{UrlMap: url_map} - op, err := config.clientCompute.TargetHttpProxies.SetUrlMap( - project, d.Id(), url_map_ref).Do() - if err != nil { - return fmt.Errorf("Error updating target: %s", err) - } - - err = computeOperationWait(config.clientCompute, op, project, "Updating Target Http Proxy") - if err != nil { - return err - } - - d.SetPartial("url_map") - } - - d.Partial(false) - return resourceComputeTargetHttpProxyRead(d, meta) } @@ -133,22 +151,93 @@ func resourceComputeTargetHttpProxyRead(d *schema.ResourceData, meta interface{} return err } - proxy, err := config.clientCompute.TargetHttpProxies.Get( - project, d.Id()).Do() + url, err := replaceVars(d, config, "https://www.googleapis.com/compute/v1/projects/{{project}}/global/targetHttpProxies/{{name}}") if err != nil { - return handleNotFoundError(err, d, fmt.Sprintf("Target HTTP Proxy %q", d.Get("name").(string))) + return err } - d.Set("self_link", proxy.SelfLink) - d.Set("proxy_id", strconv.FormatUint(proxy.Id, 10)) - d.Set("description", proxy.Description) - d.Set("url_map", proxy.UrlMap) - d.Set("name", proxy.Name) - d.Set("project", project) + res, err := Get(config, url) + if err != nil { + return handleNotFoundError(err, d, fmt.Sprintf("ComputeTargetHttpProxy %q", d.Id())) + } + if err := d.Set("creation_timestamp", flattenComputeTargetHttpProxyCreationTimestamp(res["creationTimestamp"])); err != nil { + return fmt.Errorf("Error reading TargetHttpProxy: %s", err) + } + if err := d.Set("description", flattenComputeTargetHttpProxyDescription(res["description"])); err != nil { + return fmt.Errorf("Error reading TargetHttpProxy: %s", err) + } + if err := d.Set("proxy_id", flattenComputeTargetHttpProxyProxyId(res["id"])); err != nil { + return fmt.Errorf("Error reading TargetHttpProxy: %s", err) + } + if err := d.Set("name", flattenComputeTargetHttpProxyName(res["name"])); err != nil { + return fmt.Errorf("Error reading TargetHttpProxy: %s", err) + } + if err := d.Set("url_map", flattenComputeTargetHttpProxyUrlMap(res["urlMap"])); err != nil { + return fmt.Errorf("Error reading TargetHttpProxy: %s", err) + } + if err := d.Set("self_link", res["selfLink"]); err != nil { + return fmt.Errorf("Error reading TargetHttpProxy: %s", err) + } + if err := d.Set("project", project); err != nil { + return fmt.Errorf("Error reading TargetHttpProxy: %s", err) + } return nil } +func resourceComputeTargetHttpProxyUpdate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + project, err := getProject(d, config) + if err != nil { + return err + } + + var url string + var res map[string]interface{} + op := &compute.Operation{} + + d.Partial(true) + + if d.HasChange("url_map") { + urlMapProp, err := expandComputeTargetHttpProxyUrlMap(d.Get("url_map"), d, config) + if err != nil { + return err + } + + obj := map[string]interface{}{ + "urlMap": urlMapProp, + } + url, err = replaceVars(d, config, "https://www.googleapis.com/compute/v1/projects/{{project}}/targetHttpProxies/{{name}}/setUrlMap") + if err != nil { + return err + } + res, err = sendRequest(config, "POST", url, obj) + if err != nil { + return fmt.Errorf("Error updating TargetHttpProxy %q: %s", d.Id(), err) + } + + err = Convert(res, op) + if err != nil { + return err + } + + err = computeOperationWaitTime( + config.clientCompute, op, project, "Updating TargetHttpProxy", + int(d.Timeout(schema.TimeoutUpdate).Minutes())) + + if err != nil { + return err + } + + d.SetPartial("url_map") + } + + d.Partial(false) + + return resourceComputeTargetHttpProxyRead(d, meta) +} + func resourceComputeTargetHttpProxyDelete(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) @@ -157,19 +246,86 @@ func resourceComputeTargetHttpProxyDelete(d *schema.ResourceData, meta interface return err } - // Delete the TargetHttpProxy - log.Printf("[DEBUG] TargetHttpProxy delete request") - op, err := config.clientCompute.TargetHttpProxies.Delete( - project, d.Id()).Do() - if err != nil { - return fmt.Errorf("Error deleting TargetHttpProxy: %s", err) - } - - err = computeOperationWait(config.clientCompute, op, project, "Deleting Target Http Proxy") + url, err := replaceVars(d, config, "https://www.googleapis.com/compute/v1/projects/{{project}}/global/targetHttpProxies/{{name}}") + if err != nil { + return err + } + + log.Printf("[DEBUG] Deleting TargetHttpProxy %q", d.Id()) + res, err := Delete(config, url) + if err != nil { + return fmt.Errorf("Error deleting TargetHttpProxy %q: %s", d.Id(), err) + } + + op := &compute.Operation{} + err = Convert(res, op) + if err != nil { + return err + } + + err = computeOperationWaitTime( + config.clientCompute, op, project, "Deleting TargetHttpProxy", + int(d.Timeout(schema.TimeoutDelete).Minutes())) + if err != nil { return err } - d.SetId("") return nil } + +func resourceComputeTargetHttpProxyImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + config := meta.(*Config) + parseImportId([]string{"projects/(?P[^/]+)/global/targetHttpProxies/(?P[^/]+)", "(?P[^/]+)/(?P[^/]+)", "(?P[^/]+)"}, d, config) + + // Replace import id for the resource id + id, err := replaceVars(d, config, "{{name}}") + if err != nil { + return nil, fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + return []*schema.ResourceData{d}, nil +} + +func flattenComputeTargetHttpProxyCreationTimestamp(v interface{}) interface{} { + return v +} + +func flattenComputeTargetHttpProxyDescription(v interface{}) interface{} { + return v +} + +func flattenComputeTargetHttpProxyProxyId(v interface{}) interface{} { + // Handles the string fixed64 format + if strVal, ok := v.(string); ok { + if intVal, err := strconv.Atoi(strVal); err == nil { + return intVal + } // let terraform core handle it if we can't convert the string to an int. + } + return v +} + +func flattenComputeTargetHttpProxyName(v interface{}) interface{} { + return v +} + +func flattenComputeTargetHttpProxyUrlMap(v interface{}) interface{} { + return v +} + +func expandComputeTargetHttpProxyDescription(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeTargetHttpProxyName(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeTargetHttpProxyUrlMap(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + f, err := parseGlobalFieldValue("urlMaps", v.(string), "project", d, config, true) + if err != nil { + return nil, fmt.Errorf("Invalid value for url_map: %s", err) + } + return f.RelativeLink(), nil +} diff --git a/google/resource_compute_target_https_proxy.go b/google/resource_compute_target_https_proxy.go index f5de0bc0..e5ebcb58 100644 --- a/google/resource_compute_target_https_proxy.go +++ b/google/resource_compute_target_https_proxy.go @@ -1,37 +1,53 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file in +// .github/CONTRIBUTING.md. +// +// ---------------------------------------------------------------------------- + package google import ( "fmt" "log" "strconv" + "time" "github.com/hashicorp/terraform/helper/schema" - "google.golang.org/api/compute/v1" -) - -const ( - canonicalSslCertificateTemplate = "https://www.googleapis.com/compute/v1/projects/%s/global/sslCertificates/%s" + compute "google.golang.org/api/compute/v1" ) func resourceComputeTargetHttpsProxy() *schema.Resource { return &schema.Resource{ Create: resourceComputeTargetHttpsProxyCreate, Read: resourceComputeTargetHttpsProxyRead, - Delete: resourceComputeTargetHttpsProxyDelete, Update: resourceComputeTargetHttpsProxyUpdate, + Delete: resourceComputeTargetHttpsProxyDelete, Importer: &schema.ResourceImporter{ - State: schema.ImportStatePassthrough, + State: resourceComputeTargetHttpsProxyImport, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(240 * time.Second), + Update: schema.DefaultTimeout(240 * time.Second), + Delete: schema.DefaultTimeout(240 * time.Second), }, Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Required: true, ForceNew: true, }, - - "ssl_certificates": &schema.Schema{ + "ssl_certificates": { Type: schema.TypeList, Required: true, Elem: &schema.Schema{ @@ -39,35 +55,34 @@ func resourceComputeTargetHttpsProxy() *schema.Resource { DiffSuppressFunc: compareSelfLinkOrResourceName, }, }, - - "url_map": &schema.Schema{ + "url_map": { Type: schema.TypeString, Required: true, - DiffSuppressFunc: compareSelfLinkRelativePaths, + DiffSuppressFunc: compareSelfLinkOrResourceName, }, - - "description": &schema.Schema{ + "description": { Type: schema.TypeString, Optional: true, ForceNew: true, }, - - "self_link": &schema.Schema{ + "creation_timestamp": { Type: schema.TypeString, Computed: true, }, - - "proxy_id": &schema.Schema{ - Type: schema.TypeString, + "proxy_id": { + Type: schema.TypeInt, Computed: true, }, - - "project": &schema.Schema{ + "project": { Type: schema.TypeString, Optional: true, Computed: true, ForceNew: true, }, + "self_link": { + Type: schema.TypeString, + Computed: true, + }, }, } } @@ -80,89 +95,64 @@ func resourceComputeTargetHttpsProxyCreate(d *schema.ResourceData, meta interfac return err } - sslCertificates, err := expandSslCertificates(d, config) + descriptionProp, err := expandComputeTargetHttpsProxyDescription(d.Get("description"), d, config) + if err != nil { + return err + } + nameProp, err := expandComputeTargetHttpsProxyName(d.Get("name"), d, config) + if err != nil { + return err + } + sslCertificatesProp, err := expandComputeTargetHttpsProxySslCertificates(d.Get("ssl_certificates"), d, config) + if err != nil { + return err + } + urlMapProp, err := expandComputeTargetHttpsProxyUrlMap(d.Get("url_map"), d, config) if err != nil { return err } - proxy := &compute.TargetHttpsProxy{ - Name: d.Get("name").(string), - UrlMap: d.Get("url_map").(string), - SslCertificates: sslCertificates, + obj := map[string]interface{}{ + "description": descriptionProp, + "name": nameProp, + "sslCertificates": sslCertificatesProp, + "urlMap": urlMapProp, } - if v, ok := d.GetOk("description"); ok { - proxy.Description = v.(string) + url, err := replaceVars(d, config, "https://www.googleapis.com/compute/v1/projects/{{project}}/global/targetHttpsProxies") + if err != nil { + return err } - log.Printf("[DEBUG] TargetHttpsProxy insert request: %#v", proxy) - op, err := config.clientCompute.TargetHttpsProxies.Insert( - project, proxy).Do() + log.Printf("[DEBUG] Creating new TargetHttpsProxy: %#v", obj) + res, err := Post(config, url, obj) if err != nil { return fmt.Errorf("Error creating TargetHttpsProxy: %s", err) } - err = computeOperationWait(config.clientCompute, op, project, "Creating Target Https Proxy") + // Store the ID now + id, err := replaceVars(d, config, "{{name}}") + if err != nil { + return fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + op := &compute.Operation{} + err = Convert(res, op) if err != nil { return err } - d.SetId(proxy.Name) + waitErr := computeOperationWaitTime( + config.clientCompute, op, project, "Creating TargetHttpsProxy", + int(d.Timeout(schema.TimeoutCreate).Minutes())) - return resourceComputeTargetHttpsProxyRead(d, meta) -} - -func resourceComputeTargetHttpsProxyUpdate(d *schema.ResourceData, meta interface{}) error { - config := meta.(*Config) - - project, err := getProject(d, config) - if err != nil { - return err + if waitErr != nil { + // The resource didn't actually create + d.SetId("") + return fmt.Errorf("Error waiting to create TargetHttpsProxy: %s", waitErr) } - d.Partial(true) - - if d.HasChange("url_map") { - url_map := d.Get("url_map").(string) - url_map_ref := &compute.UrlMapReference{UrlMap: url_map} - op, err := config.clientCompute.TargetHttpsProxies.SetUrlMap( - project, d.Id(), url_map_ref).Do() - if err != nil { - return fmt.Errorf("Error updating Target HTTPS proxy URL map: %s", err) - } - - err = computeOperationWait(config.clientCompute, op, project, "Updating Target Https Proxy URL Map") - if err != nil { - return err - } - - d.SetPartial("url_map") - } - - if d.HasChange("ssl_certificates") { - certs, err := expandSslCertificates(d, config) - if err != nil { - return err - } - cert_ref := &compute.TargetHttpsProxiesSetSslCertificatesRequest{ - SslCertificates: certs, - } - op, err := config.clientCompute.TargetHttpsProxies.SetSslCertificates( - project, d.Id(), cert_ref).Do() - if err != nil { - return fmt.Errorf("Error updating Target Https Proxy SSL Certificates: %s", err) - } - - err = computeOperationWait(config.clientCompute, op, project, "Updating Target Https Proxy SSL certificates") - if err != nil { - return err - } - - d.SetPartial("ssl_certificate") - } - - d.Partial(false) - return resourceComputeTargetHttpsProxyRead(d, meta) } @@ -174,23 +164,129 @@ func resourceComputeTargetHttpsProxyRead(d *schema.ResourceData, meta interface{ return err } - proxy, err := config.clientCompute.TargetHttpsProxies.Get( - project, d.Id()).Do() + url, err := replaceVars(d, config, "https://www.googleapis.com/compute/v1/projects/{{project}}/global/targetHttpsProxies/{{name}}") if err != nil { - return handleNotFoundError(err, d, fmt.Sprintf("Target HTTPS proxy %q", d.Get("name").(string))) + return err } - d.Set("ssl_certificates", proxy.SslCertificates) - d.Set("proxy_id", strconv.FormatUint(proxy.Id, 10)) - d.Set("self_link", proxy.SelfLink) - d.Set("description", proxy.Description) - d.Set("url_map", proxy.UrlMap) - d.Set("name", proxy.Name) - d.Set("project", project) + res, err := Get(config, url) + if err != nil { + return handleNotFoundError(err, d, fmt.Sprintf("ComputeTargetHttpsProxy %q", d.Id())) + } + if err := d.Set("creation_timestamp", flattenComputeTargetHttpsProxyCreationTimestamp(res["creationTimestamp"])); err != nil { + return fmt.Errorf("Error reading TargetHttpsProxy: %s", err) + } + if err := d.Set("description", flattenComputeTargetHttpsProxyDescription(res["description"])); err != nil { + return fmt.Errorf("Error reading TargetHttpsProxy: %s", err) + } + if err := d.Set("proxy_id", flattenComputeTargetHttpsProxyProxyId(res["id"])); err != nil { + return fmt.Errorf("Error reading TargetHttpsProxy: %s", err) + } + if err := d.Set("name", flattenComputeTargetHttpsProxyName(res["name"])); err != nil { + return fmt.Errorf("Error reading TargetHttpsProxy: %s", err) + } + if err := d.Set("ssl_certificates", flattenComputeTargetHttpsProxySslCertificates(res["sslCertificates"])); err != nil { + return fmt.Errorf("Error reading TargetHttpsProxy: %s", err) + } + if err := d.Set("url_map", flattenComputeTargetHttpsProxyUrlMap(res["urlMap"])); err != nil { + return fmt.Errorf("Error reading TargetHttpsProxy: %s", err) + } + if err := d.Set("self_link", res["selfLink"]); err != nil { + return fmt.Errorf("Error reading TargetHttpsProxy: %s", err) + } + if err := d.Set("project", project); err != nil { + return fmt.Errorf("Error reading TargetHttpsProxy: %s", err) + } return nil } +func resourceComputeTargetHttpsProxyUpdate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + project, err := getProject(d, config) + if err != nil { + return err + } + + var url string + var res map[string]interface{} + op := &compute.Operation{} + + d.Partial(true) + + if d.HasChange("ssl_certificates") { + sslCertificatesProp, err := expandComputeTargetHttpsProxySslCertificates(d.Get("ssl_certificates"), d, config) + if err != nil { + return err + } + + obj := map[string]interface{}{ + "sslCertificates": sslCertificatesProp, + } + url, err = replaceVars(d, config, "https://www.googleapis.com/compute/v1/projects/{{project}}/targetHttpsProxies/{{name}}/setSslCertificates") + if err != nil { + return err + } + res, err = sendRequest(config, "POST", url, obj) + if err != nil { + return fmt.Errorf("Error updating TargetHttpsProxy %q: %s", d.Id(), err) + } + + err = Convert(res, op) + if err != nil { + return err + } + + err = computeOperationWaitTime( + config.clientCompute, op, project, "Updating TargetHttpsProxy", + int(d.Timeout(schema.TimeoutUpdate).Minutes())) + + if err != nil { + return err + } + + d.SetPartial("ssl_certificates") + } + if d.HasChange("url_map") { + urlMapProp, err := expandComputeTargetHttpsProxyUrlMap(d.Get("url_map"), d, config) + if err != nil { + return err + } + + obj := map[string]interface{}{ + "urlMap": urlMapProp, + } + url, err = replaceVars(d, config, "https://www.googleapis.com/compute/v1/projects/{{project}}/targetHttpsProxies/{{name}}/setUrlMap") + if err != nil { + return err + } + res, err = sendRequest(config, "POST", url, obj) + if err != nil { + return fmt.Errorf("Error updating TargetHttpsProxy %q: %s", d.Id(), err) + } + + err = Convert(res, op) + if err != nil { + return err + } + + err = computeOperationWaitTime( + config.clientCompute, op, project, "Updating TargetHttpsProxy", + int(d.Timeout(schema.TimeoutUpdate).Minutes())) + + if err != nil { + return err + } + + d.SetPartial("url_map") + } + + d.Partial(false) + + return resourceComputeTargetHttpsProxyRead(d, meta) +} + func resourceComputeTargetHttpsProxyDelete(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) @@ -199,35 +295,103 @@ func resourceComputeTargetHttpsProxyDelete(d *schema.ResourceData, meta interfac return err } - // Delete the TargetHttpsProxy - log.Printf("[DEBUG] TargetHttpsProxy delete request") - op, err := config.clientCompute.TargetHttpsProxies.Delete( - project, d.Id()).Do() - if err != nil { - return fmt.Errorf("Error deleting TargetHttpsProxy: %s", err) - } - - err = computeOperationWait(config.clientCompute, op, project, "Deleting Target Https Proxy") + url, err := replaceVars(d, config, "https://www.googleapis.com/compute/v1/projects/{{project}}/global/targetHttpsProxies/{{name}}") + if err != nil { + return err + } + + log.Printf("[DEBUG] Deleting TargetHttpsProxy %q", d.Id()) + res, err := Delete(config, url) + if err != nil { + return fmt.Errorf("Error deleting TargetHttpsProxy %q: %s", d.Id(), err) + } + + op := &compute.Operation{} + err = Convert(res, op) + if err != nil { + return err + } + + err = computeOperationWaitTime( + config.clientCompute, op, project, "Deleting TargetHttpsProxy", + int(d.Timeout(schema.TimeoutDelete).Minutes())) + if err != nil { return err } - d.SetId("") return nil } -func expandSslCertificates(d *schema.ResourceData, config *Config) ([]string, error) { - configured := d.Get("ssl_certificates").([]interface{}) - certs := make([]string, 0, len(configured)) +func resourceComputeTargetHttpsProxyImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + config := meta.(*Config) + parseImportId([]string{"projects/(?P[^/]+)/global/targetHttpsProxies/(?P[^/]+)", "(?P[^/]+)/(?P[^/]+)", "(?P[^/]+)"}, d, config) - for _, sslCertificate := range configured { - sslCertificateFieldValue, err := ParseSslCertificateFieldValue(sslCertificate.(string), d, config) - if err != nil { - return nil, fmt.Errorf("Invalid ssl certificate: %s", err) - } - - certs = append(certs, sslCertificateFieldValue.RelativeLink()) + // Replace import id for the resource id + id, err := replaceVars(d, config, "{{name}}") + if err != nil { + return nil, fmt.Errorf("Error constructing id: %s", err) } + d.SetId(id) - return certs, nil + return []*schema.ResourceData{d}, nil +} + +func flattenComputeTargetHttpsProxyCreationTimestamp(v interface{}) interface{} { + return v +} + +func flattenComputeTargetHttpsProxyDescription(v interface{}) interface{} { + return v +} + +func flattenComputeTargetHttpsProxyProxyId(v interface{}) interface{} { + // Handles the string fixed64 format + if strVal, ok := v.(string); ok { + if intVal, err := strconv.Atoi(strVal); err == nil { + return intVal + } // let terraform core handle it if we can't convert the string to an int. + } + return v +} + +func flattenComputeTargetHttpsProxyName(v interface{}) interface{} { + return v +} + +func flattenComputeTargetHttpsProxySslCertificates(v interface{}) interface{} { + return v +} + +func flattenComputeTargetHttpsProxyUrlMap(v interface{}) interface{} { + return v +} + +func expandComputeTargetHttpsProxyDescription(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeTargetHttpsProxyName(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeTargetHttpsProxySslCertificates(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + req := make([]interface{}, 0, len(l)) + for _, raw := range l { + f, err := parseGlobalFieldValue("sslCertificates", raw.(string), "project", d, config, true) + if err != nil { + return nil, fmt.Errorf("Invalid value for ssl_certificates: %s", err) + } + req = append(req, f.RelativeLink()) + } + return req, nil +} + +func expandComputeTargetHttpsProxyUrlMap(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + f, err := parseGlobalFieldValue("urlMaps", v.(string), "project", d, config, true) + if err != nil { + return nil, fmt.Errorf("Invalid value for url_map: %s", err) + } + return f.RelativeLink(), nil } diff --git a/google/resource_compute_target_https_proxy_test.go b/google/resource_compute_target_https_proxy_test.go index 5c99b27f..8d20c3c5 100644 --- a/google/resource_compute_target_https_proxy_test.go +++ b/google/resource_compute_target_https_proxy_test.go @@ -10,6 +10,10 @@ import ( "google.golang.org/api/compute/v1" ) +const ( + canonicalSslCertificateTemplate = "https://www.googleapis.com/compute/v1/projects/%s/global/sslCertificates/%s" +) + func TestAccComputeTargetHttpsProxy_basic(t *testing.T) { t.Parallel() diff --git a/google/resource_compute_target_ssl_proxy.go b/google/resource_compute_target_ssl_proxy.go index 9b3fa31e..7c1fb15b 100644 --- a/google/resource_compute_target_ssl_proxy.go +++ b/google/resource_compute_target_ssl_proxy.go @@ -21,6 +21,7 @@ import ( "time" "github.com/hashicorp/terraform/helper/schema" + "github.com/hashicorp/terraform/helper/validation" compute "google.golang.org/api/compute/v1" ) @@ -67,9 +68,10 @@ func resourceComputeTargetSslProxy() *schema.Resource { ForceNew: true, }, "proxy_header": { - Type: schema.TypeString, - Optional: true, - Default: "NONE", + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{"NONE", "PROXY_V1", ""}, false), + Default: "NONE", }, "creation_timestamp": { Type: schema.TypeString, @@ -161,7 +163,7 @@ func resourceComputeTargetSslProxyCreate(d *schema.ResourceData, meta interface{ if waitErr != nil { // The resource didn't actually create d.SetId("") - return waitErr + return fmt.Errorf("Error waiting to create TargetSslProxy: %s", waitErr) } return resourceComputeTargetSslProxyRead(d, meta) @@ -184,16 +186,33 @@ func resourceComputeTargetSslProxyRead(d *schema.ResourceData, meta interface{}) if err != nil { return handleNotFoundError(err, d, fmt.Sprintf("ComputeTargetSslProxy %q", d.Id())) } - - d.Set("creation_timestamp", flattenComputeTargetSslProxyCreationTimestamp(res["creationTimestamp"])) - d.Set("description", flattenComputeTargetSslProxyDescription(res["description"])) - d.Set("proxy_id", flattenComputeTargetSslProxyProxyId(res["id"])) - d.Set("name", flattenComputeTargetSslProxyName(res["name"])) - d.Set("proxy_header", flattenComputeTargetSslProxyProxyHeader(res["proxyHeader"])) - d.Set("backend_service", flattenComputeTargetSslProxyBackendService(res["service"])) - d.Set("ssl_certificates", flattenComputeTargetSslProxySslCertificates(res["sslCertificates"])) - d.Set("self_link", res["selfLink"]) - d.Set("project", project) + if err := d.Set("creation_timestamp", flattenComputeTargetSslProxyCreationTimestamp(res["creationTimestamp"])); err != nil { + return fmt.Errorf("Error reading TargetSslProxy: %s", err) + } + if err := d.Set("description", flattenComputeTargetSslProxyDescription(res["description"])); err != nil { + return fmt.Errorf("Error reading TargetSslProxy: %s", err) + } + if err := d.Set("proxy_id", flattenComputeTargetSslProxyProxyId(res["id"])); err != nil { + return fmt.Errorf("Error reading TargetSslProxy: %s", err) + } + if err := d.Set("name", flattenComputeTargetSslProxyName(res["name"])); err != nil { + return fmt.Errorf("Error reading TargetSslProxy: %s", err) + } + if err := d.Set("proxy_header", flattenComputeTargetSslProxyProxyHeader(res["proxyHeader"])); err != nil { + return fmt.Errorf("Error reading TargetSslProxy: %s", err) + } + if err := d.Set("backend_service", flattenComputeTargetSslProxyBackendService(res["service"])); err != nil { + return fmt.Errorf("Error reading TargetSslProxy: %s", err) + } + if err := d.Set("ssl_certificates", flattenComputeTargetSslProxySslCertificates(res["sslCertificates"])); err != nil { + return fmt.Errorf("Error reading TargetSslProxy: %s", err) + } + if err := d.Set("self_link", res["selfLink"]); err != nil { + return fmt.Errorf("Error reading TargetSslProxy: %s", err) + } + if err := d.Set("project", project); err != nil { + return fmt.Errorf("Error reading TargetSslProxy: %s", err) + } return nil } @@ -210,34 +229,16 @@ func resourceComputeTargetSslProxyUpdate(d *schema.ResourceData, meta interface{ var res map[string]interface{} op := &compute.Operation{} + d.Partial(true) + if d.HasChange("proxy_header") { - descriptionProp, err := expandComputeTargetSslProxyDescription(d.Get("description"), d, config) - if err != nil { - return err - } - nameProp, err := expandComputeTargetSslProxyName(d.Get("name"), d, config) - if err != nil { - return err - } proxyHeaderProp, err := expandComputeTargetSslProxyProxyHeader(d.Get("proxy_header"), d, config) if err != nil { return err } - serviceProp, err := expandComputeTargetSslProxyBackendService(d.Get("backend_service"), d, config) - if err != nil { - return err - } - sslCertificatesProp, err := expandComputeTargetSslProxySslCertificates(d.Get("ssl_certificates"), d, config) - if err != nil { - return err - } obj := map[string]interface{}{ - "description": descriptionProp, - "name": nameProp, - "proxyHeader": proxyHeaderProp, - "service": serviceProp, - "sslCertificates": sslCertificatesProp, + "proxyHeader": proxyHeaderProp, } url, err = replaceVars(d, config, "https://www.googleapis.com/compute/v1/projects/{{project}}/global/targetSslProxies/{{name}}/setProxyHeader") if err != nil { @@ -260,35 +261,17 @@ func resourceComputeTargetSslProxyUpdate(d *schema.ResourceData, meta interface{ if err != nil { return err } + + d.SetPartial("proxy_header") } if d.HasChange("backend_service") { - descriptionProp, err := expandComputeTargetSslProxyDescription(d.Get("description"), d, config) - if err != nil { - return err - } - nameProp, err := expandComputeTargetSslProxyName(d.Get("name"), d, config) - if err != nil { - return err - } - proxyHeaderProp, err := expandComputeTargetSslProxyProxyHeader(d.Get("proxy_header"), d, config) - if err != nil { - return err - } serviceProp, err := expandComputeTargetSslProxyBackendService(d.Get("backend_service"), d, config) if err != nil { return err } - sslCertificatesProp, err := expandComputeTargetSslProxySslCertificates(d.Get("ssl_certificates"), d, config) - if err != nil { - return err - } obj := map[string]interface{}{ - "description": descriptionProp, - "name": nameProp, - "proxyHeader": proxyHeaderProp, - "service": serviceProp, - "sslCertificates": sslCertificatesProp, + "service": serviceProp, } url, err = replaceVars(d, config, "https://www.googleapis.com/compute/v1/projects/{{project}}/global/targetSslProxies/{{name}}/setBackendService") if err != nil { @@ -311,34 +294,16 @@ func resourceComputeTargetSslProxyUpdate(d *schema.ResourceData, meta interface{ if err != nil { return err } + + d.SetPartial("backend_service") } if d.HasChange("ssl_certificates") { - descriptionProp, err := expandComputeTargetSslProxyDescription(d.Get("description"), d, config) - if err != nil { - return err - } - nameProp, err := expandComputeTargetSslProxyName(d.Get("name"), d, config) - if err != nil { - return err - } - proxyHeaderProp, err := expandComputeTargetSslProxyProxyHeader(d.Get("proxy_header"), d, config) - if err != nil { - return err - } - serviceProp, err := expandComputeTargetSslProxyBackendService(d.Get("backend_service"), d, config) - if err != nil { - return err - } sslCertificatesProp, err := expandComputeTargetSslProxySslCertificates(d.Get("ssl_certificates"), d, config) if err != nil { return err } obj := map[string]interface{}{ - "description": descriptionProp, - "name": nameProp, - "proxyHeader": proxyHeaderProp, - "service": serviceProp, "sslCertificates": sslCertificatesProp, } url, err = replaceVars(d, config, "https://www.googleapis.com/compute/v1/projects/{{project}}/global/targetSslProxies/{{name}}/setSslCertificates") @@ -362,8 +327,12 @@ func resourceComputeTargetSslProxyUpdate(d *schema.ResourceData, meta interface{ if err != nil { return err } + + d.SetPartial("ssl_certificates") } + d.Partial(false) + return resourceComputeTargetSslProxyRead(d, meta) } diff --git a/google/resource_compute_target_tcp_proxy.go b/google/resource_compute_target_tcp_proxy.go index 1b147050..f425e58f 100644 --- a/google/resource_compute_target_tcp_proxy.go +++ b/google/resource_compute_target_tcp_proxy.go @@ -1,62 +1,84 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file in +// .github/CONTRIBUTING.md. +// +// ---------------------------------------------------------------------------- + package google import ( "fmt" "log" "strconv" + "time" "github.com/hashicorp/terraform/helper/schema" - "google.golang.org/api/compute/v1" + "github.com/hashicorp/terraform/helper/validation" + compute "google.golang.org/api/compute/v1" ) func resourceComputeTargetTcpProxy() *schema.Resource { return &schema.Resource{ Create: resourceComputeTargetTcpProxyCreate, Read: resourceComputeTargetTcpProxyRead, - Delete: resourceComputeTargetTcpProxyDelete, Update: resourceComputeTargetTcpProxyUpdate, + Delete: resourceComputeTargetTcpProxyDelete, Importer: &schema.ResourceImporter{ - State: schema.ImportStatePassthrough, + State: resourceComputeTargetTcpProxyImport, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(240 * time.Second), + Update: schema.DefaultTimeout(240 * time.Second), + Delete: schema.DefaultTimeout(240 * time.Second), }, Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ + "backend_service": { + Type: schema.TypeString, + Required: true, + DiffSuppressFunc: compareSelfLinkOrResourceName, + }, + "name": { Type: schema.TypeString, Required: true, ForceNew: true, }, - - "backend_service": &schema.Schema{ - Type: schema.TypeString, - Required: true, - }, - - "proxy_header": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Default: "NONE", - }, - - "description": &schema.Schema{ + "description": { Type: schema.TypeString, Optional: true, ForceNew: true, }, - - "proxy_id": &schema.Schema{ + "proxy_header": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{"NONE", "PROXY_V1", ""}, false), + Default: "NONE", + }, + "creation_timestamp": { Type: schema.TypeString, Computed: true, }, - - "project": &schema.Schema{ + "proxy_id": { + Type: schema.TypeInt, + Computed: true, + }, + "project": { Type: schema.TypeString, Optional: true, Computed: true, ForceNew: true, }, - - "self_link": &schema.Schema{ + "self_link": { Type: schema.TypeString, Computed: true, }, @@ -72,61 +94,64 @@ func resourceComputeTargetTcpProxyCreate(d *schema.ResourceData, meta interface{ return err } - proxy := &compute.TargetTcpProxy{ - Name: d.Get("name").(string), - Service: d.Get("backend_service").(string), - ProxyHeader: d.Get("proxy_header").(string), - Description: d.Get("description").(string), + descriptionProp, err := expandComputeTargetTcpProxyDescription(d.Get("description"), d, config) + if err != nil { + return err + } + nameProp, err := expandComputeTargetTcpProxyName(d.Get("name"), d, config) + if err != nil { + return err + } + proxyHeaderProp, err := expandComputeTargetTcpProxyProxyHeader(d.Get("proxy_header"), d, config) + if err != nil { + return err + } + serviceProp, err := expandComputeTargetTcpProxyBackendService(d.Get("backend_service"), d, config) + if err != nil { + return err } - log.Printf("[DEBUG] TargetTcpProxy insert request: %#v", proxy) - op, err := config.clientCompute.TargetTcpProxies.Insert( - project, proxy).Do() + obj := map[string]interface{}{ + "description": descriptionProp, + "name": nameProp, + "proxyHeader": proxyHeaderProp, + "service": serviceProp, + } + + url, err := replaceVars(d, config, "https://www.googleapis.com/compute/v1/projects/{{project}}/global/targetTcpProxies") + if err != nil { + return err + } + + log.Printf("[DEBUG] Creating new TargetTcpProxy: %#v", obj) + res, err := Post(config, url, obj) if err != nil { return fmt.Errorf("Error creating TargetTcpProxy: %s", err) } - err = computeOperationWait(config.clientCompute, op, project, "Creating Target Tcp Proxy") + // Store the ID now + id, err := replaceVars(d, config, "{{name}}") + if err != nil { + return fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + op := &compute.Operation{} + err = Convert(res, op) if err != nil { return err } - d.SetId(proxy.Name) + waitErr := computeOperationWaitTime( + config.clientCompute, op, project, "Creating TargetTcpProxy", + int(d.Timeout(schema.TimeoutCreate).Minutes())) - return resourceComputeTargetTcpProxyRead(d, meta) -} - -func resourceComputeTargetTcpProxyUpdate(d *schema.ResourceData, meta interface{}) error { - config := meta.(*Config) - - project, err := getProject(d, config) - if err != nil { - return err + if waitErr != nil { + // The resource didn't actually create + d.SetId("") + return fmt.Errorf("Error waiting to create TargetTcpProxy: %s", waitErr) } - d.Partial(true) - - if d.HasChange("proxy_header") { - proxy_header := d.Get("proxy_header").(string) - proxy_header_payload := &compute.TargetTcpProxiesSetProxyHeaderRequest{ - ProxyHeader: proxy_header, - } - op, err := config.clientCompute.TargetTcpProxies.SetProxyHeader( - project, d.Id(), proxy_header_payload).Do() - if err != nil { - return fmt.Errorf("Error updating target: %s", err) - } - - err = computeOperationWait(config.clientCompute, op, project, "Updating Target Tcp Proxy") - if err != nil { - return err - } - - d.SetPartial("proxy_header") - } - - d.Partial(false) - return resourceComputeTargetTcpProxyRead(d, meta) } @@ -138,23 +163,129 @@ func resourceComputeTargetTcpProxyRead(d *schema.ResourceData, meta interface{}) return err } - proxy, err := config.clientCompute.TargetTcpProxies.Get( - project, d.Id()).Do() + url, err := replaceVars(d, config, "https://www.googleapis.com/compute/v1/projects/{{project}}/global/targetTcpProxies/{{name}}") if err != nil { - return handleNotFoundError(err, d, fmt.Sprintf("Target TCP Proxy %q", d.Get("name").(string))) + return err } - d.Set("name", proxy.Name) - d.Set("backend_service", proxy.Service) - d.Set("proxy_header", proxy.ProxyHeader) - d.Set("description", proxy.Description) - d.Set("project", project) - d.Set("self_link", proxy.SelfLink) - d.Set("proxy_id", strconv.FormatUint(proxy.Id, 10)) + res, err := Get(config, url) + if err != nil { + return handleNotFoundError(err, d, fmt.Sprintf("ComputeTargetTcpProxy %q", d.Id())) + } + if err := d.Set("creation_timestamp", flattenComputeTargetTcpProxyCreationTimestamp(res["creationTimestamp"])); err != nil { + return fmt.Errorf("Error reading TargetTcpProxy: %s", err) + } + if err := d.Set("description", flattenComputeTargetTcpProxyDescription(res["description"])); err != nil { + return fmt.Errorf("Error reading TargetTcpProxy: %s", err) + } + if err := d.Set("proxy_id", flattenComputeTargetTcpProxyProxyId(res["id"])); err != nil { + return fmt.Errorf("Error reading TargetTcpProxy: %s", err) + } + if err := d.Set("name", flattenComputeTargetTcpProxyName(res["name"])); err != nil { + return fmt.Errorf("Error reading TargetTcpProxy: %s", err) + } + if err := d.Set("proxy_header", flattenComputeTargetTcpProxyProxyHeader(res["proxyHeader"])); err != nil { + return fmt.Errorf("Error reading TargetTcpProxy: %s", err) + } + if err := d.Set("backend_service", flattenComputeTargetTcpProxyBackendService(res["service"])); err != nil { + return fmt.Errorf("Error reading TargetTcpProxy: %s", err) + } + if err := d.Set("self_link", res["selfLink"]); err != nil { + return fmt.Errorf("Error reading TargetTcpProxy: %s", err) + } + if err := d.Set("project", project); err != nil { + return fmt.Errorf("Error reading TargetTcpProxy: %s", err) + } return nil } +func resourceComputeTargetTcpProxyUpdate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + project, err := getProject(d, config) + if err != nil { + return err + } + + var url string + var res map[string]interface{} + op := &compute.Operation{} + + d.Partial(true) + + if d.HasChange("proxy_header") { + proxyHeaderProp, err := expandComputeTargetTcpProxyProxyHeader(d.Get("proxy_header"), d, config) + if err != nil { + return err + } + + obj := map[string]interface{}{ + "proxyHeader": proxyHeaderProp, + } + url, err = replaceVars(d, config, "https://www.googleapis.com/compute/v1/projects/{{project}}/global/targetTcpProxies/{{name}}/setProxyHeader") + if err != nil { + return err + } + res, err = sendRequest(config, "POST", url, obj) + if err != nil { + return fmt.Errorf("Error updating TargetTcpProxy %q: %s", d.Id(), err) + } + + err = Convert(res, op) + if err != nil { + return err + } + + err = computeOperationWaitTime( + config.clientCompute, op, project, "Updating TargetTcpProxy", + int(d.Timeout(schema.TimeoutUpdate).Minutes())) + + if err != nil { + return err + } + + d.SetPartial("proxy_header") + } + if d.HasChange("backend_service") { + serviceProp, err := expandComputeTargetTcpProxyBackendService(d.Get("backend_service"), d, config) + if err != nil { + return err + } + + obj := map[string]interface{}{ + "service": serviceProp, + } + url, err = replaceVars(d, config, "https://www.googleapis.com/compute/v1/projects/{{project}}/global/targetTcpProxies/{{name}}/setBackendService") + if err != nil { + return err + } + res, err = sendRequest(config, "POST", url, obj) + if err != nil { + return fmt.Errorf("Error updating TargetTcpProxy %q: %s", d.Id(), err) + } + + err = Convert(res, op) + if err != nil { + return err + } + + err = computeOperationWaitTime( + config.clientCompute, op, project, "Updating TargetTcpProxy", + int(d.Timeout(schema.TimeoutUpdate).Minutes())) + + if err != nil { + return err + } + + d.SetPartial("backend_service") + } + + d.Partial(false) + + return resourceComputeTargetTcpProxyRead(d, meta) +} + func resourceComputeTargetTcpProxyDelete(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) @@ -163,19 +294,94 @@ func resourceComputeTargetTcpProxyDelete(d *schema.ResourceData, meta interface{ return err } - // Delete the TargetTcpProxy - log.Printf("[DEBUG] TargetTcpProxy delete request") - op, err := config.clientCompute.TargetTcpProxies.Delete( - project, d.Id()).Do() - if err != nil { - return fmt.Errorf("Error deleting TargetTcpProxy: %s", err) - } - - err = computeOperationWait(config.clientCompute, op, project, "Deleting Target Tcp Proxy") + url, err := replaceVars(d, config, "https://www.googleapis.com/compute/v1/projects/{{project}}/global/targetTcpProxies/{{name}}") + if err != nil { + return err + } + + log.Printf("[DEBUG] Deleting TargetTcpProxy %q", d.Id()) + res, err := Delete(config, url) + if err != nil { + return fmt.Errorf("Error deleting TargetTcpProxy %q: %s", d.Id(), err) + } + + op := &compute.Operation{} + err = Convert(res, op) + if err != nil { + return err + } + + err = computeOperationWaitTime( + config.clientCompute, op, project, "Deleting TargetTcpProxy", + int(d.Timeout(schema.TimeoutDelete).Minutes())) + if err != nil { return err } - d.SetId("") return nil } + +func resourceComputeTargetTcpProxyImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + config := meta.(*Config) + parseImportId([]string{"projects/(?P[^/]+)/global/targetTcpProxies/(?P[^/]+)", "(?P[^/]+)/(?P[^/]+)", "(?P[^/]+)"}, d, config) + + // Replace import id for the resource id + id, err := replaceVars(d, config, "{{name}}") + if err != nil { + return nil, fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + return []*schema.ResourceData{d}, nil +} + +func flattenComputeTargetTcpProxyCreationTimestamp(v interface{}) interface{} { + return v +} + +func flattenComputeTargetTcpProxyDescription(v interface{}) interface{} { + return v +} + +func flattenComputeTargetTcpProxyProxyId(v interface{}) interface{} { + // Handles the string fixed64 format + if strVal, ok := v.(string); ok { + if intVal, err := strconv.Atoi(strVal); err == nil { + return intVal + } // let terraform core handle it if we can't convert the string to an int. + } + return v +} + +func flattenComputeTargetTcpProxyName(v interface{}) interface{} { + return v +} + +func flattenComputeTargetTcpProxyProxyHeader(v interface{}) interface{} { + return v +} + +func flattenComputeTargetTcpProxyBackendService(v interface{}) interface{} { + return v +} + +func expandComputeTargetTcpProxyDescription(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeTargetTcpProxyName(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeTargetTcpProxyProxyHeader(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeTargetTcpProxyBackendService(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + f, err := parseGlobalFieldValue("backendServices", v.(string), "project", d, config, true) + if err != nil { + return nil, fmt.Errorf("Invalid value for backend_service: %s", err) + } + return f.RelativeLink(), nil +} diff --git a/google/resource_compute_vpn_gateway.go b/google/resource_compute_vpn_gateway.go index e9b2e59d..d5ecfe02 100644 --- a/google/resource_compute_vpn_gateway.go +++ b/google/resource_compute_vpn_gateway.go @@ -1,56 +1,79 @@ +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file in +// .github/CONTRIBUTING.md. +// +// ---------------------------------------------------------------------------- + package google import ( "fmt" + "log" + "time" "github.com/hashicorp/terraform/helper/schema" - - "google.golang.org/api/compute/v1" + compute "google.golang.org/api/compute/v1" ) func resourceComputeVpnGateway() *schema.Resource { return &schema.Resource{ - // Unfortunately, the VPNGatewayService does not support update - // operations. This is why everything is marked forcenew Create: resourceComputeVpnGatewayCreate, Read: resourceComputeVpnGatewayRead, Delete: resourceComputeVpnGatewayDelete, + Importer: &schema.ResourceImporter{ + State: resourceComputeVpnGatewayImport, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(240 * time.Second), + Delete: schema.DefaultTimeout(240 * time.Second), + }, + Schema: map[string]*schema.Schema{ - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Required: true, ForceNew: true, }, - - "network": &schema.Schema{ + "network": { Type: schema.TypeString, Required: true, ForceNew: true, DiffSuppressFunc: compareSelfLinkOrResourceName, }, - - "description": &schema.Schema{ + "description": { Type: schema.TypeString, Optional: true, ForceNew: true, }, - - "project": &schema.Schema{ + "region": { + Type: schema.TypeString, + Computed: true, + Optional: true, + ForceNew: true, + DiffSuppressFunc: compareSelfLinkOrResourceName, + StateFunc: NameFromSelfLinkStateFunc, + }, + "creation_timestamp": { + Type: schema.TypeString, + Computed: true, + }, + "project": { Type: schema.TypeString, Optional: true, Computed: true, ForceNew: true, }, - - "region": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Computed: true, - ForceNew: true, - }, - - "self_link": &schema.Schema{ + "self_link": { Type: schema.TypeString, Computed: true, }, @@ -60,42 +83,68 @@ func resourceComputeVpnGateway() *schema.Resource { func resourceComputeVpnGatewayCreate(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - network, err := ParseNetworkFieldValue(d.Get("network").(string), d, config) - if err != nil { - return err - } - - region, err := getRegion(d, config) - if err != nil { - return err - } project, err := getProject(d, config) if err != nil { return err } - name := d.Get("name").(string) - - vpnGatewaysService := compute.NewTargetVpnGatewaysService(config.clientCompute) - - vpnGateway := &compute.TargetVpnGateway{ - Name: name, - Network: network.RelativeLink(), - } - - if v, ok := d.GetOk("description"); ok { - vpnGateway.Description = v.(string) - } - - op, err := vpnGatewaysService.Insert(project, region, vpnGateway).Do() + descriptionProp, err := expandComputeVpnGatewayDescription(d.Get("description"), d, config) if err != nil { - return fmt.Errorf("Error Inserting VPN Gateway %s into network %s: %s", name, network.Name, err) + return err + } + nameProp, err := expandComputeVpnGatewayName(d.Get("name"), d, config) + if err != nil { + return err + } + networkProp, err := expandComputeVpnGatewayNetwork(d.Get("network"), d, config) + if err != nil { + return err + } + regionProp, err := expandComputeVpnGatewayRegion(d.Get("region"), d, config) + if err != nil { + return err } - err = computeOperationWait(config.clientCompute, op, project, "Inserting VPN Gateway") + obj := map[string]interface{}{ + "description": descriptionProp, + "name": nameProp, + "network": networkProp, + "region": regionProp, + } + + url, err := replaceVars(d, config, "https://www.googleapis.com/compute/v1/projects/{{project}}/regions/{{region}}/targetVpnGateways") if err != nil { - return fmt.Errorf("Error Waiting to Insert VPN Gateway %s into network %s: %s", name, network.Name, err) + return err + } + + log.Printf("[DEBUG] Creating new VpnGateway: %#v", obj) + res, err := Post(config, url, obj) + if err != nil { + return fmt.Errorf("Error creating VpnGateway: %s", err) + } + + // Store the ID now + id, err := replaceVars(d, config, "{{name}}") + if err != nil { + return fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + op := &compute.Operation{} + err = Convert(res, op) + if err != nil { + return err + } + + waitErr := computeOperationWaitTime( + config.clientCompute, op, project, "Creating VpnGateway", + int(d.Timeout(schema.TimeoutCreate).Minutes())) + + if waitErr != nil { + // The resource didn't actually create + d.SetId("") + return fmt.Errorf("Error waiting to create VpnGateway: %s", waitErr) } return resourceComputeVpnGatewayRead(d, meta) @@ -104,32 +153,41 @@ func resourceComputeVpnGatewayCreate(d *schema.ResourceData, meta interface{}) e func resourceComputeVpnGatewayRead(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - region, err := getRegion(d, config) - if err != nil { - return err - } - project, err := getProject(d, config) if err != nil { return err } - name := d.Get("name").(string) - - vpnGatewaysService := compute.NewTargetVpnGatewaysService(config.clientCompute) - vpnGateway, err := vpnGatewaysService.Get(project, region, name).Do() - + url, err := replaceVars(d, config, "https://www.googleapis.com/compute/v1/projects/{{project}}/regions/{{region}}/targetVpnGateways/{{name}}") if err != nil { - return handleNotFoundError(err, d, fmt.Sprintf("VPN Gateway %q", d.Get("name").(string))) + return err } - d.Set("name", vpnGateway.Name) - d.Set("description", vpnGateway.Description) - d.Set("network", vpnGateway.Network) - d.Set("project", project) - d.Set("region", region) - d.Set("self_link", vpnGateway.SelfLink) - d.SetId(name) + res, err := Get(config, url) + if err != nil { + return handleNotFoundError(err, d, fmt.Sprintf("ComputeVpnGateway %q", d.Id())) + } + if err := d.Set("creation_timestamp", flattenComputeVpnGatewayCreationTimestamp(res["creationTimestamp"])); err != nil { + return fmt.Errorf("Error reading VpnGateway: %s", err) + } + if err := d.Set("description", flattenComputeVpnGatewayDescription(res["description"])); err != nil { + return fmt.Errorf("Error reading VpnGateway: %s", err) + } + if err := d.Set("name", flattenComputeVpnGatewayName(res["name"])); err != nil { + return fmt.Errorf("Error reading VpnGateway: %s", err) + } + if err := d.Set("network", flattenComputeVpnGatewayNetwork(res["network"])); err != nil { + return fmt.Errorf("Error reading VpnGateway: %s", err) + } + if err := d.Set("region", flattenComputeVpnGatewayRegion(res["region"])); err != nil { + return fmt.Errorf("Error reading VpnGateway: %s", err) + } + if err := d.Set("self_link", res["selfLink"]); err != nil { + return fmt.Errorf("Error reading VpnGateway: %s", err) + } + if err := d.Set("project", project); err != nil { + return fmt.Errorf("Error reading VpnGateway: %s", err) + } return nil } @@ -137,29 +195,93 @@ func resourceComputeVpnGatewayRead(d *schema.ResourceData, meta interface{}) err func resourceComputeVpnGatewayDelete(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - region, err := getRegion(d, config) - if err != nil { - return err - } - project, err := getProject(d, config) if err != nil { return err } - name := d.Get("name").(string) - - vpnGatewaysService := compute.NewTargetVpnGatewaysService(config.clientCompute) - - op, err := vpnGatewaysService.Delete(project, region, name).Do() + url, err := replaceVars(d, config, "https://www.googleapis.com/compute/v1/projects/{{project}}/regions/{{region}}/targetVpnGateways/{{name}}") if err != nil { - return fmt.Errorf("Error Reading VPN Gateway %s: %s", name, err) + return err } - err = computeOperationWait(config.clientCompute, op, project, "Deleting VPN Gateway") + log.Printf("[DEBUG] Deleting VpnGateway %q", d.Id()) + res, err := Delete(config, url) if err != nil { - return fmt.Errorf("Error Waiting to Delete VPN Gateway %s: %s", name, err) + return fmt.Errorf("Error deleting VpnGateway %q: %s", d.Id(), err) + } + + op := &compute.Operation{} + err = Convert(res, op) + if err != nil { + return err + } + + err = computeOperationWaitTime( + config.clientCompute, op, project, "Deleting VpnGateway", + int(d.Timeout(schema.TimeoutDelete).Minutes())) + + if err != nil { + return err } return nil } + +func resourceComputeVpnGatewayImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + config := meta.(*Config) + parseImportId([]string{"projects/(?P[^/]+)/regions/(?P[^/]+)/targetVpnGateways/(?P[^/]+)", "(?P[^/]+)/(?P[^/]+)/(?P[^/]+)", "(?P[^/]+)"}, d, config) + + // Replace import id for the resource id + id, err := replaceVars(d, config, "{{name}}") + if err != nil { + return nil, fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + return []*schema.ResourceData{d}, nil +} + +func flattenComputeVpnGatewayCreationTimestamp(v interface{}) interface{} { + return v +} + +func flattenComputeVpnGatewayDescription(v interface{}) interface{} { + return v +} + +func flattenComputeVpnGatewayName(v interface{}) interface{} { + return v +} + +func flattenComputeVpnGatewayNetwork(v interface{}) interface{} { + return v +} + +func flattenComputeVpnGatewayRegion(v interface{}) interface{} { + return v +} + +func expandComputeVpnGatewayDescription(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeVpnGatewayName(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeVpnGatewayNetwork(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + f, err := parseGlobalFieldValue("networks", v.(string), "project", d, config, true) + if err != nil { + return nil, fmt.Errorf("Invalid value for network: %s", err) + } + return f.RelativeLink(), nil +} + +func expandComputeVpnGatewayRegion(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + f, err := parseGlobalFieldValue("regions", v.(string), "project", d, config, true) + if err != nil { + return nil, fmt.Errorf("Invalid value for region: %s", err) + } + return f.RelativeLink(), nil +} diff --git a/google/resource_container_cluster.go b/google/resource_container_cluster.go index 17d7d0bf..87cd734c 100644 --- a/google/resource_container_cluster.go +++ b/google/resource_container_cluster.go @@ -282,6 +282,24 @@ func resourceContainerCluster() *schema.Resource { ForceNew: true, }, + "client_certificate_config": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + DiffSuppressFunc: masterAuthClientCertCfgSuppress, + ForceNew: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "issue_client_certificate": { + Type: schema.TypeBool, + Required: true, + ForceNew: true, + DiffSuppressFunc: masterAuthClientCertCfgSuppress, + }, + }, + }, + }, + "client_certificate": { Type: schema.TypeString, Computed: true, @@ -490,6 +508,15 @@ func resourceContainerClusterCreate(d *schema.ResourceData, meta interface{}) er Password: masterAuth["password"].(string), Username: masterAuth["username"].(string), } + if certConfigV, ok := masterAuth["client_certificate_config"]; ok { + certConfigs := certConfigV.([]interface{}) + if len(certConfigs) > 0 { + certConfig := certConfigs[0].(map[string]interface{}) + cluster.MasterAuth.ClientCertificateConfig = &containerBeta.ClientCertificateConfig{ + IssueClientCertificate: certConfig["issue_client_certificate"].(bool), + } + } + } } if v, ok := d.GetOk("master_authorized_networks_config"); ok { @@ -747,6 +774,11 @@ func resourceContainerClusterRead(d *schema.ResourceData, meta interface{}) erro "cluster_ca_certificate": cluster.MasterAuth.ClusterCaCertificate, }, } + if len(cluster.MasterAuth.ClientCertificate) == 0 { + masterAuth[0]["client_certificate_config"] = []map[string]interface{}{ + {"issue_client_certificate": false}, + } + } d.Set("master_auth", masterAuth) if cluster.MasterAuthorizedNetworksConfig != nil { @@ -1629,3 +1661,27 @@ func extractNodePoolInformationFromCluster(d *schema.ResourceData, config *Confi cluster: d.Get("name").(string), }, nil } + +// We want to suppress diffs for empty or default client certificate configs, i.e: +// [{ "issue_client_certificate": true}] --> [] +// [] -> [{ "issue_client_certificate": true}] +func masterAuthClientCertCfgSuppress(k, old, new string, r *schema.ResourceData) bool { + var clientConfig map[string]interface{} + if v, ok := r.GetOk("master_auth"); ok { + masterAuths := v.([]interface{}) + masterAuth := masterAuths[0].(map[string]interface{}) + cfgs := masterAuth["client_certificate_config"].([]interface{}) + if len(cfgs) > 0 { + clientConfig = cfgs[0].(map[string]interface{}) + } + } + + if strings.HasSuffix(k, "client_certificate_config.#") && old == "0" && new == "1" { + // nil --> { "issue_client_certificate": true } + if issueCert, ok := clientConfig["issue_client_certificate"]; ok { + return issueCert.(bool) + } + } + + return strings.HasSuffix(k, ".issue_client_certificate") && old == "" && new == "true" +} diff --git a/google/resource_container_cluster_test.go b/google/resource_container_cluster_test.go index ac6a2ce4..33e95a26 100644 --- a/google/resource_container_cluster_test.go +++ b/google/resource_container_cluster_test.go @@ -104,7 +104,7 @@ func TestAccContainerCluster_withAddons(t *testing.T) { }) } -func TestAccContainerCluster_withMasterAuth(t *testing.T) { +func TestAccContainerCluster_withMasterAuthConfig(t *testing.T) { t.Parallel() resource.Test(t, resource.TestCase{ @@ -115,7 +115,7 @@ func TestAccContainerCluster_withMasterAuth(t *testing.T) { { Config: testAccContainerCluster_withMasterAuth(), }, - resource.TestStep{ + { ResourceName: "google_container_cluster.with_master_auth", ImportStateIdPrefix: "us-central1-a/", ImportState: true, @@ -125,6 +125,30 @@ func TestAccContainerCluster_withMasterAuth(t *testing.T) { }) } +func TestAccContainerCluster_withMasterAuthConfig_NoCert(t *testing.T) { + t.Parallel() + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckContainerClusterDestroy, + Steps: []resource.TestStep{ + { + Config: testAccContainerCluster_withMasterAuthNoCert(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("google_container_cluster.with_master_auth_no_cert", "master_auth.0.client_certificate", ""), + ), + }, + { + ResourceName: "google_container_cluster.with_master_auth_no_cert", + ImportStateIdPrefix: "us-central1-a/", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func TestAccContainerCluster_withNetworkPolicyEnabled(t *testing.T) { t.Parallel() @@ -1300,6 +1324,40 @@ resource "google_container_cluster" "with_master_auth" { }`, acctest.RandString(10)) } +func testAccContainerCluster_updateMasterAuthNoCert() string { + return fmt.Sprintf(` +resource "google_container_cluster" "with_master_auth" { + name = "cluster-test-%s" + zone = "us-central1-a" + initial_node_count = 3 + + master_auth { + username = "mr.yoda" + password = "adoy.rm.123456789" + client_certificate_config { + issue_client_certificate = false + } + } +}`, acctest.RandString(10)) +} + +func testAccContainerCluster_withMasterAuthNoCert() string { + return fmt.Sprintf(` +resource "google_container_cluster" "with_master_auth_no_cert" { + name = "cluster-test-%s" + zone = "us-central1-a" + initial_node_count = 3 + + master_auth { + username = "mr.yoda" + password = "adoy.rm.123456789" + client_certificate_config { + issue_client_certificate = false + } + } +}`, acctest.RandString(10)) +} + func testAccContainerCluster_withNetworkPolicyEnabled(clusterName string) string { return fmt.Sprintf(` resource "google_container_cluster" "with_network_policy_enabled" { diff --git a/google/resource_dataproc_cluster_test.go b/google/resource_dataproc_cluster_test.go index 98b468ef..8eb32e89 100644 --- a/google/resource_dataproc_cluster_test.go +++ b/google/resource_dataproc_cluster_test.go @@ -16,10 +16,6 @@ import ( "google.golang.org/api/googleapi" ) -const emptyTFDefinition = ` -# empty def -` - func TestExtractInitTimeout(t *testing.T) { t.Parallel() diff --git a/google/resource_google_project_organization_policy_test.go b/google/resource_google_project_organization_policy_test.go index f5a68f6a..84fcd52e 100644 --- a/google/resource_google_project_organization_policy_test.go +++ b/google/resource_google_project_organization_policy_test.go @@ -169,6 +169,10 @@ func testAccCheckGoogleProjectOrganizationListPolicyAll(n, policyType string) re return err } + if policy.ListPolicy == nil { + return nil + } + if len(policy.ListPolicy.AllowedValues) > 0 || len(policy.ListPolicy.DeniedValues) > 0 { return fmt.Errorf("The `values` field shouldn't be set") } diff --git a/google/resource_sql_user_test.go b/google/resource_sql_user_test.go index 6be64dfa..59211cb6 100644 --- a/google/resource_sql_user_test.go +++ b/google/resource_sql_user_test.go @@ -91,6 +91,10 @@ func testAccCheckGoogleSqlUserExists(n string) resource.TestCheckFunc { users, err := config.clientSqlAdmin.Users.List(config.Project, instance).Do() + if err != nil { + return err + } + for _, user := range users.Items { if user.Name == name && user.Host == host { return nil diff --git a/google/self_link_helpers.go b/google/self_link_helpers.go index c18273e9..893ed053 100644 --- a/google/self_link_helpers.go +++ b/google/self_link_helpers.go @@ -70,6 +70,10 @@ func GetResourceNameFromSelfLink(link string) string { return parts[len(parts)-1] } +func NameFromSelfLinkStateFunc(v interface{}) string { + return GetResourceNameFromSelfLink(v.(string)) +} + func StoreResourceName(resourceLink interface{}) string { return GetResourceNameFromSelfLink(resourceLink.(string)) } diff --git a/google/transport_test.go b/google/transport_test.go index 727e7bc2..6a4b5d9f 100644 --- a/google/transport_test.go +++ b/google/transport_test.go @@ -55,6 +55,15 @@ func TestReplaceVars(t *testing.T) { }, Expected: "projects/project1/regions/region1/subnetworks/subnetwork1", }, + "regional schema self-link region": { + Template: "projects/{{project}}/regions/{{region}}/subnetworks/{{name}}", + SchemaValues: map[string]interface{}{ + "project": "project1", + "region": "https://www.googleapis.com/compute/v1/projects/project1/regions/region1", + "name": "subnetwork1", + }, + Expected: "projects/project1/regions/region1/subnetworks/subnetwork1", + }, "zonal schema values": { Template: "projects/{{project}}/zones/{{zone}}/instances/{{name}}", SchemaValues: map[string]interface{}{ @@ -64,6 +73,15 @@ func TestReplaceVars(t *testing.T) { }, Expected: "projects/project1/zones/zone1/instances/instance1", }, + "zonal schema self-link zone": { + Template: "projects/{{project}}/zones/{{zone}}/instances/{{name}}", + SchemaValues: map[string]interface{}{ + "project": "project1", + "zone": "https://www.googleapis.com/compute/v1/projects/project1/zones/zone1", + "name": "instance1", + }, + Expected: "projects/project1/zones/zone1/instances/instance1", + }, } for tn, tc := range cases { diff --git a/google/utils.go b/google/utils.go index 64d43795..2f82d1a3 100644 --- a/google/utils.go +++ b/google/utils.go @@ -118,18 +118,6 @@ func getZonalBetaResourceFromRegion(getResource func(string) (interface{}, error return nil, nil } -func getNetworkNameFromSelfLink(network string) (string, error) { - if !strings.HasPrefix(network, "https://www.googleapis.com/compute/") { - return network, nil - } - // extract the network name from SelfLink URL - networkName := network[strings.LastIndex(network, "/")+1:] - if networkName == "" { - return "", fmt.Errorf("network url not valid") - } - return networkName, nil -} - func getRouterLockName(region string, router string) string { return fmt.Sprintf("router/%s/%s", region, router) } @@ -298,6 +286,20 @@ func mergeSchemas(a, b map[string]*schema.Schema) map[string]*schema.Schema { return merged } +func mergeResourceMaps(a, b map[string]*schema.Resource) map[string]*schema.Resource { + merged := make(map[string]*schema.Resource) + + for k, v := range a { + merged[k] = v + } + + for k, v := range b { + merged[k] = v + } + + return merged +} + func retry(retryFunc func() error) error { return retryTime(retryFunc, 1) } diff --git a/google/validation.go b/google/validation.go index c03fffe7..0c0c039c 100644 --- a/google/validation.go +++ b/google/validation.go @@ -20,6 +20,10 @@ const ( RFC1035NameTemplate = "[a-z](?:[-a-z0-9]{%d,%d}[a-z0-9])" CloudIoTIdRegex = "^[a-zA-Z][-a-zA-Z0-9._+~%]{2,254}$" + + // Format of default Compute service accounts created by Google + // ${PROJECT_ID}-compute@developer.gserviceaccount.com where PROJECT_ID is an int64 (max 20 digits) + ComputeServiceAccountNameRegex = "[0-9]{1,20}-compute@developer.gserviceaccount.com" ) var ( @@ -29,8 +33,20 @@ var ( // 4 and 28 since the first and last character are excluded. ServiceAccountNameRegex = fmt.Sprintf(RFC1035NameTemplate, 4, 28) - ProjectNameInDNSFormRegex = "[-a-z0-9\\.]{1,63}" - ServiceAccountLinkRegex = "projects/" + ProjectRegex + "/serviceAccounts/" + ServiceAccountNameRegex + "@" + ProjectNameInDNSFormRegex + "\\.iam\\.gserviceaccount\\.com$" + ServiceAccountLinkRegexPrefix = "projects/" + ProjectRegex + "/serviceAccounts/" + PossibleServiceAccountNames = []string{ + AppEngineServiceAccountNameRegex, + ComputeServiceAccountNameRegex, + CreatedServiceAccountNameRegex, + } + ServiceAccountLinkRegex = ServiceAccountLinkRegexPrefix + "(" + strings.Join(PossibleServiceAccountNames, "|") + ")" + + // Format of service accounts created through the API + CreatedServiceAccountNameRegex = fmt.Sprintf(RFC1035NameTemplate, 4, 28) + "@" + ProjectNameInDNSFormRegex + "\\.iam\\.gserviceaccount\\.com$" + ProjectNameInDNSFormRegex = "[-a-z0-9\\.]{1,63}" + + // Format of default App Engine service accounts created by Google + AppEngineServiceAccountNameRegex = ProjectRegex + "@appspot.gserviceaccount.com" ) var rfc1918Networks = []string{ diff --git a/google/validation_test.go b/google/validation_test.go index e4109194..bbb65906 100644 --- a/google/validation_test.go +++ b/google/validation_test.go @@ -117,6 +117,8 @@ func TestValidateServiceAccountLink(t *testing.T) { {TestName: "valid with dash", Value: "projects/my-project/serviceAccounts/svcacct@my-project.iam.gserviceaccount.com"}, {TestName: "valid with colon", Value: "projects/my:project/serviceAccounts/svcacct@project.my.iam.gserviceaccount.com"}, {TestName: "valid with dot and colon", Value: "projects/my.thing:project/serviceAccounts/svcacct@project.my.thing.iam.gserviceaccount.com"}, + {TestName: "valid with compute default service account", Value: "projects/my-project/serviceAccounts/123456-compute@developer.gserviceaccount.com"}, + {TestName: "valid with app engine default service account", Value: "projects/my-project/serviceAccounts/my-project@appspot.gserviceaccount.com"}, // Errors {TestName: "multiple colons", Value: "projects/my:project:thing/serviceAccounts/svcacct@thing.project.my.iam.gserviceaccount.com", ExpectError: true}, diff --git a/website/docs/r/compute_backend_bucket.html.markdown b/website/docs/r/compute_backend_bucket.html.markdown index 2594ebce..1f24b27c 100644 --- a/website/docs/r/compute_backend_bucket.html.markdown +++ b/website/docs/r/compute_backend_bucket.html.markdown @@ -1,26 +1,23 @@ - - --- +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +# +# ---------------------------------------------------------------------------- +# +# This file is automatically generated by Magic Modules and manual +# changes will be clobbered when the file is regenerated. +# +# Please read more about how to change this file in +# .github/CONTRIBUTING.md. +# +# ---------------------------------------------------------------------------- layout: "google" page_title: "Google: google_compute_backend_bucket" sidebar_current: "docs-google-compute-backend-bucket" description: |- Backend buckets allow you to use Google Cloud Storage buckets with HTTP(S) -load balancing. + load balancing. --- # google\_compute\_backend\_bucket diff --git a/website/docs/r/compute_global_address.html.markdown b/website/docs/r/compute_global_address.html.markdown index 6a327cdb..b64d0415 100644 --- a/website/docs/r/compute_global_address.html.markdown +++ b/website/docs/r/compute_global_address.html.markdown @@ -1,17 +1,34 @@ --- +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +# +# ---------------------------------------------------------------------------- +# +# This file is automatically generated by Magic Modules and manual +# changes will be clobbered when the file is regenerated. +# +# Please read more about how to change this file in +# .github/CONTRIBUTING.md. +# +# ---------------------------------------------------------------------------- layout: "google" page_title: "Google: google_compute_global_address" sidebar_current: "docs-google-compute-global-address" description: |- - Creates a static global IP address resource for a Google Compute Engine project. + Represents a Global Address resource. --- # google\_compute\_global\_address -Creates a static IP address resource global to a Google Compute Engine project. For more information see -[the official documentation](https://cloud.google.com/compute/docs/instances-and-network) and -[API](https://cloud.google.com/compute/docs/reference/latest/globalAddresses). +Represents a Global Address resource. Global addresses are used for +HTTP(S) load balancing. +To get more information about GlobalAddress, see: + +* [API documentation](https://cloud.google.com/compute/docs/reference/latest/globalAddresses) +* How-to Guides + * [Reserving a Static External IP Address](https://cloud.google.com/compute/docs/ip-addresses/reserve-static-external-ip-address) ## Example Usage @@ -25,29 +42,56 @@ resource "google_compute_global_address" "default" { The following arguments are supported: -* `name` - (Required) A unique name for the resource, required by GCE. - Changing this forces a new resource to be created. +* `name` - + (Required) + Name of the resource. Provided by the client when the resource is +created. The name must be 1-63 characters long, and comply with +RFC1035. Specifically, the name must be 1-63 characters long and +match the regular expression `[a-z]([-a-z0-9]*[a-z0-9])?` which means +the first character must be a lowercase letter, and all following +characters must be a dash, lowercase letter, or digit, except the last +character, which cannot be a dash. + - - - -* `project` - (Optional) The ID of the project in which the resource belongs. If it -is not provided, the provider project is used. +* `description` - + (Optional) + An optional description of this resource. +Provide this property when you create the resource. +* `ip_version` - + (Optional) + The IP Version that will be used by this address. Valid options are +IPV4 or IPV6. The default value is IPV4. +* `project` (Optional) The ID of the project in which the resource belongs. + If it is not provided, the provider project is used. -* `ip_version` - (Optional) The IP Version that will be used by this address. One of `"IPV4"` or `"IPV6"`. ## Attributes Reference -In addition to the arguments listed above, the following computed attributes are -exported: - -* `address` - The assigned address. +In addition to the arguments listed above, the following computed attributes are exported: +* `address` - + The static external IP address represented by this resource. +* `creation_timestamp` - + Creation timestamp in RFC3339 text format. * `self_link` - The URI of the created resource. + +## Timeouts + +This resource provides the following +[Timeouts](/docs/configuration/resources.html#timeouts) configuration options: + +- `create` - Default is 4 minutes. +- `delete` - Default is 4 minutes. + ## Import -Global addresses can be imported using the `name`, e.g. +GlobalAddress can be imported using any of these accepted formats: ``` -$ terraform import google_compute_global_address.default global-appserver-ip +$ terraform import google_compute_global_address.default projects/{{project}}/global/addresses/{{name}} +$ terraform import google_compute_global_address.default {{project}}/{{name}} +$ terraform import google_compute_global_address.default {{name}} ``` diff --git a/website/docs/r/compute_http_health_check.html.markdown b/website/docs/r/compute_http_health_check.html.markdown index 0dbeb35e..f11d8628 100644 --- a/website/docs/r/compute_http_health_check.html.markdown +++ b/website/docs/r/compute_http_health_check.html.markdown @@ -1,20 +1,17 @@ - - --- +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +# +# ---------------------------------------------------------------------------- +# +# This file is automatically generated by Magic Modules and manual +# changes will be clobbered when the file is regenerated. +# +# Please read more about how to change this file in +# .github/CONTRIBUTING.md. +# +# ---------------------------------------------------------------------------- layout: "google" page_title: "Google: google_compute_http_health_check" sidebar_current: "docs-google-compute-http-health-check" diff --git a/website/docs/r/compute_https_health_check.html.markdown b/website/docs/r/compute_https_health_check.html.markdown index b3f95c21..ff0db6d2 100644 --- a/website/docs/r/compute_https_health_check.html.markdown +++ b/website/docs/r/compute_https_health_check.html.markdown @@ -1,20 +1,17 @@ - - --- +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +# +# ---------------------------------------------------------------------------- +# +# This file is automatically generated by Magic Modules and manual +# changes will be clobbered when the file is regenerated. +# +# Please read more about how to change this file in +# .github/CONTRIBUTING.md. +# +# ---------------------------------------------------------------------------- layout: "google" page_title: "Google: google_compute_https_health_check" sidebar_current: "docs-google-compute-https-health-check" diff --git a/website/docs/r/compute_target_http_proxy.html.markdown b/website/docs/r/compute_target_http_proxy.html.markdown index edad94d0..cd57a039 100644 --- a/website/docs/r/compute_target_http_proxy.html.markdown +++ b/website/docs/r/compute_target_http_proxy.html.markdown @@ -1,18 +1,35 @@ --- +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +# +# ---------------------------------------------------------------------------- +# +# This file is automatically generated by Magic Modules and manual +# changes will be clobbered when the file is regenerated. +# +# Please read more about how to change this file in +# .github/CONTRIBUTING.md. +# +# ---------------------------------------------------------------------------- layout: "google" page_title: "Google: google_compute_target_http_proxy" sidebar_current: "docs-google-compute-target-http-proxy" description: |- - Creates a Target HTTP Proxy resource in GCE. + Represents a TargetHttpProxy resource, which is used by one or more global + forwarding rule to route incoming HTTP requests to a URL map. --- # google\_compute\_target\_http\_proxy -Creates a target HTTP proxy resource in GCE. For more information see -[the official -documentation](https://cloud.google.com/compute/docs/load-balancing/http/target-proxies) and -[API](https://cloud.google.com/compute/docs/reference/latest/targetHttpProxies). +Represents a TargetHttpProxy resource, which is used by one or more global +forwarding rule to route incoming HTTP requests to a URL map. +To get more information about TargetHttpProxy, see: + +* [API documentation](https://cloud.google.com/compute/docs/reference/latest/targetHttpProxies) +* How-to Guides + * [Official Documentation](https://cloud.google.com/compute/docs/load-balancing/http/target-proxies) ## Example Usage @@ -66,34 +83,55 @@ resource "google_compute_http_health_check" "default" { The following arguments are supported: -* `name` - (Required) A unique name for the resource, required by GCE. Changing - this forces a new resource to be created. +* `name` - + (Required) + Name of the resource. Provided by the client when the resource is +created. The name must be 1-63 characters long, and comply with +RFC1035. Specifically, the name must be 1-63 characters long and match +the regular expression `[a-z]([-a-z0-9]*[a-z0-9])?` which means the +first character must be a lowercase letter, and all following +characters must be a dash, lowercase letter, or digit, except the last +character, which cannot be a dash. +* `url_map` - + (Required) + A reference to UrlMap resource -* `url_map` - (Required) The URL of a URL Map resource that defines the mapping - from the URL to the BackendService. - -* `project` - (Optional) The ID of the project in which the resource belongs. If it - is not provided, the provider project is used. - - - -* `description` - (Optional) A description of this resource. Changing this - forces a new resource to be created. +* `description` - + (Optional) + An optional description of this resource. +* `project` (Optional) The ID of the project in which the resource belongs. + If it is not provided, the provider project is used. ## Attributes Reference -In addition to the arguments listed above, the following computed attributes are -exported: - -* `proxy_id` - A unique ID assigned by GCE. +In addition to the arguments listed above, the following computed attributes are exported: +* `creation_timestamp` - + Creation timestamp in RFC3339 text format. +* `proxy_id` - + The unique identifier for the resource. * `self_link` - The URI of the created resource. + +## Timeouts + +This resource provides the following +[Timeouts](/docs/configuration/resources.html#timeouts) configuration options: + +- `create` - Default is 4 minutes. +- `update` - Default is 4 minutes. +- `delete` - Default is 4 minutes. + ## Import -Target HTTP Proxy can be imported using the `name`, e.g. +TargetHttpProxy can be imported using any of these accepted formats: ``` -$ terraform import compute_target_http_proxy.foobar foobar +$ terraform import google_compute_target_http_proxy.default projects/{{project}}/global/targetHttpProxies/{{name}} +$ terraform import google_compute_target_http_proxy.default {{project}}/{{name}} +$ terraform import google_compute_target_http_proxy.default {{name}} ``` diff --git a/website/docs/r/compute_target_https_proxy.html.markdown b/website/docs/r/compute_target_https_proxy.html.markdown index 4ec47c4b..a53cc865 100644 --- a/website/docs/r/compute_target_https_proxy.html.markdown +++ b/website/docs/r/compute_target_https_proxy.html.markdown @@ -1,18 +1,35 @@ --- +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +# +# ---------------------------------------------------------------------------- +# +# This file is automatically generated by Magic Modules and manual +# changes will be clobbered when the file is regenerated. +# +# Please read more about how to change this file in +# .github/CONTRIBUTING.md. +# +# ---------------------------------------------------------------------------- layout: "google" page_title: "Google: google_compute_target_https_proxy" sidebar_current: "docs-google-compute-target-https-proxy" description: |- - Creates a Target HTTPS Proxy resource in GCE. + Represents a TargetHttpsProxy resource, which is used by one or more + global forwarding rule to route incoming HTTPS requests to a URL map. --- # google\_compute\_target\_https\_proxy -Creates a target HTTPS proxy resource in GCE. For more information see -[the official -documentation](https://cloud.google.com/compute/docs/load-balancing/http/target-proxies) and -[API](https://cloud.google.com/compute/docs/reference/latest/targetHttpsProxies). +Represents a TargetHttpsProxy resource, which is used by one or more +global forwarding rule to route incoming HTTPS requests to a URL map. +To get more information about TargetHttpsProxy, see: + +* [API documentation](https://cloud.google.com/compute/docs/reference/latest/targetHttpsProxies) +* How-to Guides + * [Official Documentation](https://cloud.google.com/compute/docs/load-balancing/http/target-proxies) ## Example Usage @@ -74,36 +91,60 @@ resource "google_compute_http_health_check" "default" { The following arguments are supported: -* `name` - (Required) A unique name for the resource, required by GCE. Changing - this forces a new resource to be created. +* `name` - + (Required) + Name of the resource. Provided by the client when the resource is +created. The name must be 1-63 characters long, and comply with +RFC1035. Specifically, the name must be 1-63 characters long and match +the regular expression `[a-z]([-a-z0-9]*[a-z0-9])?` which means the +first character must be a lowercase letter, and all following +characters must be a dash, lowercase letter, or digit, except the last +character, which cannot be a dash. +* `ssl_certificates` - + (Required) + A list of SslCertificate resources that are used to authenticate +connections between users and the load balancer. Currently, exactly +one SSL certificate must be specified. +* `url_map` - + (Required) + A reference to UrlMap resource -* `ssl_certificates` - (Required) The URLs or names of the SSL Certificate resources - that authenticate connections between users and load balancing. - -* `url_map` - (Required) The URL of a URL Map resource that defines the mapping - from the URL to the BackendService. - - - -* `description` - (Optional) A description of this resource. Changing this - forces a new resource to be created. +* `description` - + (Optional) + An optional description of this resource. +* `project` (Optional) The ID of the project in which the resource belongs. + If it is not provided, the provider project is used. -* `project` - (Optional) The ID of the project in which the resource belongs. If it - is not provided, the provider project is used. ## Attributes Reference -In addition to the arguments listed above, the following computed attributes are -exported: - -* `proxy_id` - A unique ID assigned by GCE. +In addition to the arguments listed above, the following computed attributes are exported: +* `creation_timestamp` - + Creation timestamp in RFC3339 text format. +* `proxy_id` - + The unique identifier for the resource. * `self_link` - The URI of the created resource. + +## Timeouts + +This resource provides the following +[Timeouts](/docs/configuration/resources.html#timeouts) configuration options: + +- `create` - Default is 4 minutes. +- `update` - Default is 4 minutes. +- `delete` - Default is 4 minutes. + ## Import -Target HTTPS Proxy can be imported using the `name`, e.g. +TargetHttpsProxy can be imported using any of these accepted formats: ``` -$ terraform import compute_target_https_proxy.foobar foobar +$ terraform import google_compute_target_https_proxy.default projects/{{project}}/global/targetHttpsProxies/{{name}} +$ terraform import google_compute_target_https_proxy.default {{project}}/{{name}} +$ terraform import google_compute_target_https_proxy.default {{name}} ``` diff --git a/website/docs/r/compute_target_ssl_proxy.html.markdown b/website/docs/r/compute_target_ssl_proxy.html.markdown index c7ceb3f2..955f4645 100644 --- a/website/docs/r/compute_target_ssl_proxy.html.markdown +++ b/website/docs/r/compute_target_ssl_proxy.html.markdown @@ -1,27 +1,24 @@ - - --- +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +# +# ---------------------------------------------------------------------------- +# +# This file is automatically generated by Magic Modules and manual +# changes will be clobbered when the file is regenerated. +# +# Please read more about how to change this file in +# .github/CONTRIBUTING.md. +# +# ---------------------------------------------------------------------------- layout: "google" page_title: "Google: google_compute_target_ssl_proxy" sidebar_current: "docs-google-compute-target-ssl-proxy" description: |- Represents a TargetSslProxy resource, which is used by one or more -global forwarding rule to route incoming SSL requests to a backend -service. + global forwarding rule to route incoming SSL requests to a backend + service. --- # google\_compute\_target\_ssl\_proxy diff --git a/website/docs/r/compute_target_tcp_proxy.html.markdown b/website/docs/r/compute_target_tcp_proxy.html.markdown index 37da0b2e..7004e535 100644 --- a/website/docs/r/compute_target_tcp_proxy.html.markdown +++ b/website/docs/r/compute_target_tcp_proxy.html.markdown @@ -1,18 +1,37 @@ --- +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +# +# ---------------------------------------------------------------------------- +# +# This file is automatically generated by Magic Modules and manual +# changes will be clobbered when the file is regenerated. +# +# Please read more about how to change this file in +# .github/CONTRIBUTING.md. +# +# ---------------------------------------------------------------------------- layout: "google" page_title: "Google: google_compute_target_tcp_proxy" sidebar_current: "docs-google-compute-target-tcp-proxy" description: |- - Creates a Target TCP Proxy resource in GCE. + Represents a TargetTcpProxy resource, which is used by one or more + global forwarding rule to route incoming TCP requests to a Backend + service. --- # google\_compute\_target\_tcp\_proxy -Creates a target TCP proxy resource in GCE. For more information see -[the official -documentation](https://cloud.google.com/compute/docs/load-balancing/tcp-ssl/tcp-proxy) and -[API](https://cloud.google.com/compute/docs/reference/latest/targetTcpProxies). +Represents a TargetTcpProxy resource, which is used by one or more +global forwarding rule to route incoming TCP requests to a Backend +service. +To get more information about TargetTcpProxy, see: + +* [API documentation](https://cloud.google.com/compute/docs/reference/latest/targetTcpProxies) +* How-to Guides + * [Setting Up TCP proxy for Google Cloud Load Balancing](https://cloud.google.com/compute/docs/load-balancing/tcp-ssl/tcp-proxy) ## Example Usage @@ -46,35 +65,59 @@ resource "google_compute_health_check" "default" { The following arguments are supported: -* `name` - (Required) A unique name for the resource, required by GCE. Changing - this forces a new resource to be created. +* `name` - + (Required) + Name of the resource. Provided by the client when the resource is +created. The name must be 1-63 characters long, and comply with +RFC1035. Specifically, the name must be 1-63 characters long and match +the regular expression `[a-z]([-a-z0-9]*[a-z0-9])?` which means the +first character must be a lowercase letter, and all following +characters must be a dash, lowercase letter, or digit, except the last +character, which cannot be a dash. +* `backend_service` - + (Required) + A reference to BackendService resource -* `backend_service` - (Required) The URL of a Backend Service resource to receive the matched traffic. - - - -* `proxy_header` - (Optional) Type of proxy header to append before sending - data to the backend, either NONE or PROXY_V1 (default NONE). +* `description` - + (Optional) + An optional description of this resource. +* `proxy_header` - + (Optional) + Specifies the type of proxy header to append before sending data to +the backend, either NONE or PROXY_V1. The default is NONE. +* `project` (Optional) The ID of the project in which the resource belongs. + If it is not provided, the provider project is used. -* `description` - (Optional) A description of this resource. Changing this - forces a new resource to be created. - -* `project` - (Optional) The ID of the project in which the resource belongs. If it - is not provided, the provider project is used. ## Attributes Reference -In addition to the arguments listed above, the following computed attributes are -exported: - -* `proxy_id` - A unique ID assigned by GCE. +In addition to the arguments listed above, the following computed attributes are exported: +* `creation_timestamp` - + Creation timestamp in RFC3339 text format. +* `proxy_id` - + The unique identifier for the resource. * `self_link` - The URI of the created resource. + +## Timeouts + +This resource provides the following +[Timeouts](/docs/configuration/resources.html#timeouts) configuration options: + +- `create` - Default is 4 minutes. +- `update` - Default is 4 minutes. +- `delete` - Default is 4 minutes. + ## Import -TCP proxy can be imported using the `name`, e.g. +TargetTcpProxy can be imported using any of these accepted formats: ``` -$ terraform import google_compute_target_tcp_proxy.default test +$ terraform import google_compute_target_tcp_proxy.default projects/{{project}}/global/targetTcpProxies/{{name}} +$ terraform import google_compute_target_tcp_proxy.default {{project}}/{{name}} +$ terraform import google_compute_target_tcp_proxy.default {{name}} ``` diff --git a/website/docs/r/compute_vpn_gateway.html.markdown b/website/docs/r/compute_vpn_gateway.html.markdown index 18a6319f..8e6cc757 100644 --- a/website/docs/r/compute_vpn_gateway.html.markdown +++ b/website/docs/r/compute_vpn_gateway.html.markdown @@ -1,16 +1,32 @@ --- +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +# +# ---------------------------------------------------------------------------- +# +# This file is automatically generated by Magic Modules and manual +# changes will be clobbered when the file is regenerated. +# +# Please read more about how to change this file in +# .github/CONTRIBUTING.md. +# +# ---------------------------------------------------------------------------- layout: "google" page_title: "Google: google_compute_vpn_gateway" sidebar_current: "docs-google-compute-vpn-gateway" description: |- - Manages a VPN Gateway in the GCE network + Represents a VPN gateway running in GCP. --- # google\_compute\_vpn\_gateway -Manages a VPN Gateway in the GCE network. For more info, read the -[documentation](https://cloud.google.com/compute/docs/vpn). +Represents a VPN gateway running in GCP. This virtual device is managed +by Google, but used only by you. +To get more information about VpnGateway, see: + +* [API documentation](https://cloud.google.com/compute/docs/reference/rest/v1/targetVpnGateways) ## Example Usage @@ -86,27 +102,55 @@ resource "google_compute_route" "route1" { The following arguments are supported: -* `name` - (Required) A unique name for the resource, required by GCE. Changing - this forces a new resource to be created. +* `name` - + (Required) + Name of the resource. Provided by the client when the resource is +created. The name must be 1-63 characters long, and comply with +RFC1035. Specifically, the name must be 1-63 characters long and +match the regular expression `[a-z]([-a-z0-9]*[a-z0-9])?` which means +the first character must be a lowercase letter, and all following +characters must be a dash, lowercase letter, or digit, except the last +character, which cannot be a dash. +* `network` - + (Required) + A reference to Network resource -* `network` - (Required) The name or resource link to the network this VPN gateway - is accepting traffic for. Changing this forces a new resource to be created. - - - -* `description` - (Optional) A description of the resource. - Changing this forces a new resource to be created. +* `description` - + (Optional) + An optional description of this resource. +* `region` - + (Optional) + A reference to Region resource +* `project` (Optional) The ID of the project in which the resource belongs. + If it is not provided, the provider project is used. -* `project` - (Optional) The ID of the project in which the resource belongs. If it - is not provided, the provider project is used. - -* `region` - (Optional) The region this gateway should sit in. If not specified, - the project region will be used. Changing this forces a new resource to be - created. ## Attributes Reference -In addition to the arguments listed above, the following computed attributes are -exported: +In addition to the arguments listed above, the following computed attributes are exported: +* `creation_timestamp` - + Creation timestamp in RFC3339 text format. * `self_link` - The URI of the created resource. + + +## Timeouts + +This resource provides the following +[Timeouts](/docs/configuration/resources.html#timeouts) configuration options: + +- `create` - Default is 4 minutes. +- `delete` - Default is 4 minutes. + +## Import + +VpnGateway can be imported using any of these accepted formats: + +``` +$ terraform import google_compute_vpn_gateway.default projects/{{project}}/regions/{{region}}/targetVpnGateways/{{name}} +$ terraform import google_compute_vpn_gateway.default {{project}}/{{region}}/{{name}} +$ terraform import google_compute_vpn_gateway.default {{name}} +``` diff --git a/website/docs/r/dns_record_set.markdown b/website/docs/r/dns_record_set.markdown index c9bb617c..0916f62d 100644 --- a/website/docs/r/dns_record_set.markdown +++ b/website/docs/r/dns_record_set.markdown @@ -99,7 +99,7 @@ resource "google_dns_managed_zone" "prod" { ### Adding an SPF record -`\"` must be added around your `rrdatas` for a SPF record. Otherwise `rrdatas` string gets split on spaces. +Quotes (`""`) must be added around your `rrdatas` for a SPF record. Otherwise `rrdatas` string gets split on spaces. ```hcl resource "google_dns_record_set" "spf" {