From 98b3e2d8538796042e8ab0f5c37c1f2bf7815f55 Mon Sep 17 00:00:00 2001 From: Modular Magician Date: Thu, 7 Sep 2023 14:21:19 +0000 Subject: [PATCH] Add Apigee target server resource support (#8800) * Implement apigee target server resource * fix : yaml format * fix : add missing resource fields in test * test : include more than one element in list * docs : update descriptions and hcl example * fix : add default value for protocol field * test : add test step for omitting protocol field * fix : replace default_value with default_from_api * test : split clientAuthEnabled to seperate test * Add comment explaining why acc test is skipped due to incompatibility with VCR --------- Co-authored-by: Sarah French <15078782+SarahFrench@users.noreply.github.com> Signed-off-by: Modular Magician --- .changelog/8800.txt | 3 + google-beta/provider/provider.go | 5 +- .../apigee/resource_apigee_target_server.go | 746 ++++++++++++++++++ ...rce_apigee_target_server_generated_test.go | 174 ++++ .../resource_apigee_target_server_test.go | 467 +++++++++++ .../docs/r/apigee_target_server.html.markdown | 227 ++++++ 6 files changed, 1620 insertions(+), 2 deletions(-) create mode 100644 .changelog/8800.txt create mode 100644 google-beta/services/apigee/resource_apigee_target_server.go create mode 100644 google-beta/services/apigee/resource_apigee_target_server_generated_test.go create mode 100644 google-beta/services/apigee/resource_apigee_target_server_test.go create mode 100644 website/docs/r/apigee_target_server.html.markdown diff --git a/.changelog/8800.txt b/.changelog/8800.txt new file mode 100644 index 0000000000..78911a7c36 --- /dev/null +++ b/.changelog/8800.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +google_apigee_target_server +``` diff --git a/google-beta/provider/provider.go b/google-beta/provider/provider.go index 1968f126c1..d8d6792321 100644 --- a/google-beta/provider/provider.go +++ b/google-beta/provider/provider.go @@ -1094,9 +1094,9 @@ func DatasourceMapWithErrors() (map[string]*schema.Resource, error) { }) } -// Generated resources: 378 +// Generated resources: 379 // Generated IAM resources: 237 -// Total generated resources: 615 +// Total generated resources: 616 func ResourceMap() map[string]*schema.Resource { resourceMap, _ := ResourceMapWithErrors() return resourceMap @@ -1158,6 +1158,7 @@ func ResourceMapWithErrors() (map[string]*schema.Resource, error) { "google_apigee_nat_address": apigee.ResourceApigeeNatAddress(), "google_apigee_organization": apigee.ResourceApigeeOrganization(), "google_apigee_sync_authorization": apigee.ResourceApigeeSyncAuthorization(), + "google_apigee_target_server": apigee.ResourceApigeeTargetServer(), "google_app_engine_application_url_dispatch_rules": appengine.ResourceAppEngineApplicationUrlDispatchRules(), "google_app_engine_domain_mapping": appengine.ResourceAppEngineDomainMapping(), "google_app_engine_firewall_rule": appengine.ResourceAppEngineFirewallRule(), diff --git a/google-beta/services/apigee/resource_apigee_target_server.go b/google-beta/services/apigee/resource_apigee_target_server.go new file mode 100644 index 0000000000..6b04af2b46 --- /dev/null +++ b/google-beta/services/apigee/resource_apigee_target_server.go @@ -0,0 +1,746 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** Type: MMv1 *** +// +// ---------------------------------------------------------------------------- +// +// 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 apigee + +import ( + "fmt" + "log" + "reflect" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/hashicorp/terraform-provider-google-beta/google-beta/tpgresource" + transport_tpg "github.com/hashicorp/terraform-provider-google-beta/google-beta/transport" + "github.com/hashicorp/terraform-provider-google-beta/google-beta/verify" +) + +func ResourceApigeeTargetServer() *schema.Resource { + return &schema.Resource{ + Create: resourceApigeeTargetServerCreate, + Read: resourceApigeeTargetServerRead, + Update: resourceApigeeTargetServerUpdate, + Delete: resourceApigeeTargetServerDelete, + + Importer: &schema.ResourceImporter{ + State: resourceApigeeTargetServerImport, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(1 * time.Minute), + Update: schema.DefaultTimeout(1 * time.Minute), + Delete: schema.DefaultTimeout(1 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "env_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: `The Apigee environment group associated with the Apigee environment, +in the format 'organizations/{{org_name}}/environments/{{env_name}}'.`, + }, + "host": { + Type: schema.TypeString, + Required: true, + Description: `The host name this target connects to. Value must be a valid hostname as described by RFC-1123.`, + }, + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: `The resource id of this reference. Values must match the regular expression [\w\s-.]+.`, + }, + "port": { + Type: schema.TypeInt, + Required: true, + Description: `The port number this target connects to on the given host. Value must be between 1 and 65535, inclusive.`, + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: `A human-readable description of this TargetServer.`, + }, + "is_enabled": { + Type: schema.TypeBool, + Optional: true, + Description: `Enabling/disabling a TargetServer is useful when TargetServers are used in load balancing configurations, and one or more TargetServers need to taken out of rotation periodically. Defaults to true.`, + Default: true, + }, + "protocol": { + Type: schema.TypeString, + Computed: true, + Optional: true, + ForceNew: true, + ValidateFunc: verify.ValidateEnum([]string{"HTTP", "HTTP2", "GRPC_TARGET", "GRPC", "EXTERNAL_CALLOUT", ""}), + Description: `Immutable. The protocol used by this TargetServer. Possible values: ["HTTP", "HTTP2", "GRPC_TARGET", "GRPC", "EXTERNAL_CALLOUT"]`, + }, + "s_sl_info": { + Type: schema.TypeList, + Optional: true, + Description: `Specifies TLS configuration info for this TargetServer. The JSON name is sSLInfo for legacy/backwards compatibility reasons -- Edge originally supported SSL, and the name is still used for TLS configuration.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "enabled": { + Type: schema.TypeBool, + Required: true, + Description: `Enables TLS. If false, neither one-way nor two-way TLS will be enabled.`, + }, + "ciphers": { + Type: schema.TypeList, + Optional: true, + Description: `The SSL/TLS cipher suites to be used. For programmable proxies, it must be one of the cipher suite names listed in: http://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#ciphersuites. For configurable proxies, it must follow the configuration specified in: https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#Cipher-suite-configuration. This setting has no effect for configurable proxies when negotiating TLS 1.3.`, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "client_auth_enabled": { + Type: schema.TypeBool, + Optional: true, + Description: `Enables two-way TLS.`, + }, + "common_name": { + Type: schema.TypeList, + Optional: true, + Description: `The TLS Common Name of the certificate.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "value": { + Type: schema.TypeString, + Optional: true, + Description: `The TLS Common Name string of the certificate.`, + }, + "wildcard_match": { + Type: schema.TypeBool, + Optional: true, + Description: `Indicates whether the cert should be matched against as a wildcard cert.`, + }, + }, + }, + }, + "ignore_validation_errors": { + Type: schema.TypeBool, + Optional: true, + Description: `If true, Edge ignores TLS certificate errors. Valid when configuring TLS for target servers and target endpoints, and when configuring virtual hosts that use 2-way TLS. When used with a target endpoint/target server, if the backend system uses SNI and returns a cert with a subject Distinguished Name (DN) that does not match the hostname, there is no way to ignore the error and the connection fails.`, + }, + "key_alias": { + Type: schema.TypeString, + Optional: true, + Description: `Required if clientAuthEnabled is true. The resource ID for the alias containing the private key and cert.`, + }, + "key_store": { + Type: schema.TypeString, + Optional: true, + Description: `Required if clientAuthEnabled is true. The resource ID of the keystore.`, + }, + "protocols": { + Type: schema.TypeList, + Optional: true, + Description: `The TLS versioins to be used.`, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "trust_store": { + Type: schema.TypeString, + Optional: true, + Description: `The resource ID of the truststore.`, + }, + }, + }, + }, + }, + UseJSONNumber: true, + } +} + +func resourceApigeeTargetServerCreate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*transport_tpg.Config) + userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) + if err != nil { + return err + } + + obj := make(map[string]interface{}) + nameProp, err := expandApigeeTargetServerName(d.Get("name"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("name"); !tpgresource.IsEmptyValue(reflect.ValueOf(nameProp)) && (ok || !reflect.DeepEqual(v, nameProp)) { + obj["name"] = nameProp + } + descriptionProp, err := expandApigeeTargetServerDescription(d.Get("description"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("description"); !tpgresource.IsEmptyValue(reflect.ValueOf(descriptionProp)) && (ok || !reflect.DeepEqual(v, descriptionProp)) { + obj["description"] = descriptionProp + } + hostProp, err := expandApigeeTargetServerHost(d.Get("host"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("host"); !tpgresource.IsEmptyValue(reflect.ValueOf(hostProp)) && (ok || !reflect.DeepEqual(v, hostProp)) { + obj["host"] = hostProp + } + portProp, err := expandApigeeTargetServerPort(d.Get("port"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("port"); !tpgresource.IsEmptyValue(reflect.ValueOf(portProp)) && (ok || !reflect.DeepEqual(v, portProp)) { + obj["port"] = portProp + } + isEnabledProp, err := expandApigeeTargetServerIsEnabled(d.Get("is_enabled"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("is_enabled"); !tpgresource.IsEmptyValue(reflect.ValueOf(isEnabledProp)) && (ok || !reflect.DeepEqual(v, isEnabledProp)) { + obj["isEnabled"] = isEnabledProp + } + sSLInfoProp, err := expandApigeeTargetServerSSLInfo(d.Get("s_sl_info"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("s_sl_info"); !tpgresource.IsEmptyValue(reflect.ValueOf(sSLInfoProp)) && (ok || !reflect.DeepEqual(v, sSLInfoProp)) { + obj["sSLInfo"] = sSLInfoProp + } + protocolProp, err := expandApigeeTargetServerProtocol(d.Get("protocol"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("protocol"); !tpgresource.IsEmptyValue(reflect.ValueOf(protocolProp)) && (ok || !reflect.DeepEqual(v, protocolProp)) { + obj["protocol"] = protocolProp + } + + url, err := tpgresource.ReplaceVars(d, config, "{{ApigeeBasePath}}{{env_id}}/targetservers") + if err != nil { + return err + } + + log.Printf("[DEBUG] Creating new TargetServer: %#v", obj) + billingProject := "" + + // err == nil indicates that the billing_project value was found + if bp, err := tpgresource.GetBillingProject(d, config); err == nil { + billingProject = bp + } + + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "POST", + Project: billingProject, + RawURL: url, + UserAgent: userAgent, + Body: obj, + Timeout: d.Timeout(schema.TimeoutCreate), + }) + if err != nil { + return fmt.Errorf("Error creating TargetServer: %s", err) + } + + // Store the ID now + id, err := tpgresource.ReplaceVars(d, config, "{{env_id}}/targetservers/{{name}}") + if err != nil { + return fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + log.Printf("[DEBUG] Finished creating TargetServer %q: %#v", d.Id(), res) + + return resourceApigeeTargetServerRead(d, meta) +} + +func resourceApigeeTargetServerRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*transport_tpg.Config) + userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) + if err != nil { + return err + } + + url, err := tpgresource.ReplaceVars(d, config, "{{ApigeeBasePath}}{{env_id}}/targetservers/{{name}}") + if err != nil { + return err + } + + billingProject := "" + + // err == nil indicates that the billing_project value was found + if bp, err := tpgresource.GetBillingProject(d, config); err == nil { + billingProject = bp + } + + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "GET", + Project: billingProject, + RawURL: url, + UserAgent: userAgent, + }) + if err != nil { + return transport_tpg.HandleNotFoundError(err, d, fmt.Sprintf("ApigeeTargetServer %q", d.Id())) + } + + if err := d.Set("name", flattenApigeeTargetServerName(res["name"], d, config)); err != nil { + return fmt.Errorf("Error reading TargetServer: %s", err) + } + if err := d.Set("description", flattenApigeeTargetServerDescription(res["description"], d, config)); err != nil { + return fmt.Errorf("Error reading TargetServer: %s", err) + } + if err := d.Set("host", flattenApigeeTargetServerHost(res["host"], d, config)); err != nil { + return fmt.Errorf("Error reading TargetServer: %s", err) + } + if err := d.Set("port", flattenApigeeTargetServerPort(res["port"], d, config)); err != nil { + return fmt.Errorf("Error reading TargetServer: %s", err) + } + if err := d.Set("is_enabled", flattenApigeeTargetServerIsEnabled(res["isEnabled"], d, config)); err != nil { + return fmt.Errorf("Error reading TargetServer: %s", err) + } + if err := d.Set("s_sl_info", flattenApigeeTargetServerSSLInfo(res["sSLInfo"], d, config)); err != nil { + return fmt.Errorf("Error reading TargetServer: %s", err) + } + if err := d.Set("protocol", flattenApigeeTargetServerProtocol(res["protocol"], d, config)); err != nil { + return fmt.Errorf("Error reading TargetServer: %s", err) + } + + return nil +} + +func resourceApigeeTargetServerUpdate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*transport_tpg.Config) + userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) + if err != nil { + return err + } + + billingProject := "" + + obj := make(map[string]interface{}) + nameProp, err := expandApigeeTargetServerName(d.Get("name"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("name"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, nameProp)) { + obj["name"] = nameProp + } + descriptionProp, err := expandApigeeTargetServerDescription(d.Get("description"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("description"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, descriptionProp)) { + obj["description"] = descriptionProp + } + hostProp, err := expandApigeeTargetServerHost(d.Get("host"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("host"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, hostProp)) { + obj["host"] = hostProp + } + portProp, err := expandApigeeTargetServerPort(d.Get("port"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("port"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, portProp)) { + obj["port"] = portProp + } + isEnabledProp, err := expandApigeeTargetServerIsEnabled(d.Get("is_enabled"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("is_enabled"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, isEnabledProp)) { + obj["isEnabled"] = isEnabledProp + } + sSLInfoProp, err := expandApigeeTargetServerSSLInfo(d.Get("s_sl_info"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("s_sl_info"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, sSLInfoProp)) { + obj["sSLInfo"] = sSLInfoProp + } + protocolProp, err := expandApigeeTargetServerProtocol(d.Get("protocol"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("protocol"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, protocolProp)) { + obj["protocol"] = protocolProp + } + + url, err := tpgresource.ReplaceVars(d, config, "{{ApigeeBasePath}}{{env_id}}/targetservers/{{name}}") + if err != nil { + return err + } + + log.Printf("[DEBUG] Updating TargetServer %q: %#v", d.Id(), obj) + + // err == nil indicates that the billing_project value was found + if bp, err := tpgresource.GetBillingProject(d, config); err == nil { + billingProject = bp + } + + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "PUT", + Project: billingProject, + RawURL: url, + UserAgent: userAgent, + Body: obj, + Timeout: d.Timeout(schema.TimeoutUpdate), + }) + + if err != nil { + return fmt.Errorf("Error updating TargetServer %q: %s", d.Id(), err) + } else { + log.Printf("[DEBUG] Finished updating TargetServer %q: %#v", d.Id(), res) + } + + return resourceApigeeTargetServerRead(d, meta) +} + +func resourceApigeeTargetServerDelete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*transport_tpg.Config) + userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) + if err != nil { + return err + } + + billingProject := "" + + url, err := tpgresource.ReplaceVars(d, config, "{{ApigeeBasePath}}{{env_id}}/targetservers/{{name}}") + if err != nil { + return err + } + + var obj map[string]interface{} + log.Printf("[DEBUG] Deleting TargetServer %q", d.Id()) + + // err == nil indicates that the billing_project value was found + if bp, err := tpgresource.GetBillingProject(d, config); err == nil { + billingProject = bp + } + + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "DELETE", + Project: billingProject, + RawURL: url, + UserAgent: userAgent, + Body: obj, + Timeout: d.Timeout(schema.TimeoutDelete), + }) + if err != nil { + return transport_tpg.HandleNotFoundError(err, d, "TargetServer") + } + + log.Printf("[DEBUG] Finished deleting TargetServer %q: %#v", d.Id(), res) + return nil +} + +func resourceApigeeTargetServerImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + config := meta.(*transport_tpg.Config) + + // current import_formats cannot import fields with forward slashes in their value + if err := tpgresource.ParseImportId([]string{ + "(?P.+)/targetservers/(?P.+)", + "(?P.+)/(?P.+)", + }, d, config); err != nil { + return nil, err + } + + // Replace import id for the resource id + id, err := tpgresource.ReplaceVars(d, config, "{{env_id}}/targetservers/{{name}}") + if err != nil { + return nil, fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + return []*schema.ResourceData{d}, nil +} + +func flattenApigeeTargetServerName(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenApigeeTargetServerDescription(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenApigeeTargetServerHost(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenApigeeTargetServerPort(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + // Handles the string fixed64 format + if strVal, ok := v.(string); ok { + if intVal, err := tpgresource.StringToFixed64(strVal); err == nil { + return intVal + } + } + + // number values are represented as float64 + if floatVal, ok := v.(float64); ok { + intVal := int(floatVal) + return intVal + } + + return v // let terraform core handle it otherwise +} + +func flattenApigeeTargetServerIsEnabled(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenApigeeTargetServerSSLInfo(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["enabled"] = + flattenApigeeTargetServerSSLInfoEnabled(original["enabled"], d, config) + transformed["client_auth_enabled"] = + flattenApigeeTargetServerSSLInfoClientAuthEnabled(original["clientAuthEnabled"], d, config) + transformed["key_store"] = + flattenApigeeTargetServerSSLInfoKeyStore(original["keyStore"], d, config) + transformed["key_alias"] = + flattenApigeeTargetServerSSLInfoKeyAlias(original["keyAlias"], d, config) + transformed["trust_store"] = + flattenApigeeTargetServerSSLInfoTrustStore(original["trustStore"], d, config) + transformed["ignore_validation_errors"] = + flattenApigeeTargetServerSSLInfoIgnoreValidationErrors(original["ignoreValidationErrors"], d, config) + transformed["protocols"] = + flattenApigeeTargetServerSSLInfoProtocols(original["protocols"], d, config) + transformed["ciphers"] = + flattenApigeeTargetServerSSLInfoCiphers(original["ciphers"], d, config) + transformed["common_name"] = + flattenApigeeTargetServerSSLInfoCommonName(original["commonName"], d, config) + return []interface{}{transformed} +} +func flattenApigeeTargetServerSSLInfoEnabled(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenApigeeTargetServerSSLInfoClientAuthEnabled(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenApigeeTargetServerSSLInfoKeyStore(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenApigeeTargetServerSSLInfoKeyAlias(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenApigeeTargetServerSSLInfoTrustStore(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenApigeeTargetServerSSLInfoIgnoreValidationErrors(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenApigeeTargetServerSSLInfoProtocols(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenApigeeTargetServerSSLInfoCiphers(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenApigeeTargetServerSSLInfoCommonName(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["value"] = + flattenApigeeTargetServerSSLInfoCommonNameValue(original["value"], d, config) + transformed["wildcard_match"] = + flattenApigeeTargetServerSSLInfoCommonNameWildcardMatch(original["wildcardMatch"], d, config) + return []interface{}{transformed} +} +func flattenApigeeTargetServerSSLInfoCommonNameValue(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenApigeeTargetServerSSLInfoCommonNameWildcardMatch(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenApigeeTargetServerProtocol(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func expandApigeeTargetServerName(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandApigeeTargetServerDescription(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandApigeeTargetServerHost(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandApigeeTargetServerPort(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandApigeeTargetServerIsEnabled(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandApigeeTargetServerSSLInfo(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedEnabled, err := expandApigeeTargetServerSSLInfoEnabled(original["enabled"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedEnabled); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["enabled"] = transformedEnabled + } + + transformedClientAuthEnabled, err := expandApigeeTargetServerSSLInfoClientAuthEnabled(original["client_auth_enabled"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedClientAuthEnabled); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["clientAuthEnabled"] = transformedClientAuthEnabled + } + + transformedKeyStore, err := expandApigeeTargetServerSSLInfoKeyStore(original["key_store"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedKeyStore); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["keyStore"] = transformedKeyStore + } + + transformedKeyAlias, err := expandApigeeTargetServerSSLInfoKeyAlias(original["key_alias"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedKeyAlias); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["keyAlias"] = transformedKeyAlias + } + + transformedTrustStore, err := expandApigeeTargetServerSSLInfoTrustStore(original["trust_store"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedTrustStore); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["trustStore"] = transformedTrustStore + } + + transformedIgnoreValidationErrors, err := expandApigeeTargetServerSSLInfoIgnoreValidationErrors(original["ignore_validation_errors"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedIgnoreValidationErrors); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["ignoreValidationErrors"] = transformedIgnoreValidationErrors + } + + transformedProtocols, err := expandApigeeTargetServerSSLInfoProtocols(original["protocols"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedProtocols); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["protocols"] = transformedProtocols + } + + transformedCiphers, err := expandApigeeTargetServerSSLInfoCiphers(original["ciphers"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedCiphers); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["ciphers"] = transformedCiphers + } + + transformedCommonName, err := expandApigeeTargetServerSSLInfoCommonName(original["common_name"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedCommonName); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["commonName"] = transformedCommonName + } + + return transformed, nil +} + +func expandApigeeTargetServerSSLInfoEnabled(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandApigeeTargetServerSSLInfoClientAuthEnabled(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandApigeeTargetServerSSLInfoKeyStore(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandApigeeTargetServerSSLInfoKeyAlias(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandApigeeTargetServerSSLInfoTrustStore(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandApigeeTargetServerSSLInfoIgnoreValidationErrors(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandApigeeTargetServerSSLInfoProtocols(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandApigeeTargetServerSSLInfoCiphers(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandApigeeTargetServerSSLInfoCommonName(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedValue, err := expandApigeeTargetServerSSLInfoCommonNameValue(original["value"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedValue); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["value"] = transformedValue + } + + transformedWildcardMatch, err := expandApigeeTargetServerSSLInfoCommonNameWildcardMatch(original["wildcard_match"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedWildcardMatch); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["wildcardMatch"] = transformedWildcardMatch + } + + return transformed, nil +} + +func expandApigeeTargetServerSSLInfoCommonNameValue(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandApigeeTargetServerSSLInfoCommonNameWildcardMatch(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandApigeeTargetServerProtocol(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} diff --git a/google-beta/services/apigee/resource_apigee_target_server_generated_test.go b/google-beta/services/apigee/resource_apigee_target_server_generated_test.go new file mode 100644 index 0000000000..818c90c9c9 --- /dev/null +++ b/google-beta/services/apigee/resource_apigee_target_server_generated_test.go @@ -0,0 +1,174 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** Type: MMv1 *** +// +// ---------------------------------------------------------------------------- +// +// 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 apigee_test + +import ( + "fmt" + "strings" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + "github.com/hashicorp/terraform-provider-google-beta/google-beta/acctest" + "github.com/hashicorp/terraform-provider-google-beta/google-beta/envvar" + "github.com/hashicorp/terraform-provider-google-beta/google-beta/tpgresource" + transport_tpg "github.com/hashicorp/terraform-provider-google-beta/google-beta/transport" +) + +func TestAccApigeeTargetServer_apigeeTargetServerTestExample(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "org_id": envvar.GetTestOrgFromEnv(t), + "billing_account": envvar.GetTestBillingAccountFromEnv(t), + "random_suffix": acctest.RandString(t, 10), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckApigeeTargetServerDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccApigeeTargetServer_apigeeTargetServerTestExample(context), + }, + { + ResourceName: "google_apigee_target_server.apigee_target_server", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"env_id"}, + }, + }, + }) +} + +func testAccApigeeTargetServer_apigeeTargetServerTestExample(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_project" "project" { + project_id = "tf-test%{random_suffix}" + name = "tf-test%{random_suffix}" + org_id = "%{org_id}" + billing_account = "%{billing_account}" +} + +resource "google_project_service" "apigee" { + project = google_project.project.project_id + service = "apigee.googleapis.com" +} + +resource "google_project_service" "servicenetworking" { + project = google_project.project.project_id + service = "servicenetworking.googleapis.com" + depends_on = [google_project_service.apigee] +} + +resource "google_project_service" "compute" { + project = google_project.project.project_id + service = "compute.googleapis.com" + depends_on = [google_project_service.servicenetworking] +} + +resource "google_compute_network" "apigee_network" { + name = "apigee-network" + project = google_project.project.project_id + depends_on = [google_project_service.compute] +} + +resource "google_compute_global_address" "apigee_range" { + name = "apigee-range" + purpose = "VPC_PEERING" + address_type = "INTERNAL" + prefix_length = 16 + network = google_compute_network.apigee_network.id + project = google_project.project.project_id +} + +resource "google_service_networking_connection" "apigee_vpc_connection" { + network = google_compute_network.apigee_network.id + service = "servicenetworking.googleapis.com" + reserved_peering_ranges = [google_compute_global_address.apigee_range.name] + depends_on = [google_project_service.servicenetworking] +} + +resource "google_apigee_organization" "apigee_org" { + analytics_region = "us-central1" + project_id = google_project.project.project_id + authorized_network = google_compute_network.apigee_network.id + depends_on = [ + google_service_networking_connection.apigee_vpc_connection, + google_project_service.apigee, + ] +} + +resource "google_apigee_environment" "apigee_environment" { + org_id = google_apigee_organization.apigee_org.id + name = "tf-test%{random_suffix}" + description = "Apigee Environment" + display_name = "environment-1" +} + +resource "google_apigee_target_server" "apigee_target_server" { + name = "tf-test-target-server%{random_suffix}" + description = "Apigee Target Server" + protocol = "HTTP" + host = "abc.foo.com" + port = 8080 + env_id = google_apigee_environment.apigee_environment.id +} +`, context) +} + +func testAccCheckApigeeTargetServerDestroyProducer(t *testing.T) func(s *terraform.State) error { + return func(s *terraform.State) error { + for name, rs := range s.RootModule().Resources { + if rs.Type != "google_apigee_target_server" { + continue + } + if strings.HasPrefix(name, "data.") { + continue + } + + config := acctest.GoogleProviderConfig(t) + + url, err := tpgresource.ReplaceVarsForTest(config, rs, "{{ApigeeBasePath}}{{env_id}}/targetservers/{{name}}") + if err != nil { + return err + } + + billingProject := "" + + if config.BillingProject != "" { + billingProject = config.BillingProject + } + + _, err = transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "GET", + Project: billingProject, + RawURL: url, + UserAgent: config.UserAgent, + }) + if err == nil { + return fmt.Errorf("ApigeeTargetServer still exists at %s", url) + } + } + + return nil + } +} diff --git a/google-beta/services/apigee/resource_apigee_target_server_test.go b/google-beta/services/apigee/resource_apigee_target_server_test.go new file mode 100644 index 0000000000..3ad6dc25e8 --- /dev/null +++ b/google-beta/services/apigee/resource_apigee_target_server_test.go @@ -0,0 +1,467 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** Type: MMv1 *** +// +// ---------------------------------------------------------------------------- +// +// 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 apigee_test + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + "github.com/hashicorp/terraform-provider-google-beta/google-beta/acctest" + "github.com/hashicorp/terraform-provider-google-beta/google-beta/envvar" +) + +func TestAccApigeeTargetServer_apigeeTargetServerTest_update(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "org_id": envvar.GetTestOrgFromEnv(t), + "billing_account": envvar.GetTestBillingAccountFromEnv(t), + "random_suffix": acctest.RandString(t, 10), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckApigeeTargetServerDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccApigeeTargetServer_apigeeTargetServerTest_basic(context), + }, + { + ResourceName: "google_apigee_target_server.apigee_target_server", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"env_id"}, + }, + { + Config: testAccApigeeTargetServer_apigeeTargetServerTest_createWithoutProtocol(context), + }, + { + ResourceName: "google_apigee_target_server.apigee_target_server", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"env_id"}, + }, + }, + }) +} + +func testAccApigeeTargetServer_apigeeTargetServerTest_basic(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_project" "project" { + project_id = "tf-test%{random_suffix}" + name = "tf-test%{random_suffix}" + org_id = "%{org_id}" + billing_account = "%{billing_account}" +} + +resource "google_project_service" "apigee" { + project = google_project.project.project_id + service = "apigee.googleapis.com" +} + +resource "google_project_service" "servicenetworking" { + project = google_project.project.project_id + service = "servicenetworking.googleapis.com" + depends_on = [google_project_service.apigee] +} + +resource "google_project_service" "compute" { + project = google_project.project.project_id + service = "compute.googleapis.com" + depends_on = [google_project_service.servicenetworking] +} + +resource "google_compute_network" "apigee_network" { + name = "apigee-network" + project = google_project.project.project_id + depends_on = [google_project_service.compute] +} + +resource "google_compute_global_address" "apigee_range" { + name = "apigee-range" + purpose = "VPC_PEERING" + address_type = "INTERNAL" + prefix_length = 16 + network = google_compute_network.apigee_network.id + project = google_project.project.project_id +} + +resource "google_service_networking_connection" "apigee_vpc_connection" { + network = google_compute_network.apigee_network.id + service = "servicenetworking.googleapis.com" + reserved_peering_ranges = [google_compute_global_address.apigee_range.name] + depends_on = [google_project_service.servicenetworking] +} + +resource "google_apigee_organization" "apigee_org" { + analytics_region = "us-central1" + project_id = google_project.project.project_id + authorized_network = google_compute_network.apigee_network.id + depends_on = [ + google_service_networking_connection.apigee_vpc_connection, + google_project_service.apigee, + ] +} + +resource "google_apigee_environment" "apigee_environment" { + org_id = google_apigee_organization.apigee_org.id + name = "tf-test%{random_suffix}" + description = "Apigee Environment" + display_name = "environment-1" +} + +resource "google_apigee_target_server" "apigee_target_server" { + name = "tf-test-target-server%{random_suffix}" + description = "Apigee Target Server" + protocol = "HTTP" + host = "abc.foo.com" + port = 8080 + env_id = google_apigee_environment.apigee_environment.id +} +`, context) +} + +func testAccApigeeTargetServer_apigeeTargetServerTest_createWithoutProtocol(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_project" "project" { + project_id = "tf-test%{random_suffix}" + name = "tf-test%{random_suffix}" + org_id = "%{org_id}" + billing_account = "%{billing_account}" +} + +resource "google_project_service" "apigee" { + project = google_project.project.project_id + service = "apigee.googleapis.com" +} + +resource "google_project_service" "servicenetworking" { + project = google_project.project.project_id + service = "servicenetworking.googleapis.com" + depends_on = [google_project_service.apigee] +} + +resource "google_project_service" "compute" { + project = google_project.project.project_id + service = "compute.googleapis.com" + depends_on = [google_project_service.servicenetworking] +} + +resource "google_compute_network" "apigee_network" { + name = "apigee-network" + project = google_project.project.project_id + depends_on = [google_project_service.compute] +} + +resource "google_compute_global_address" "apigee_range" { + name = "apigee-range" + purpose = "VPC_PEERING" + address_type = "INTERNAL" + prefix_length = 16 + network = google_compute_network.apigee_network.id + project = google_project.project.project_id +} + +resource "google_service_networking_connection" "apigee_vpc_connection" { + network = google_compute_network.apigee_network.id + service = "servicenetworking.googleapis.com" + reserved_peering_ranges = [google_compute_global_address.apigee_range.name] + depends_on = [google_project_service.servicenetworking] +} + +resource "google_apigee_organization" "apigee_org" { + analytics_region = "us-central1" + project_id = google_project.project.project_id + authorized_network = google_compute_network.apigee_network.id + depends_on = [ + google_service_networking_connection.apigee_vpc_connection, + google_project_service.apigee, + ] +} + +resource "google_apigee_environment" "apigee_environment" { + org_id = google_apigee_organization.apigee_org.id + name = "tf-test%{random_suffix}" + description = "Apigee Environment" + display_name = "environment-1" +} + +resource "google_apigee_target_server" "apigee_target_server" { + name = "tf-test-target-server%{random_suffix}" + description = "Apigee Target Server" + host = "abc.foo.com" + port = 8080 + env_id = google_apigee_environment.apigee_environment.id +} +`, context) +} + +func TestAccApigeeTargetServer_apigeeTargetServerTest_clientAuthEnabled(t *testing.T) { + t.Parallel() + // Skipping VCR tests; google_apigee_keystores_aliases_key_cert_file resource uses multipart boundary which by default is random. Currently this is incompatible with VCR. + acctest.SkipIfVcr(t) + context := map[string]interface{}{ + "org_id": envvar.GetTestOrgFromEnv(t), + "billing_account": envvar.GetTestBillingAccountFromEnv(t), + "random_suffix": acctest.RandString(t, 10), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckApigeeTargetServerDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccApigeeTargetServer_apigeeTargetServerTest_full(context), + }, + { + ResourceName: "google_apigee_target_server.apigee_target_server", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"env_id"}, + }, + { + Config: testAccApigeeTargetServer_apigeeTargetServerTest_update(context), + }, + { + ResourceName: "google_apigee_target_server.apigee_target_server", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"env_id"}, + }, + }, + }) +} + +func testAccApigeeTargetServer_apigeeTargetServerTest_full(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_project" "project" { + project_id = "tf-test%{random_suffix}" + name = "tf-test%{random_suffix}" + org_id = "%{org_id}" + billing_account = "%{billing_account}" +} + +resource "google_project_service" "apigee" { + project = google_project.project.project_id + service = "apigee.googleapis.com" +} + +resource "google_project_service" "servicenetworking" { + project = google_project.project.project_id + service = "servicenetworking.googleapis.com" + depends_on = [google_project_service.apigee] +} + +resource "google_project_service" "compute" { + project = google_project.project.project_id + service = "compute.googleapis.com" + depends_on = [google_project_service.servicenetworking] +} + +resource "google_compute_network" "apigee_network" { + name = "apigee-network" + project = google_project.project.project_id + depends_on = [google_project_service.compute] +} + +resource "google_compute_global_address" "apigee_range" { + name = "apigee-range" + purpose = "VPC_PEERING" + address_type = "INTERNAL" + prefix_length = 16 + network = google_compute_network.apigee_network.id + project = google_project.project.project_id +} + +resource "google_service_networking_connection" "apigee_vpc_connection" { + network = google_compute_network.apigee_network.id + service = "servicenetworking.googleapis.com" + reserved_peering_ranges = [google_compute_global_address.apigee_range.name] + depends_on = [google_project_service.servicenetworking] +} + +resource "google_apigee_organization" "apigee_org" { + analytics_region = "us-central1" + project_id = google_project.project.project_id + authorized_network = google_compute_network.apigee_network.id + depends_on = [ + google_service_networking_connection.apigee_vpc_connection, + google_project_service.apigee, + ] +} + +resource "google_apigee_environment" "apigee_environment" { + org_id = google_apigee_organization.apigee_org.id + name = "tf-test%{random_suffix}" + description = "Apigee Environment" + display_name = "environment-1" +} + +resource "google_apigee_env_keystore" "apigee_environment_keystore" { + name = "tf-test-keystore%{random_suffix}" + env_id = google_apigee_environment.apigee_environment.id +} + +resource "google_apigee_keystores_aliases_key_cert_file" "apigee_test_alias" { + alias = "tf-test-alias%{random_suffix}" + org_id = google_apigee_organization.apigee_org.name + environment = google_apigee_environment.apigee_environment.name + cert = file("./test-fixtures/apigee_keystore_alias_test_cert.pem") + key = sensitive(file("./test-fixtures/apigee_keystore_alias_test_key.pem")) + password = sensitive("password") + keystore = google_apigee_env_keystore.apigee_environment_keystore.name +} + +resource "google_apigee_target_server" "apigee_target_server"{ + env_id = google_apigee_environment.apigee_environment.id + is_enabled = true + name = "tf-test-target-server%{random_suffix}" + host = "host.test.com" + port = 443 + protocol = "HTTP" + s_sl_info{ + enabled = true + ciphers = ["TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA38411"] + client_auth_enabled = true + ignore_validation_errors = true + key_alias = google_apigee_keystores_aliases_key_cert_file.apigee_test_alias.alias + key_store = google_apigee_env_keystore.apigee_environment_keystore.name + protocols = ["TLSv1.1"] + trust_store = google_apigee_env_keystore.apigee_environment_keystore.name + common_name{ + value = "testCn" + wildcard_match = true + } + } + depends_on = [ + google_apigee_env_keystore.apigee_environment_keystore, + google_apigee_keystores_aliases_key_cert_file.apigee_test_alias + ] + } +`, context) +} + +func testAccApigeeTargetServer_apigeeTargetServerTest_update(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_project" "project" { + project_id = "tf-test%{random_suffix}" + name = "tf-test%{random_suffix}" + org_id = "%{org_id}" + billing_account = "%{billing_account}" +} + +resource "google_project_service" "apigee" { + project = google_project.project.project_id + service = "apigee.googleapis.com" +} + +resource "google_project_service" "servicenetworking" { + project = google_project.project.project_id + service = "servicenetworking.googleapis.com" + depends_on = [google_project_service.apigee] +} + +resource "google_project_service" "compute" { + project = google_project.project.project_id + service = "compute.googleapis.com" + depends_on = [google_project_service.servicenetworking] +} + +resource "google_compute_network" "apigee_network" { + name = "apigee-network" + project = google_project.project.project_id + depends_on = [google_project_service.compute] +} + +resource "google_compute_global_address" "apigee_range" { + name = "apigee-range" + purpose = "VPC_PEERING" + address_type = "INTERNAL" + prefix_length = 16 + network = google_compute_network.apigee_network.id + project = google_project.project.project_id +} + +resource "google_service_networking_connection" "apigee_vpc_connection" { + network = google_compute_network.apigee_network.id + service = "servicenetworking.googleapis.com" + reserved_peering_ranges = [google_compute_global_address.apigee_range.name] + depends_on = [google_project_service.servicenetworking] +} + +resource "google_apigee_organization" "apigee_org" { + analytics_region = "us-central1" + project_id = google_project.project.project_id + authorized_network = google_compute_network.apigee_network.id + depends_on = [ + google_service_networking_connection.apigee_vpc_connection, + google_project_service.apigee, + ] +} + +resource "google_apigee_environment" "apigee_environment" { + org_id = google_apigee_organization.apigee_org.id + name = "tf-test%{random_suffix}" + description = "Apigee Environment" + display_name = "environment-1" +} + +resource "google_apigee_env_keystore" "apigee_environment_keystore2" { + name = "tf-test-keystore2%{random_suffix}" + env_id = google_apigee_environment.apigee_environment.id +} + +resource "google_apigee_keystores_aliases_key_cert_file" "apigee_test_alias2" { + alias = "tf-test-alias%{random_suffix}" + org_id = google_apigee_organization.apigee_org.name + environment = google_apigee_environment.apigee_environment.name + cert = file("./test-fixtures/apigee_keystore_alias_test_cert2.pem") + key = sensitive(file("./test-fixtures/apigee_keystore_alias_test_key.pem")) + password = sensitive("password") + keystore = google_apigee_env_keystore.apigee_environment_keystore2.name +} + +resource "google_apigee_target_server" "apigee_target_server"{ + env_id = google_apigee_environment.apigee_environment.id + is_enabled = true + name = "tf-test-target-server%{random_suffix}" + host = "host.test.com" + port = 8443 + protocol = "GRPC" + s_sl_info{ + enabled = true + ciphers = ["TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384"] + client_auth_enabled = true + ignore_validation_errors = true + key_alias = google_apigee_keystores_aliases_key_cert_file.apigee_test_alias2.alias + key_store = google_apigee_env_keystore.apigee_environment_keystore2.name + protocols = ["TLSv1.2", "TLSv1.1"] + trust_store = google_apigee_env_keystore.apigee_environment_keystore2.name + } + depends_on = [ + google_apigee_env_keystore.apigee_environment_keystore2, + google_apigee_keystores_aliases_key_cert_file.apigee_test_alias2 + ] +} +`, context) +} diff --git a/website/docs/r/apigee_target_server.html.markdown b/website/docs/r/apigee_target_server.html.markdown new file mode 100644 index 0000000000..a9abbb6bc8 --- /dev/null +++ b/website/docs/r/apigee_target_server.html.markdown @@ -0,0 +1,227 @@ +--- +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** Type: MMv1 *** +# +# ---------------------------------------------------------------------------- +# +# 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. +# +# ---------------------------------------------------------------------------- +subcategory: "Apigee" +description: |- + TargetServer configuration. +--- + +# google\_apigee\_target\_server + +TargetServer configuration. TargetServers are used to decouple a proxy TargetEndpoint HTTPTargetConnections from concrete URLs for backend services. + + +To get more information about TargetServer, see: + +* [API documentation](https://cloud.google.com/apigee/docs/reference/apis/apigee/rest/v1/organizations.environments.targetservers/create) +* How-to Guides + * [Load balancing across backend servers](https://cloud.google.com/apigee/docs/api-platform/deploy/load-balancing-across-backend-servers) + +## Example Usage - Apigee Target Server Test Basic + + +```hcl +resource "google_project" "project" { + project_id = "my-project" + name = "my-project" + org_id = "123456789" + billing_account = "000000-0000000-0000000-000000" +} + +resource "google_project_service" "apigee" { + project = google_project.project.project_id + service = "apigee.googleapis.com" +} + +resource "google_project_service" "servicenetworking" { + project = google_project.project.project_id + service = "servicenetworking.googleapis.com" + depends_on = [google_project_service.apigee] +} + +resource "google_project_service" "compute" { + project = google_project.project.project_id + service = "compute.googleapis.com" + depends_on = [google_project_service.servicenetworking] +} + +resource "google_compute_network" "apigee_network" { + name = "apigee-network" + project = google_project.project.project_id + depends_on = [google_project_service.compute] +} + +resource "google_compute_global_address" "apigee_range" { + name = "apigee-range" + purpose = "VPC_PEERING" + address_type = "INTERNAL" + prefix_length = 16 + network = google_compute_network.apigee_network.id + project = google_project.project.project_id +} + +resource "google_service_networking_connection" "apigee_vpc_connection" { + network = google_compute_network.apigee_network.id + service = "servicenetworking.googleapis.com" + reserved_peering_ranges = [google_compute_global_address.apigee_range.name] + depends_on = [google_project_service.servicenetworking] +} + +resource "google_apigee_organization" "apigee_org" { + analytics_region = "us-central1" + project_id = google_project.project.project_id + authorized_network = google_compute_network.apigee_network.id + depends_on = [ + google_service_networking_connection.apigee_vpc_connection, + google_project_service.apigee, + ] +} + +resource "google_apigee_environment" "apigee_environment" { + org_id = google_apigee_organization.apigee_org.id + name = "my-environment-name" + description = "Apigee Environment" + display_name = "environment-1" +} + +resource "google_apigee_target_server" "apigee_target_server" { + name = "my-target-server" + description = "Apigee Target Server" + protocol = "HTTP" + host = "abc.foo.com" + port = 8080 + env_id = google_apigee_environment.apigee_environment.id +} +``` + +## Argument Reference + +The following arguments are supported: + + +* `name` - + (Required) + The resource id of this reference. Values must match the regular expression [\w\s-.]+. + +* `host` - + (Required) + The host name this target connects to. Value must be a valid hostname as described by RFC-1123. + +* `port` - + (Required) + The port number this target connects to on the given host. Value must be between 1 and 65535, inclusive. + +* `env_id` - + (Required) + The Apigee environment group associated with the Apigee environment, + in the format `organizations/{{org_name}}/environments/{{env_name}}`. + + +- - - + + +* `description` - + (Optional) + A human-readable description of this TargetServer. + +* `is_enabled` - + (Optional) + Enabling/disabling a TargetServer is useful when TargetServers are used in load balancing configurations, and one or more TargetServers need to taken out of rotation periodically. Defaults to true. + +* `s_sl_info` - + (Optional) + Specifies TLS configuration info for this TargetServer. The JSON name is sSLInfo for legacy/backwards compatibility reasons -- Edge originally supported SSL, and the name is still used for TLS configuration. + Structure is [documented below](#nested_s_sl_info). + +* `protocol` - + (Optional) + Immutable. The protocol used by this TargetServer. + Possible values are: `HTTP`, `HTTP2`, `GRPC_TARGET`, `GRPC`, `EXTERNAL_CALLOUT`. + + +The `s_sl_info` block supports: + +* `enabled` - + (Required) + Enables TLS. If false, neither one-way nor two-way TLS will be enabled. + +* `client_auth_enabled` - + (Optional) + Enables two-way TLS. + +* `key_store` - + (Optional) + Required if clientAuthEnabled is true. The resource ID of the keystore. + +* `key_alias` - + (Optional) + Required if clientAuthEnabled is true. The resource ID for the alias containing the private key and cert. + +* `trust_store` - + (Optional) + The resource ID of the truststore. + +* `ignore_validation_errors` - + (Optional) + If true, Edge ignores TLS certificate errors. Valid when configuring TLS for target servers and target endpoints, and when configuring virtual hosts that use 2-way TLS. When used with a target endpoint/target server, if the backend system uses SNI and returns a cert with a subject Distinguished Name (DN) that does not match the hostname, there is no way to ignore the error and the connection fails. + +* `protocols` - + (Optional) + The TLS versioins to be used. + +* `ciphers` - + (Optional) + The SSL/TLS cipher suites to be used. For programmable proxies, it must be one of the cipher suite names listed in: http://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#ciphersuites. For configurable proxies, it must follow the configuration specified in: https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#Cipher-suite-configuration. This setting has no effect for configurable proxies when negotiating TLS 1.3. + +* `common_name` - + (Optional) + The TLS Common Name of the certificate. + Structure is [documented below](#nested_common_name). + + +The `common_name` block supports: + +* `value` - + (Optional) + The TLS Common Name string of the certificate. + +* `wildcard_match` - + (Optional) + Indicates whether the cert should be matched against as a wildcard cert. + +## Attributes Reference + +In addition to the arguments listed above, the following computed attributes are exported: + +* `id` - an identifier for the resource with format `{{env_id}}/targetservers/{{name}}` + + +## Timeouts + +This resource provides the following +[Timeouts](https://developer.hashicorp.com/terraform/plugin/sdkv2/resources/retries-and-customizable-timeouts) configuration options: + +- `create` - Default is 1 minutes. +- `update` - Default is 1 minutes. +- `delete` - Default is 1 minutes. + +## Import + + +TargetServer can be imported using any of these accepted formats: + +``` +$ terraform import google_apigee_target_server.default {{env_id}}/targetservers/{{name}} +$ terraform import google_apigee_target_server.default {{env_id}}/{{name}} +```