diff --git a/google/provider_compute_gen.go b/google/provider_compute_gen.go index eb2bec0d..50baf00e 100644 --- a/google/provider_compute_gen.go +++ b/google/provider_compute_gen.go @@ -21,6 +21,7 @@ var GeneratedComputeResourcesMap = map[string]*schema.Resource{ "google_compute_autoscaler": resourceComputeAutoscaler(), "google_compute_backend_bucket": resourceComputeBackendBucket(), "google_compute_disk": resourceComputeDisk(), + "google_compute_firewall": resourceComputeFirewall(), "google_compute_forwarding_rule": resourceComputeForwardingRule(), "google_compute_global_address": resourceComputeGlobalAddress(), "google_compute_http_health_check": resourceComputeHttpHealthCheck(), diff --git a/google/resource_compute_firewall.go b/google/resource_compute_firewall.go index 2700e72e..9a782f9b 100644 --- a/google/resource_compute_firewall.go +++ b/google/resource_compute_firewall.go @@ -1,181 +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. +// +// ---------------------------------------------------------------------------- + package google import ( "bytes" "fmt" + "log" + "reflect" "sort" + "strconv" + "time" "github.com/hashicorp/terraform/helper/hashcode" "github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/helper/validation" - - computeBeta "google.golang.org/api/compute/v0.beta" + compute "google.golang.org/api/compute/v1" ) -func resourceComputeFirewall() *schema.Resource { - return &schema.Resource{ - Create: resourceComputeFirewallCreate, - Read: resourceComputeFirewallRead, - Update: resourceComputeFirewallUpdate, - Delete: resourceComputeFirewallDelete, - Importer: &schema.ResourceImporter{ - State: schema.ImportStatePassthrough, - }, - SchemaVersion: 1, - MigrateState: resourceComputeFirewallMigrateState, - - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - }, - - "network": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - DiffSuppressFunc: compareSelfLinkOrResourceName, - }, - - "priority": { - Type: schema.TypeInt, - Optional: true, - ForceNew: true, - Default: 1000, - ValidateFunc: validation.IntBetween(0, 65535), - }, - - "allow": { - Type: schema.TypeSet, - Optional: true, - ConflictsWith: []string{"deny"}, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "protocol": { - Type: schema.TypeString, - Required: true, - }, - - "ports": { - Type: schema.TypeList, - Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, - }, - }, - }, - Set: resourceComputeFirewallRuleHash, - }, - - "deny": { - Type: schema.TypeSet, - Optional: true, - ConflictsWith: []string{"allow"}, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "protocol": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - }, - - "ports": { - Type: schema.TypeList, - Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, - ForceNew: true, - }, - }, - }, - Set: resourceComputeFirewallRuleHash, - - // Unlike allow, deny can't be updated upstream - ForceNew: true, - }, - - "description": { - Type: schema.TypeString, - Optional: true, - }, - - "direction": { - Type: schema.TypeString, - Optional: true, - Computed: true, - ValidateFunc: validation.StringInSlice([]string{"INGRESS", "EGRESS"}, false), - ForceNew: true, - }, - - "disabled": { - Type: schema.TypeBool, - Optional: true, - }, - - "project": { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - Computed: true, - }, - - "self_link": { - Type: schema.TypeString, - Computed: true, - }, - - "source_ranges": { - Type: schema.TypeSet, - Optional: true, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - }, - - "source_tags": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - }, - - "destination_ranges": { - Type: schema.TypeSet, - Optional: true, - Computed: true, - ConflictsWith: []string{"source_ranges", "source_tags"}, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - ForceNew: true, - }, - - "target_tags": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - }, - - "source_service_accounts": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, - ForceNew: true, - MaxItems: 1, - ConflictsWith: []string{"source_tags", "target_tags"}, - }, - - "target_service_accounts": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Schema{Type: schema.TypeString}, - ForceNew: true, - MaxItems: 1, - ConflictsWith: []string{"source_tags", "target_tags"}, - }, - }, - } -} - func resourceComputeFirewallRuleHash(v interface{}) int { var buf bytes.Buffer m := v.(map[string]interface{}) @@ -195,229 +48,790 @@ func resourceComputeFirewallRuleHash(v interface{}) int { return hashcode.String(buf.String()) } +func resourceComputeFirewall() *schema.Resource { + return &schema.Resource{ + Create: resourceComputeFirewallCreate, + Read: resourceComputeFirewallRead, + Update: resourceComputeFirewallUpdate, + Delete: resourceComputeFirewallDelete, + + Importer: &schema.ResourceImporter{ + State: resourceComputeFirewallImport, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(240 * time.Second), + Update: schema.DefaultTimeout(240 * time.Second), + Delete: schema.DefaultTimeout(240 * time.Second), + }, + SchemaVersion: 1, + MigrateState: resourceComputeFirewallMigrateState, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validateGCPName, + }, + "network": { + Type: schema.TypeString, + Required: true, + DiffSuppressFunc: compareSelfLinkOrResourceName, + }, + "allow": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "protocol": { + Type: schema.TypeString, + Required: true, + }, + "ports": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + Set: resourceComputeFirewallRuleHash, + ConflictsWith: []string{"deny"}, + }, + "deny": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "protocol": { + Type: schema.TypeString, + Required: true, + }, + "ports": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + Set: resourceComputeFirewallRuleHash, + ConflictsWith: []string{"allow"}, + }, + "description": { + Type: schema.TypeString, + Optional: true, + }, + "destination_ranges": { + Type: schema.TypeSet, + Computed: true, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Set: schema.HashString, + ConflictsWith: []string{"source_ranges", "source_tags"}, + }, + "direction": { + Type: schema.TypeString, + Computed: true, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{"INGRESS", "EGRESS", ""}, false), + }, + "disabled": { + Type: schema.TypeBool, + Optional: true, + }, + "priority": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntBetween(0, 65535), + Default: 1000, + }, + "source_ranges": { + Type: schema.TypeSet, + Computed: true, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Set: schema.HashString, + }, + "source_service_accounts": { + Type: schema.TypeSet, + Optional: true, + MaxItems: 1, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Set: schema.HashString, + ConflictsWith: []string{"source_tags", "target_tags"}, + }, + "source_tags": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Set: schema.HashString, + }, + "target_service_accounts": { + Type: schema.TypeSet, + Optional: true, + MaxItems: 1, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Set: schema.HashString, + ConflictsWith: []string{"source_tags", "target_tags"}, + }, + "target_tags": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Set: schema.HashString, + }, + "creation_timestamp": { + Type: schema.TypeString, + Computed: true, + }, + "project": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + "self_link": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + func resourceComputeFirewallCreate(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) + obj := make(map[string]interface{}) + allowedProp, err := expandComputeFirewallAllow(d.Get("allow"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("allow"); !isEmptyValue(reflect.ValueOf(allowedProp)) && (ok || !reflect.DeepEqual(v, allowedProp)) { + obj["allowed"] = allowedProp + } + deniedProp, err := expandComputeFirewallDeny(d.Get("deny"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("deny"); !isEmptyValue(reflect.ValueOf(deniedProp)) && (ok || !reflect.DeepEqual(v, deniedProp)) { + obj["denied"] = deniedProp + } + descriptionProp, err := expandComputeFirewallDescription(d.Get("description"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("description"); !isEmptyValue(reflect.ValueOf(descriptionProp)) && (ok || !reflect.DeepEqual(v, descriptionProp)) { + obj["description"] = descriptionProp + } + destinationRangesProp, err := expandComputeFirewallDestinationRanges(d.Get("destination_ranges"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("destination_ranges"); !isEmptyValue(reflect.ValueOf(destinationRangesProp)) && (ok || !reflect.DeepEqual(v, destinationRangesProp)) { + obj["destinationRanges"] = destinationRangesProp + } + directionProp, err := expandComputeFirewallDirection(d.Get("direction"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("direction"); !isEmptyValue(reflect.ValueOf(directionProp)) && (ok || !reflect.DeepEqual(v, directionProp)) { + obj["direction"] = directionProp + } + disabledProp, err := expandComputeFirewallDisabled(d.Get("disabled"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("disabled"); ok || !reflect.DeepEqual(v, disabledProp) { + obj["disabled"] = disabledProp + } + nameProp, err := expandComputeFirewallName(d.Get("name"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("name"); !isEmptyValue(reflect.ValueOf(nameProp)) && (ok || !reflect.DeepEqual(v, nameProp)) { + obj["name"] = nameProp + } + networkProp, err := expandComputeFirewallNetwork(d.Get("network"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("network"); !isEmptyValue(reflect.ValueOf(networkProp)) && (ok || !reflect.DeepEqual(v, networkProp)) { + obj["network"] = networkProp + } + priorityProp, err := expandComputeFirewallPriority(d.Get("priority"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("priority"); !isEmptyValue(reflect.ValueOf(priorityProp)) && (ok || !reflect.DeepEqual(v, priorityProp)) { + obj["priority"] = priorityProp + } + sourceRangesProp, err := expandComputeFirewallSourceRanges(d.Get("source_ranges"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("source_ranges"); !isEmptyValue(reflect.ValueOf(sourceRangesProp)) && (ok || !reflect.DeepEqual(v, sourceRangesProp)) { + obj["sourceRanges"] = sourceRangesProp + } + sourceServiceAccountsProp, err := expandComputeFirewallSourceServiceAccounts(d.Get("source_service_accounts"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("source_service_accounts"); !isEmptyValue(reflect.ValueOf(sourceServiceAccountsProp)) && (ok || !reflect.DeepEqual(v, sourceServiceAccountsProp)) { + obj["sourceServiceAccounts"] = sourceServiceAccountsProp + } + sourceTagsProp, err := expandComputeFirewallSourceTags(d.Get("source_tags"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("source_tags"); !isEmptyValue(reflect.ValueOf(sourceTagsProp)) && (ok || !reflect.DeepEqual(v, sourceTagsProp)) { + obj["sourceTags"] = sourceTagsProp + } + targetServiceAccountsProp, err := expandComputeFirewallTargetServiceAccounts(d.Get("target_service_accounts"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("target_service_accounts"); !isEmptyValue(reflect.ValueOf(targetServiceAccountsProp)) && (ok || !reflect.DeepEqual(v, targetServiceAccountsProp)) { + obj["targetServiceAccounts"] = targetServiceAccountsProp + } + targetTagsProp, err := expandComputeFirewallTargetTags(d.Get("target_tags"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("target_tags"); !isEmptyValue(reflect.ValueOf(targetTagsProp)) && (ok || !reflect.DeepEqual(v, targetTagsProp)) { + obj["targetTags"] = targetTagsProp + } + + url, err := replaceVars(d, config, "https://www.googleapis.com/compute/beta/projects/{{project}}/global/firewalls") + if err != nil { + return err + } + + log.Printf("[DEBUG] Creating new Firewall: %#v", obj) + res, err := sendRequest(config, "POST", url, obj) + if err != nil { + return fmt.Errorf("Error creating Firewall: %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) + project, err := getProject(d, config) if err != nil { return err } - - firewall, err := resourceFirewall(d, meta) + op := &compute.Operation{} + err = Convert(res, op) if err != nil { return err } - op, err := config.clientComputeBeta.Firewalls.Insert(project, firewall).Do() - if err != nil { - return fmt.Errorf("Error creating firewall: %s", err) + waitErr := computeOperationWaitTime( + config.clientCompute, op, project, "Creating Firewall", + int(d.Timeout(schema.TimeoutCreate).Minutes())) + + if waitErr != nil { + // The resource didn't actually create + d.SetId("") + return fmt.Errorf("Error waiting to create Firewall: %s", waitErr) } - // It probably maybe worked, so store the ID now - d.SetId(firewall.Name) - - err = computeSharedOperationWait(config.clientCompute, op, project, "Creating Firewall") - if err != nil { - return err - } + log.Printf("[DEBUG] Finished creating Firewall %q: %#v", d.Id(), res) return resourceComputeFirewallRead(d, meta) } -func flattenFirewallAllowed(allowed []*computeBeta.FirewallAllowed) []map[string]interface{} { - result := make([]map[string]interface{}, 0, len(allowed)) - for _, allow := range allowed { - allowMap := make(map[string]interface{}) - allowMap["protocol"] = allow.IPProtocol - allowMap["ports"] = allow.Ports - - result = append(result, allowMap) - } - return result -} - -func flattenFirewallDenied(denied []*computeBeta.FirewallDenied) []map[string]interface{} { - result := make([]map[string]interface{}, 0, len(denied)) - for _, deny := range denied { - denyMap := make(map[string]interface{}) - denyMap["protocol"] = deny.IPProtocol - denyMap["ports"] = deny.Ports - - result = append(result, denyMap) - } - return result -} - func resourceComputeFirewallRead(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - project, err := getProject(d, config) + url, err := replaceVars(d, config, "https://www.googleapis.com/compute/beta/projects/{{project}}/global/firewalls/{{name}}") if err != nil { return err } - firewall, err := config.clientComputeBeta.Firewalls.Get(project, d.Id()).Do() + res, err := sendRequest(config, "GET", url, nil) if err != nil { - return handleNotFoundError(err, d, fmt.Sprintf("Firewall %q", d.Get("name").(string))) + return handleNotFoundError(err, d, fmt.Sprintf("ComputeFirewall %q", d.Id())) + } + + if err := d.Set("allow", flattenComputeFirewallAllow(res["allowed"])); err != nil { + return fmt.Errorf("Error reading Firewall: %s", err) + } + if err := d.Set("creation_timestamp", flattenComputeFirewallCreationTimestamp(res["creationTimestamp"])); err != nil { + return fmt.Errorf("Error reading Firewall: %s", err) + } + if err := d.Set("deny", flattenComputeFirewallDeny(res["denied"])); err != nil { + return fmt.Errorf("Error reading Firewall: %s", err) + } + if err := d.Set("description", flattenComputeFirewallDescription(res["description"])); err != nil { + return fmt.Errorf("Error reading Firewall: %s", err) + } + if err := d.Set("destination_ranges", flattenComputeFirewallDestinationRanges(res["destinationRanges"])); err != nil { + return fmt.Errorf("Error reading Firewall: %s", err) + } + if err := d.Set("direction", flattenComputeFirewallDirection(res["direction"])); err != nil { + return fmt.Errorf("Error reading Firewall: %s", err) + } + if err := d.Set("disabled", flattenComputeFirewallDisabled(res["disabled"])); err != nil { + return fmt.Errorf("Error reading Firewall: %s", err) + } + if err := d.Set("name", flattenComputeFirewallName(res["name"])); err != nil { + return fmt.Errorf("Error reading Firewall: %s", err) + } + if err := d.Set("network", flattenComputeFirewallNetwork(res["network"])); err != nil { + return fmt.Errorf("Error reading Firewall: %s", err) + } + if err := d.Set("priority", flattenComputeFirewallPriority(res["priority"])); err != nil { + return fmt.Errorf("Error reading Firewall: %s", err) + } + if err := d.Set("source_ranges", flattenComputeFirewallSourceRanges(res["sourceRanges"])); err != nil { + return fmt.Errorf("Error reading Firewall: %s", err) + } + if err := d.Set("source_service_accounts", flattenComputeFirewallSourceServiceAccounts(res["sourceServiceAccounts"])); err != nil { + return fmt.Errorf("Error reading Firewall: %s", err) + } + if err := d.Set("source_tags", flattenComputeFirewallSourceTags(res["sourceTags"])); err != nil { + return fmt.Errorf("Error reading Firewall: %s", err) + } + if err := d.Set("target_service_accounts", flattenComputeFirewallTargetServiceAccounts(res["targetServiceAccounts"])); err != nil { + return fmt.Errorf("Error reading Firewall: %s", err) + } + if err := d.Set("target_tags", flattenComputeFirewallTargetTags(res["targetTags"])); err != nil { + return fmt.Errorf("Error reading Firewall: %s", err) + } + if err := d.Set("self_link", ConvertSelfLinkToV1(res["selfLink"].(string))); err != nil { + return fmt.Errorf("Error reading Firewall: %s", err) + } + project, err := getProject(d, config) + if err != nil { + return err + } + if err := d.Set("project", project); err != nil { + return fmt.Errorf("Error reading Firewall: %s", err) } - d.Set("self_link", ConvertSelfLinkToV1(firewall.SelfLink)) - d.Set("name", firewall.Name) - d.Set("network", ConvertSelfLinkToV1(firewall.Network)) - d.Set("direction", firewall.Direction) - d.Set("description", firewall.Description) - d.Set("project", project) - d.Set("source_ranges", firewall.SourceRanges) - d.Set("source_tags", firewall.SourceTags) - d.Set("destination_ranges", firewall.DestinationRanges) - d.Set("target_tags", firewall.TargetTags) - d.Set("allow", flattenFirewallAllowed(firewall.Allowed)) - d.Set("deny", flattenFirewallDenied(firewall.Denied)) - d.Set("priority", int(firewall.Priority)) - d.Set("source_service_accounts", firewall.SourceServiceAccounts) - d.Set("target_service_accounts", firewall.TargetServiceAccounts) - d.Set("disabled", firewall.Disabled) return nil } func resourceComputeFirewallUpdate(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) + obj := make(map[string]interface{}) + allowedProp, err := expandComputeFirewallAllow(d.Get("allow"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("allow"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, allowedProp)) { + obj["allowed"] = allowedProp + } + deniedProp, err := expandComputeFirewallDeny(d.Get("deny"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("deny"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, deniedProp)) { + obj["denied"] = deniedProp + } + descriptionProp, err := expandComputeFirewallDescription(d.Get("description"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("description"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, descriptionProp)) { + obj["description"] = descriptionProp + } + destinationRangesProp, err := expandComputeFirewallDestinationRanges(d.Get("destination_ranges"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("destination_ranges"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, destinationRangesProp)) { + obj["destinationRanges"] = destinationRangesProp + } + directionProp, err := expandComputeFirewallDirection(d.Get("direction"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("direction"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, directionProp)) { + obj["direction"] = directionProp + } + disabledProp, err := expandComputeFirewallDisabled(d.Get("disabled"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("disabled"); ok || !reflect.DeepEqual(v, disabledProp) { + obj["disabled"] = disabledProp + } + nameProp, err := expandComputeFirewallName(d.Get("name"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("name"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, nameProp)) { + obj["name"] = nameProp + } + networkProp, err := expandComputeFirewallNetwork(d.Get("network"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("network"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, networkProp)) { + obj["network"] = networkProp + } + priorityProp, err := expandComputeFirewallPriority(d.Get("priority"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("priority"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, priorityProp)) { + obj["priority"] = priorityProp + } + sourceRangesProp, err := expandComputeFirewallSourceRanges(d.Get("source_ranges"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("source_ranges"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, sourceRangesProp)) { + obj["sourceRanges"] = sourceRangesProp + } + sourceServiceAccountsProp, err := expandComputeFirewallSourceServiceAccounts(d.Get("source_service_accounts"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("source_service_accounts"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, sourceServiceAccountsProp)) { + obj["sourceServiceAccounts"] = sourceServiceAccountsProp + } + sourceTagsProp, err := expandComputeFirewallSourceTags(d.Get("source_tags"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("source_tags"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, sourceTagsProp)) { + obj["sourceTags"] = sourceTagsProp + } + targetServiceAccountsProp, err := expandComputeFirewallTargetServiceAccounts(d.Get("target_service_accounts"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("target_service_accounts"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, targetServiceAccountsProp)) { + obj["targetServiceAccounts"] = targetServiceAccountsProp + } + targetTagsProp, err := expandComputeFirewallTargetTags(d.Get("target_tags"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("target_tags"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, targetTagsProp)) { + obj["targetTags"] = targetTagsProp + } + + url, err := replaceVars(d, config, "https://www.googleapis.com/compute/beta/projects/{{project}}/global/firewalls/{{name}}") + if err != nil { + return err + } + + log.Printf("[DEBUG] Updating Firewall %q: %#v", d.Id(), obj) + res, err := sendRequest(config, "PATCH", url, obj) + + if err != nil { + return fmt.Errorf("Error updating Firewall %q: %s", d.Id(), err) + } + project, err := getProject(d, config) if err != nil { return err } - - d.Partial(true) - - firewall, err := resourceFirewall(d, meta) + op := &compute.Operation{} + err = Convert(res, op) if err != nil { return err } - op, err := config.clientComputeBeta.Firewalls.Patch(project, d.Id(), firewall).Do() - if err != nil { - return fmt.Errorf("Error updating firewall: %s", err) - } + err = computeOperationWaitTime( + config.clientCompute, op, project, "Updating Firewall", + int(d.Timeout(schema.TimeoutUpdate).Minutes())) - err = computeSharedOperationWait(config.clientCompute, op, project, "Updating Firewall") if err != nil { return err } - d.Partial(false) - return resourceComputeFirewallRead(d, meta) } func resourceComputeFirewallDelete(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) + url, err := replaceVars(d, config, "https://www.googleapis.com/compute/beta/projects/{{project}}/global/firewalls/{{name}}") + if err != nil { + return err + } + + var obj map[string]interface{} + log.Printf("[DEBUG] Deleting Firewall %q", d.Id()) + res, err := sendRequest(config, "DELETE", url, obj) + if err != nil { + return handleNotFoundError(err, d, "Firewall") + } + project, err := getProject(d, config) if err != nil { return err } - - // Delete the firewall - op, err := config.clientComputeBeta.Firewalls.Delete(project, d.Id()).Do() - if err != nil { - return fmt.Errorf("Error deleting firewall: %s", err) - } - - err = computeSharedOperationWait(config.clientCompute, op, project, "Deleting Firewall") + op := &compute.Operation{} + err = Convert(res, op) if err != nil { return err } - d.SetId("") + err = computeOperationWaitTime( + config.clientCompute, op, project, "Deleting Firewall", + int(d.Timeout(schema.TimeoutDelete).Minutes())) + + if err != nil { + return err + } + + log.Printf("[DEBUG] Finished deleting Firewall %q: %#v", d.Id(), res) return nil } -func resourceFirewall(d *schema.ResourceData, meta interface{}) (*computeBeta.Firewall, error) { +func resourceComputeFirewallImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { config := meta.(*Config) + parseImportId([]string{"projects/(?P[^/]+)/global/firewalls/(?P[^/]+)", "(?P[^/]+)/(?P[^/]+)", "(?P[^/]+)"}, d, config) - network, err := ParseNetworkFieldValue(d.Get("network").(string), d, config) + // Replace import id for the resource id + id, err := replaceVars(d, config, "{{name}}") if err != nil { - return nil, err + return nil, fmt.Errorf("Error constructing id: %s", err) } + d.SetId(id) - // Build up the list of allowed entries - var allowed []*computeBeta.FirewallAllowed - if v := d.Get("allow").(*schema.Set); v.Len() > 0 { - allowed = make([]*computeBeta.FirewallAllowed, 0, v.Len()) - for _, v := range v.List() { - m := v.(map[string]interface{}) - - allowed = append(allowed, &computeBeta.FirewallAllowed{ - IPProtocol: m["protocol"].(string), - Ports: convertStringArr(m["ports"].([]interface{})), - }) - } - } - - // Build up the list of denied entries - var denied []*computeBeta.FirewallDenied - if v := d.Get("deny").(*schema.Set); v.Len() > 0 { - denied = make([]*computeBeta.FirewallDenied, 0, v.Len()) - for _, v := range v.List() { - m := v.(map[string]interface{}) - - denied = append(denied, &computeBeta.FirewallDenied{ - IPProtocol: m["protocol"].(string), - Ports: convertStringArr(m["ports"].([]interface{})), - }) - } - } - - // Build up the list of sources - var sourceRanges, sourceTags []string - if v := d.Get("source_ranges").(*schema.Set); v.Len() > 0 { - sourceRanges = make([]string, v.Len()) - for i, v := range v.List() { - sourceRanges[i] = v.(string) - } - } - if v := d.Get("source_tags").(*schema.Set); v.Len() > 0 { - sourceTags = make([]string, v.Len()) - for i, v := range v.List() { - sourceTags[i] = v.(string) - } - } - - // Build up the list of destinations - var destinationRanges []string - if v := d.Get("destination_ranges").(*schema.Set); v.Len() > 0 { - destinationRanges = make([]string, v.Len()) - for i, v := range v.List() { - destinationRanges[i] = v.(string) - } - } - - // Build up the list of targets - var targetTags []string - if v := d.Get("target_tags").(*schema.Set); v.Len() > 0 { - targetTags = make([]string, v.Len()) - for i, v := range v.List() { - targetTags[i] = v.(string) - } - } - - // Build the firewall parameter - return &computeBeta.Firewall{ - Name: d.Get("name").(string), - Description: d.Get("description").(string), - Direction: d.Get("direction").(string), - Network: network.RelativeLink(), - Allowed: allowed, - Denied: denied, - SourceRanges: sourceRanges, - SourceTags: sourceTags, - DestinationRanges: destinationRanges, - TargetTags: targetTags, - Priority: int64(d.Get("priority").(int)), - SourceServiceAccounts: convertStringSet(d.Get("source_service_accounts").(*schema.Set)), - TargetServiceAccounts: convertStringSet(d.Get("target_service_accounts").(*schema.Set)), - Disabled: d.Get("disabled").(bool), - ForceSendFields: []string{"Disabled", "Allowed", "Denied", "SourceRanges", "SourceTags", "DestinationRanges", "TargetTags"}, - }, nil + return []*schema.ResourceData{d}, nil +} + +func flattenComputeFirewallAllow(v interface{}) interface{} { + if v == nil { + return v + } + l := v.([]interface{}) + transformed := make([]interface{}, 0, len(l)) + for _, raw := range l { + original := raw.(map[string]interface{}) + transformed = append(transformed, map[string]interface{}{ + "protocol": flattenComputeFirewallAllowProtocol(original["IPProtocol"]), + "ports": flattenComputeFirewallAllowPorts(original["ports"]), + }) + } + return transformed +} +func flattenComputeFirewallAllowProtocol(v interface{}) interface{} { + return v +} + +func flattenComputeFirewallAllowPorts(v interface{}) interface{} { + return v +} + +func flattenComputeFirewallCreationTimestamp(v interface{}) interface{} { + return v +} + +func flattenComputeFirewallDeny(v interface{}) interface{} { + if v == nil { + return v + } + l := v.([]interface{}) + transformed := make([]interface{}, 0, len(l)) + for _, raw := range l { + original := raw.(map[string]interface{}) + transformed = append(transformed, map[string]interface{}{ + "protocol": flattenComputeFirewallDenyProtocol(original["IPProtocol"]), + "ports": flattenComputeFirewallDenyPorts(original["ports"]), + }) + } + return transformed +} +func flattenComputeFirewallDenyProtocol(v interface{}) interface{} { + return v +} + +func flattenComputeFirewallDenyPorts(v interface{}) interface{} { + return v +} + +func flattenComputeFirewallDescription(v interface{}) interface{} { + return v +} + +func flattenComputeFirewallDestinationRanges(v interface{}) interface{} { + if v == nil { + return v + } + return schema.NewSet(schema.HashString, v.([]interface{})) +} + +func flattenComputeFirewallDirection(v interface{}) interface{} { + return v +} + +func flattenComputeFirewallDisabled(v interface{}) interface{} { + return v +} + +func flattenComputeFirewallName(v interface{}) interface{} { + return v +} + +func flattenComputeFirewallNetwork(v interface{}) interface{} { + if v == nil { + return v + } + return ConvertSelfLinkToV1(v.(string)) +} + +func flattenComputeFirewallPriority(v interface{}) interface{} { + // Handles the string fixed64 format + if strVal, ok := v.(string); ok { + if intVal, err := strconv.ParseInt(strVal, 10, 64); err == nil { + return intVal + } // let terraform core handle it if we can't convert the string to an int. + } + return v +} + +func flattenComputeFirewallSourceRanges(v interface{}) interface{} { + if v == nil { + return v + } + return schema.NewSet(schema.HashString, v.([]interface{})) +} + +func flattenComputeFirewallSourceServiceAccounts(v interface{}) interface{} { + if v == nil { + return v + } + return schema.NewSet(schema.HashString, v.([]interface{})) +} + +func flattenComputeFirewallSourceTags(v interface{}) interface{} { + if v == nil { + return v + } + return schema.NewSet(schema.HashString, v.([]interface{})) +} + +func flattenComputeFirewallTargetServiceAccounts(v interface{}) interface{} { + if v == nil { + return v + } + return schema.NewSet(schema.HashString, v.([]interface{})) +} + +func flattenComputeFirewallTargetTags(v interface{}) interface{} { + if v == nil { + return v + } + return schema.NewSet(schema.HashString, v.([]interface{})) +} + +func expandComputeFirewallAllow(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + v = v.(*schema.Set).List() + l := v.([]interface{}) + req := make([]interface{}, 0, len(l)) + for _, raw := range l { + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedProtocol, err := expandComputeFirewallAllowProtocol(original["protocol"], d, config) + if err != nil { + return nil, err + } + transformed["IPProtocol"] = transformedProtocol + transformedPorts, err := expandComputeFirewallAllowPorts(original["ports"], d, config) + if err != nil { + return nil, err + } + transformed["ports"] = transformedPorts + req = append(req, transformed) + } + return req, nil +} + +func expandComputeFirewallAllowProtocol(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeFirewallAllowPorts(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeFirewallDeny(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + v = v.(*schema.Set).List() + l := v.([]interface{}) + req := make([]interface{}, 0, len(l)) + for _, raw := range l { + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedProtocol, err := expandComputeFirewallDenyProtocol(original["protocol"], d, config) + if err != nil { + return nil, err + } + transformed["IPProtocol"] = transformedProtocol + transformedPorts, err := expandComputeFirewallDenyPorts(original["ports"], d, config) + if err != nil { + return nil, err + } + transformed["ports"] = transformedPorts + req = append(req, transformed) + } + return req, nil +} + +func expandComputeFirewallDenyProtocol(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeFirewallDenyPorts(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeFirewallDescription(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeFirewallDestinationRanges(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + v = v.(*schema.Set).List() + return v, nil +} + +func expandComputeFirewallDirection(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeFirewallDisabled(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeFirewallName(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeFirewallNetwork(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 expandComputeFirewallPriority(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeFirewallSourceRanges(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + v = v.(*schema.Set).List() + return v, nil +} + +func expandComputeFirewallSourceServiceAccounts(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + v = v.(*schema.Set).List() + return v, nil +} + +func expandComputeFirewallSourceTags(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + v = v.(*schema.Set).List() + return v, nil +} + +func expandComputeFirewallTargetServiceAccounts(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + v = v.(*schema.Set).List() + return v, nil +} + +func expandComputeFirewallTargetTags(v interface{}, d *schema.ResourceData, config *Config) (interface{}, error) { + v = v.(*schema.Set).List() + return v, nil } diff --git a/website/docs/r/compute_firewall.html.markdown b/website/docs/r/compute_firewall.html.markdown index 699b510c..677890c7 100644 --- a/website/docs/r/compute_firewall.html.markdown +++ b/website/docs/r/compute_firewall.html.markdown @@ -1,24 +1,56 @@ --- +# ---------------------------------------------------------------------------- +# +# *** 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_firewall" sidebar_current: "docs-google-compute-firewall" description: |- - Manages a firewall resource within GCE. + Each network has its own firewall controlling access to and from the + instances. --- # google\_compute\_firewall -Manages a firewall resource within GCE. For more information see -[the official documentation](https://cloud.google.com/compute/docs/vpc/firewalls) -and -[API](https://cloud.google.com/compute/docs/reference/latest/firewalls). +Each network has its own firewall controlling access to and from the +instances. + +All traffic to instances, even from other instances, is blocked by the +firewall unless firewall rules are created to allow it. + +The default network has automatically created firewall rules that are +shown in default firewall rules. No manually created network has +automatically created firewall rules except for a default "allow" rule for +outgoing traffic and a default "deny" for incoming traffic. For all +networks except the default network, you must create any firewall rules +you need. + +To get more information about Firewall, see: + +* [API documentation](https://cloud.google.com/compute/docs/reference/latest/firewalls) +* How-to Guides + * [Official Documentation](https://cloud.google.com/vpc/docs/firewalls) ## Example Usage ```hcl +resource "google_compute_network" "default" { + name = "test-network" +} + resource "google_compute_firewall" "default" { name = "test-firewall" - network = "${google_compute_network.other.name}" + network = "${google_compute_network.default.name}" allow { protocol = "icmp" @@ -37,88 +69,187 @@ resource "google_compute_firewall" "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. -* `network` - (Required) The name or self_link of the network to attach this firewall to. +* `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) + The name or self_link of the network to attach this firewall to. + - - - -* `allow` - (Required) Can be specified multiple times for each allow - rule. Each allow block supports fields documented below. - -* `deny` - (Optional) Can be specified multiple times for each deny - rule. Each deny block supports fields documented below. Can be specified - instead of allow. -* `description` - (Optional) Textual description field. +* `allow` - + (Optional) + The list of ALLOW rules specified by this firewall. Each rule + specifies a protocol and port-range tuple that describes a permitted + connection. Structure is documented below. -* `disabled` - (Optional) Denotes whether the firewall rule is disabled, i.e not applied to the network it is associated with. - When set to true, the firewall rule is not enforced and the network behaves as if it did not exist. +* `deny` - + (Optional) + The list of DENY rules specified by this firewall. Each rule specifies + a protocol and port-range tuple that describes a denied connection. Structure is documented below. -* `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. -* `priority` - (Optional) The priority for this firewall. Ranges from 0-65535, inclusive. Defaults to 1000. Firewall - resources with lower priority values have higher precedence (e.g. a firewall resource with a priority value of 0 - takes effect over all other firewall rules with a non-zero priority). +* `destination_ranges` - + (Optional) + If destination ranges are specified, the firewall will apply only to + traffic that has destination IP address in these ranges. These ranges + must be expressed in CIDR format. Only IPv4 is supported. -* `source_ranges` - (Optional) A list of source CIDR ranges that this - firewall applies to. Can't be used for `EGRESS`. +* `direction` - + (Optional) + Direction of traffic to which this firewall applies; default is + INGRESS. Note: For INGRESS traffic, it is NOT supported to specify + destinationRanges; For EGRESS traffic, it is NOT supported to specify + sourceRanges OR sourceTags. -* `source_tags` - (Optional) A list of source tags for this firewall. Can't be used for `EGRESS`. +* `disabled` - + (Optional) + Denotes whether the firewall rule is disabled, i.e not applied to the + network it is associated with. When set to true, the firewall rule is + not enforced and the network behaves as if it did not exist. If this + is unspecified, the firewall rule will be enabled. -* `target_tags` - (Optional) A list of target tags for this firewall. +* `priority` - + (Optional) + Priority for this rule. This is an integer between 0 and 65535, both + inclusive. When not specified, the value assumed is 1000. Relative + priorities determine precedence of conflicting rules. Lower value of + priority implies higher precedence (eg, a rule with priority 0 has + higher precedence than a rule with priority 1). DENY rules take + precedence over ALLOW rules having equal priority. -* `direction` - (Optional) Direction of traffic to which this firewall applies; - One of `INGRESS` or `EGRESS`. Defaults to `INGRESS`. +* `source_ranges` - + (Optional) + If source ranges are specified, the firewall will apply only to + traffic that has source IP address in these ranges. These ranges must + be expressed in CIDR format. One or both of sourceRanges and + sourceTags may be set. If both properties are set, the firewall will + apply to traffic that has source IP address within sourceRanges OR the + source IP that belongs to a tag listed in the sourceTags property. The + connection does not need to match both properties for the firewall to + apply. Only IPv4 is supported. -* `destination_ranges` - (Optional) A list of destination CIDR ranges that this - firewall applies to. Can't be used for `INGRESS`. +* `source_service_accounts` - + (Optional) + If source service accounts are specified, the firewall will apply only + to traffic originating from an instance with a service account in this + list. Source service accounts cannot be used to control traffic to an + instance's external IP address because service accounts are associated + with an instance, not an IP address. sourceRanges can be set at the + same time as sourceServiceAccounts. If both are set, the firewall will + apply to traffic that has source IP address within sourceRanges OR the + source IP belongs to an instance with service account listed in + sourceServiceAccount. The connection does not need to match both + properties for the firewall to apply. sourceServiceAccounts cannot be + used at the same time as sourceTags or targetTags. -* `source_service_accounts` - (Optional) A list of service accounts such that - the firewall will apply only to traffic originating from an instance with a service account in this list. Note that as of May 2018, - this list can contain only one item, due to a change in the way that these firewall rules are handled. Source service accounts - cannot be used to control traffic to an instance's external IP address because service accounts are associated with an instance, not - an IP address. `source_ranges` can be set at the same time as `source_service_accounts`. If both are set, the firewall will apply to - traffic that has source IP address within `source_ranges` OR the source IP belongs to an instance with service account listed in - `source_service_accounts`. The connection does not need to match both properties for the firewall to apply. `source_service_accounts` - cannot be used at the same time as `source_tags` or `target_tags`. +* `source_tags` - + (Optional) + If source tags are specified, the firewall will apply only to traffic + with source IP that belongs to a tag listed in source tags. Source + tags cannot be used to control traffic to an instance's external IP + address. Because tags are associated with an instance, not an IP + address. One or both of sourceRanges and sourceTags may be set. If + both properties are set, the firewall will apply to traffic that has + source IP address within sourceRanges OR the source IP that belongs to + a tag listed in the sourceTags property. The connection does not need + to match both properties for the firewall to apply. + +* `target_service_accounts` - + (Optional) + A list of service accounts indicating sets of instances located in the + network that may make network connections as specified in allowed[]. + targetServiceAccounts cannot be used at the same time as targetTags or + sourceTags. If neither targetServiceAccounts nor targetTags are + specified, the firewall rule applies to all instances on the specified + network. + +* `target_tags` - + (Optional) + A list of instance tags indicating sets of instances located in the + network that may make network connections as specified in allowed[]. + If no targetTags are specified, the firewall rule applies to all + instances on the specified network. +* `project` - (Optional) The ID of the project in which the resource belongs. + If it is not provided, the provider project is used. -* `target_service_accounts` - (Optional) A list of service accounts indicating - sets of instances located in the network that may make network connections as specified in `allow`. `target_service_accounts` cannot - be used at the same time as `source_tags` or `target_tags`. If neither `target_service_accounts` nor `target_tags` are specified, the - firewall rule applies to all instances on the specified network. Note that as of May 2018, this list can contain only one item, due - to a change in the way that these firewall rules are handled. The `allow` block supports: -* `protocol` - (Required) The name of the protocol to allow. This value can either be one of the following well - known protocol strings (tcp, udp, icmp, esp, ah, sctp), or the IP protocol number, or `all`. +* `protocol` - + (Required) + The IP protocol to which this rule applies. The protocol type is + required when creating a firewall rule. This value can either be + one of the following well known protocol strings (tcp, udp, + icmp, esp, ah, sctp), or the IP protocol number. -* `ports` - (Optional) List of ports and/or port ranges to allow. This can - only be specified if the protocol is TCP or UDP. +* `ports` - + (Optional) + An optional list of ports to which this rule applies. This field + is only applicable for UDP or TCP protocol. Each entry must be + either an integer or a range. If not specified, this rule + applies to connections through any port. + Example inputs include: ["22"], ["80","443"], and + ["12345-12349"]. The `deny` block supports: -* `protocol` - (Required) The name of the protocol to deny. This value can either be one of the following well - known protocol strings (tcp, udp, icmp, esp, ah, sctp), or the IP protocol number, or `all`. +* `protocol` - + (Required) + The IP protocol to which this rule applies. The protocol type is + required when creating a firewall rule. This value can either be + one of the following well known protocol strings (tcp, udp, + icmp, esp, ah, sctp), or the IP protocol number. -* `ports` - (Optional) List of ports and/or port ranges to allow. This can - only be specified if the protocol is TCP or UDP. +* `ports` - + (Optional) + An optional list of ports to which this rule applies. This field + is only applicable for UDP or TCP protocol. Each entry must be + either an integer or a range. If not specified, this rule + applies to connections through any port. + Example inputs include: ["22"], ["80","443"], and + ["12345-12349"]. ## 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. +- `update` - Default is 4 minutes. +- `delete` - Default is 4 minutes. + ## Import -Firewalls can be imported using the `name`, e.g. +Firewall can be imported using any of these accepted formats: ``` -$ terraform import google_compute_firewall.default test-firewall +$ terraform import google_compute_firewall.default projects/{{project}}/global/firewalls/{{name}} +$ terraform import google_compute_firewall.default {{project}}/{{name}} +$ terraform import google_compute_firewall.default {{name}} ```