| // 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 compute |
| |
| import ( |
| "fmt" |
| "log" |
| "reflect" |
| "time" |
| |
| "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" |
| "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 ResourceComputeRegionAutoscaler() *schema.Resource { |
| return &schema.Resource{ |
| Create: resourceComputeRegionAutoscalerCreate, |
| Read: resourceComputeRegionAutoscalerRead, |
| Update: resourceComputeRegionAutoscalerUpdate, |
| Delete: resourceComputeRegionAutoscalerDelete, |
| |
| Importer: &schema.ResourceImporter{ |
| State: resourceComputeRegionAutoscalerImport, |
| }, |
| |
| Timeouts: &schema.ResourceTimeout{ |
| Create: schema.DefaultTimeout(20 * time.Minute), |
| Update: schema.DefaultTimeout(20 * time.Minute), |
| Delete: schema.DefaultTimeout(20 * time.Minute), |
| }, |
| |
| CustomizeDiff: customdiff.All( |
| tpgresource.DefaultProviderProject, |
| tpgresource.DefaultProviderRegion, |
| ), |
| |
| Schema: map[string]*schema.Schema{ |
| "autoscaling_policy": { |
| Type: schema.TypeList, |
| Required: true, |
| Description: `The configuration parameters for the autoscaling algorithm. You can |
| define one or more of the policies for an autoscaler: cpuUtilization, |
| customMetricUtilizations, and loadBalancingUtilization. |
| |
| If none of these are specified, the default will be to autoscale based |
| on cpuUtilization to 0.6 or 60%.`, |
| MaxItems: 1, |
| Elem: &schema.Resource{ |
| Schema: map[string]*schema.Schema{ |
| "max_replicas": { |
| Type: schema.TypeInt, |
| Required: true, |
| Description: `The maximum number of instances that the autoscaler can scale up |
| to. This is required when creating or updating an autoscaler. The |
| maximum number of replicas should not be lower than minimal number |
| of replicas.`, |
| }, |
| "min_replicas": { |
| Type: schema.TypeInt, |
| Required: true, |
| Description: `The minimum number of replicas that the autoscaler can scale down |
| to. This cannot be less than 0. If not provided, autoscaler will |
| choose a default value depending on maximum number of instances |
| allowed.`, |
| }, |
| "cooldown_period": { |
| Type: schema.TypeInt, |
| Optional: true, |
| Description: `The number of seconds that the autoscaler should wait before it |
| starts collecting information from a new instance. This prevents |
| the autoscaler from collecting information when the instance is |
| initializing, during which the collected usage would not be |
| reliable. The default time autoscaler waits is 60 seconds. |
| |
| Virtual machine initialization times might vary because of |
| numerous factors. We recommend that you test how long an |
| instance may take to initialize. To do this, create an instance |
| and time the startup process.`, |
| Default: 60, |
| }, |
| "cpu_utilization": { |
| Type: schema.TypeList, |
| Computed: true, |
| Optional: true, |
| Description: `Defines the CPU utilization policy that allows the autoscaler to |
| scale based on the average CPU utilization of a managed instance |
| group.`, |
| MaxItems: 1, |
| Elem: &schema.Resource{ |
| Schema: map[string]*schema.Schema{ |
| "target": { |
| Type: schema.TypeFloat, |
| Required: true, |
| Description: `The target CPU utilization that the autoscaler should maintain. |
| Must be a float value in the range (0, 1]. If not specified, the |
| default is 0.6. |
| |
| If the CPU level is below the target utilization, the autoscaler |
| scales down the number of instances until it reaches the minimum |
| number of instances you specified or until the average CPU of |
| your instances reaches the target utilization. |
| |
| If the average CPU is above the target utilization, the autoscaler |
| scales up until it reaches the maximum number of instances you |
| specified or until the average utilization reaches the target |
| utilization.`, |
| }, |
| "predictive_method": { |
| Type: schema.TypeString, |
| Optional: true, |
| Description: `Indicates whether predictive autoscaling based on CPU metric is enabled. Valid values are: |
| |
| - NONE (default). No predictive method is used. The autoscaler scales the group to meet current demand based on real-time metrics. |
| |
| - OPTIMIZE_AVAILABILITY. Predictive autoscaling improves availability by monitoring daily and weekly load patterns and scaling out ahead of anticipated demand.`, |
| Default: "NONE", |
| }, |
| }, |
| }, |
| }, |
| "load_balancing_utilization": { |
| Type: schema.TypeList, |
| Optional: true, |
| Description: `Configuration parameters of autoscaling based on a load balancer.`, |
| MaxItems: 1, |
| Elem: &schema.Resource{ |
| Schema: map[string]*schema.Schema{ |
| "target": { |
| Type: schema.TypeFloat, |
| Required: true, |
| Description: `Fraction of backend capacity utilization (set in HTTP(s) load |
| balancing configuration) that autoscaler should maintain. Must |
| be a positive float value. If not defined, the default is 0.8.`, |
| }, |
| }, |
| }, |
| }, |
| "metric": { |
| Type: schema.TypeList, |
| Optional: true, |
| Description: `Configuration parameters of autoscaling based on a custom metric.`, |
| Elem: &schema.Resource{ |
| Schema: map[string]*schema.Schema{ |
| "name": { |
| Type: schema.TypeString, |
| Required: true, |
| Description: `The identifier (type) of the Stackdriver Monitoring metric. |
| The metric cannot have negative values. |
| |
| The metric must have a value type of INT64 or DOUBLE.`, |
| }, |
| "filter": { |
| Type: schema.TypeString, |
| Optional: true, |
| Description: `A filter string to be used as the filter string for |
| a Stackdriver Monitoring TimeSeries.list API call. |
| This filter is used to select a specific TimeSeries for |
| the purpose of autoscaling and to determine whether the metric |
| is exporting per-instance or per-group data. |
| |
| You can only use the AND operator for joining selectors. |
| You can only use direct equality comparison operator (=) without |
| any functions for each selector. |
| You can specify the metric in both the filter string and in the |
| metric field. However, if specified in both places, the metric must |
| be identical. |
| |
| The monitored resource type determines what kind of values are |
| expected for the metric. If it is a gce_instance, the autoscaler |
| expects the metric to include a separate TimeSeries for each |
| instance in a group. In such a case, you cannot filter on resource |
| labels. |
| |
| If the resource type is any other value, the autoscaler expects |
| this metric to contain values that apply to the entire autoscaled |
| instance group and resource label filtering can be performed to |
| point autoscaler at the correct TimeSeries to scale upon. |
| This is called a per-group metric for the purpose of autoscaling. |
| |
| If not specified, the type defaults to gce_instance. |
| |
| You should provide a filter that is selective enough to pick just |
| one TimeSeries for the autoscaled group or for each of the instances |
| (if you are using gce_instance resource type). If multiple |
| TimeSeries are returned upon the query execution, the autoscaler |
| will sum their respective values to obtain its scaling value.`, |
| }, |
| "single_instance_assignment": { |
| Type: schema.TypeFloat, |
| Optional: true, |
| Description: `If scaling is based on a per-group metric value that represents the |
| total amount of work to be done or resource usage, set this value to |
| an amount assigned for a single instance of the scaled group. |
| The autoscaler will keep the number of instances proportional to the |
| value of this metric, the metric itself should not change value due |
| to group resizing. |
| |
| For example, a good metric to use with the target is |
| 'pubsub.googleapis.com/subscription/num_undelivered_messages' |
| or a custom metric exporting the total number of requests coming to |
| your instances. |
| |
| A bad example would be a metric exporting an average or median |
| latency, since this value can't include a chunk assignable to a |
| single instance, it could be better used with utilization_target |
| instead.`, |
| }, |
| "target": { |
| Type: schema.TypeFloat, |
| Optional: true, |
| Description: `The target value of the metric that autoscaler should |
| maintain. This must be a positive value. A utilization |
| metric scales number of virtual machines handling requests |
| to increase or decrease proportionally to the metric. |
| |
| For example, a good metric to use as a utilizationTarget is |
| www.googleapis.com/compute/instance/network/received_bytes_count. |
| The autoscaler will work to keep this value constant for each |
| of the instances.`, |
| }, |
| "type": { |
| Type: schema.TypeString, |
| Optional: true, |
| ValidateFunc: verify.ValidateEnum([]string{"GAUGE", "DELTA_PER_SECOND", "DELTA_PER_MINUTE", ""}), |
| Description: `Defines how target utilization value is expressed for a |
| Stackdriver Monitoring metric. Possible values: ["GAUGE", "DELTA_PER_SECOND", "DELTA_PER_MINUTE"]`, |
| }, |
| }, |
| }, |
| }, |
| "mode": { |
| Type: schema.TypeString, |
| Optional: true, |
| Description: `Defines operating mode for this policy.`, |
| Default: "ON", |
| }, |
| "scale_down_control": { |
| Type: schema.TypeList, |
| Optional: true, |
| Description: `Defines scale down controls to reduce the risk of response latency |
| and outages due to abrupt scale-in events`, |
| MaxItems: 1, |
| Elem: &schema.Resource{ |
| Schema: map[string]*schema.Schema{ |
| "max_scaled_down_replicas": { |
| Type: schema.TypeList, |
| Optional: true, |
| Description: `A nested object resource`, |
| MaxItems: 1, |
| Elem: &schema.Resource{ |
| Schema: map[string]*schema.Schema{ |
| "fixed": { |
| Type: schema.TypeInt, |
| Optional: true, |
| Description: `Specifies a fixed number of VM instances. This must be a positive |
| integer.`, |
| AtLeastOneOf: []string{"autoscaling_policy.0.scale_down_control.0.max_scaled_down_replicas.0.fixed", "autoscaling_policy.0.scale_down_control.0.max_scaled_down_replicas.0.percent"}, |
| }, |
| "percent": { |
| Type: schema.TypeInt, |
| Optional: true, |
| Description: `Specifies a percentage of instances between 0 to 100%, inclusive. |
| For example, specify 80 for 80%.`, |
| AtLeastOneOf: []string{"autoscaling_policy.0.scale_down_control.0.max_scaled_down_replicas.0.fixed", "autoscaling_policy.0.scale_down_control.0.max_scaled_down_replicas.0.percent"}, |
| }, |
| }, |
| }, |
| AtLeastOneOf: []string{"autoscaling_policy.0.scale_down_control.0.max_scaled_down_replicas", "autoscaling_policy.0.scale_down_control.0.time_window_sec"}, |
| }, |
| "time_window_sec": { |
| Type: schema.TypeInt, |
| Optional: true, |
| Description: `How long back autoscaling should look when computing recommendations |
| to include directives regarding slower scale down, as described above.`, |
| AtLeastOneOf: []string{"autoscaling_policy.0.scale_down_control.0.max_scaled_down_replicas", "autoscaling_policy.0.scale_down_control.0.time_window_sec"}, |
| }, |
| }, |
| }, |
| }, |
| "scale_in_control": { |
| Type: schema.TypeList, |
| Optional: true, |
| Description: `Defines scale in controls to reduce the risk of response latency |
| and outages due to abrupt scale-in events`, |
| MaxItems: 1, |
| Elem: &schema.Resource{ |
| Schema: map[string]*schema.Schema{ |
| "max_scaled_in_replicas": { |
| Type: schema.TypeList, |
| Optional: true, |
| Description: `A nested object resource`, |
| MaxItems: 1, |
| Elem: &schema.Resource{ |
| Schema: map[string]*schema.Schema{ |
| "fixed": { |
| Type: schema.TypeInt, |
| Optional: true, |
| Description: `Specifies a fixed number of VM instances. This must be a positive |
| integer.`, |
| AtLeastOneOf: []string{"autoscaling_policy.0.scale_in_control.0.max_scaled_in_replicas.0.fixed", "autoscaling_policy.0.scale_in_control.0.max_scaled_in_replicas.0.percent"}, |
| }, |
| "percent": { |
| Type: schema.TypeInt, |
| Optional: true, |
| Description: `Specifies a percentage of instances between 0 to 100%, inclusive. |
| For example, specify 80 for 80%.`, |
| AtLeastOneOf: []string{"autoscaling_policy.0.scale_in_control.0.max_scaled_in_replicas.0.fixed", "autoscaling_policy.0.scale_in_control.0.max_scaled_in_replicas.0.percent"}, |
| }, |
| }, |
| }, |
| AtLeastOneOf: []string{"autoscaling_policy.0.scale_in_control.0.max_scaled_in_replicas", "autoscaling_policy.0.scale_in_control.0.time_window_sec"}, |
| }, |
| "time_window_sec": { |
| Type: schema.TypeInt, |
| Optional: true, |
| Description: `How long back autoscaling should look when computing recommendations |
| to include directives regarding slower scale down, as described above.`, |
| AtLeastOneOf: []string{"autoscaling_policy.0.scale_in_control.0.max_scaled_in_replicas", "autoscaling_policy.0.scale_in_control.0.time_window_sec"}, |
| }, |
| }, |
| }, |
| }, |
| "scaling_schedules": { |
| Type: schema.TypeSet, |
| Optional: true, |
| Description: `Scaling schedules defined for an autoscaler. Multiple schedules can be set on an autoscaler and they can overlap.`, |
| Elem: &schema.Resource{ |
| Schema: map[string]*schema.Schema{ |
| "name": { |
| Type: schema.TypeString, |
| Required: true, |
| }, |
| "duration_sec": { |
| Type: schema.TypeInt, |
| Required: true, |
| Description: `The duration of time intervals (in seconds) for which this scaling schedule will be running. The minimum allowed value is 300.`, |
| }, |
| "min_required_replicas": { |
| Type: schema.TypeInt, |
| Required: true, |
| Description: `Minimum number of VM instances that autoscaler will recommend in time intervals starting according to schedule.`, |
| }, |
| "schedule": { |
| Type: schema.TypeString, |
| Required: true, |
| Description: `The start timestamps of time intervals when this scaling schedule should provide a scaling signal. This field uses the extended cron format (with an optional year field).`, |
| }, |
| "description": { |
| Type: schema.TypeString, |
| Optional: true, |
| Description: `A description of a scaling schedule.`, |
| }, |
| "disabled": { |
| Type: schema.TypeBool, |
| Optional: true, |
| Description: `A boolean value that specifies if a scaling schedule can influence autoscaler recommendations. If set to true, then a scaling schedule has no effect.`, |
| Default: false, |
| }, |
| "time_zone": { |
| Type: schema.TypeString, |
| Optional: true, |
| Description: `The time zone to be used when interpreting the schedule. The value of this field must be a time zone name from the tz database: http://en.wikipedia.org/wiki/Tz_database.`, |
| Default: "UTC", |
| }, |
| }, |
| }, |
| }, |
| }, |
| }, |
| }, |
| "name": { |
| Type: schema.TypeString, |
| Required: true, |
| ForceNew: true, |
| ValidateFunc: verify.ValidateGCEName, |
| Description: `Name of the resource. 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.`, |
| }, |
| "target": { |
| Type: schema.TypeString, |
| Required: true, |
| DiffSuppressFunc: tpgresource.CompareSelfLinkOrResourceName, |
| Description: `URL of the managed instance group that this autoscaler will scale.`, |
| }, |
| "description": { |
| Type: schema.TypeString, |
| Optional: true, |
| Description: `An optional description of this resource.`, |
| }, |
| "region": { |
| Type: schema.TypeString, |
| Computed: true, |
| Optional: true, |
| ForceNew: true, |
| DiffSuppressFunc: tpgresource.CompareSelfLinkOrResourceName, |
| Description: `URL of the region where the instance group resides.`, |
| }, |
| "creation_timestamp": { |
| Type: schema.TypeString, |
| Computed: true, |
| Description: `Creation timestamp in RFC3339 text format.`, |
| }, |
| "project": { |
| Type: schema.TypeString, |
| Optional: true, |
| Computed: true, |
| ForceNew: true, |
| }, |
| "self_link": { |
| Type: schema.TypeString, |
| Computed: true, |
| }, |
| }, |
| UseJSONNumber: true, |
| } |
| } |
| |
| func resourceComputeRegionAutoscalerCreate(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 := expandComputeRegionAutoscalerName(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 := expandComputeRegionAutoscalerDescription(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 |
| } |
| autoscalingPolicyProp, err := expandComputeRegionAutoscalerAutoscalingPolicy(d.Get("autoscaling_policy"), d, config) |
| if err != nil { |
| return err |
| } else if v, ok := d.GetOkExists("autoscaling_policy"); !tpgresource.IsEmptyValue(reflect.ValueOf(autoscalingPolicyProp)) && (ok || !reflect.DeepEqual(v, autoscalingPolicyProp)) { |
| obj["autoscalingPolicy"] = autoscalingPolicyProp |
| } |
| targetProp, err := expandComputeRegionAutoscalerTarget(d.Get("target"), d, config) |
| if err != nil { |
| return err |
| } else if v, ok := d.GetOkExists("target"); !tpgresource.IsEmptyValue(reflect.ValueOf(targetProp)) && (ok || !reflect.DeepEqual(v, targetProp)) { |
| obj["target"] = targetProp |
| } |
| regionProp, err := expandComputeRegionAutoscalerRegion(d.Get("region"), d, config) |
| if err != nil { |
| return err |
| } else if v, ok := d.GetOkExists("region"); !tpgresource.IsEmptyValue(reflect.ValueOf(regionProp)) && (ok || !reflect.DeepEqual(v, regionProp)) { |
| obj["region"] = regionProp |
| } |
| |
| url, err := tpgresource.ReplaceVars(d, config, "{{ComputeBasePath}}projects/{{project}}/regions/{{region}}/autoscalers") |
| if err != nil { |
| return err |
| } |
| |
| log.Printf("[DEBUG] Creating new RegionAutoscaler: %#v", obj) |
| billingProject := "" |
| |
| project, err := tpgresource.GetProject(d, config) |
| if err != nil { |
| return fmt.Errorf("Error fetching project for RegionAutoscaler: %s", err) |
| } |
| billingProject = project |
| |
| // 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 RegionAutoscaler: %s", err) |
| } |
| |
| // Store the ID now |
| id, err := tpgresource.ReplaceVars(d, config, "projects/{{project}}/regions/{{region}}/autoscalers/{{name}}") |
| if err != nil { |
| return fmt.Errorf("Error constructing id: %s", err) |
| } |
| d.SetId(id) |
| |
| err = ComputeOperationWaitTime( |
| config, res, project, "Creating RegionAutoscaler", userAgent, |
| d.Timeout(schema.TimeoutCreate)) |
| |
| if err != nil { |
| // The resource didn't actually create |
| d.SetId("") |
| return fmt.Errorf("Error waiting to create RegionAutoscaler: %s", err) |
| } |
| |
| log.Printf("[DEBUG] Finished creating RegionAutoscaler %q: %#v", d.Id(), res) |
| |
| return resourceComputeRegionAutoscalerRead(d, meta) |
| } |
| |
| func resourceComputeRegionAutoscalerRead(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, "{{ComputeBasePath}}projects/{{project}}/regions/{{region}}/autoscalers/{{name}}") |
| if err != nil { |
| return err |
| } |
| |
| billingProject := "" |
| |
| project, err := tpgresource.GetProject(d, config) |
| if err != nil { |
| return fmt.Errorf("Error fetching project for RegionAutoscaler: %s", err) |
| } |
| billingProject = project |
| |
| // 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("ComputeRegionAutoscaler %q", d.Id())) |
| } |
| |
| if err := d.Set("project", project); err != nil { |
| return fmt.Errorf("Error reading RegionAutoscaler: %s", err) |
| } |
| |
| region, err := tpgresource.GetRegion(d, config) |
| if err != nil { |
| return err |
| } |
| if err := d.Set("region", region); err != nil { |
| return fmt.Errorf("Error reading RegionAutoscaler: %s", err) |
| } |
| |
| if err := d.Set("creation_timestamp", flattenComputeRegionAutoscalerCreationTimestamp(res["creationTimestamp"], d, config)); err != nil { |
| return fmt.Errorf("Error reading RegionAutoscaler: %s", err) |
| } |
| if err := d.Set("name", flattenComputeRegionAutoscalerName(res["name"], d, config)); err != nil { |
| return fmt.Errorf("Error reading RegionAutoscaler: %s", err) |
| } |
| if err := d.Set("description", flattenComputeRegionAutoscalerDescription(res["description"], d, config)); err != nil { |
| return fmt.Errorf("Error reading RegionAutoscaler: %s", err) |
| } |
| if err := d.Set("autoscaling_policy", flattenComputeRegionAutoscalerAutoscalingPolicy(res["autoscalingPolicy"], d, config)); err != nil { |
| return fmt.Errorf("Error reading RegionAutoscaler: %s", err) |
| } |
| if err := d.Set("target", flattenComputeRegionAutoscalerTarget(res["target"], d, config)); err != nil { |
| return fmt.Errorf("Error reading RegionAutoscaler: %s", err) |
| } |
| if err := d.Set("self_link", tpgresource.ConvertSelfLinkToV1(res["selfLink"].(string))); err != nil { |
| return fmt.Errorf("Error reading RegionAutoscaler: %s", err) |
| } |
| |
| return nil |
| } |
| |
| func resourceComputeRegionAutoscalerUpdate(d *schema.ResourceData, meta interface{}) error { |
| config := meta.(*transport_tpg.Config) |
| userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) |
| if err != nil { |
| return err |
| } |
| |
| billingProject := "" |
| |
| project, err := tpgresource.GetProject(d, config) |
| if err != nil { |
| return fmt.Errorf("Error fetching project for RegionAutoscaler: %s", err) |
| } |
| billingProject = project |
| |
| obj := make(map[string]interface{}) |
| nameProp, err := expandComputeRegionAutoscalerName(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 := expandComputeRegionAutoscalerDescription(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 |
| } |
| autoscalingPolicyProp, err := expandComputeRegionAutoscalerAutoscalingPolicy(d.Get("autoscaling_policy"), d, config) |
| if err != nil { |
| return err |
| } else if v, ok := d.GetOkExists("autoscaling_policy"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, autoscalingPolicyProp)) { |
| obj["autoscalingPolicy"] = autoscalingPolicyProp |
| } |
| targetProp, err := expandComputeRegionAutoscalerTarget(d.Get("target"), d, config) |
| if err != nil { |
| return err |
| } else if v, ok := d.GetOkExists("target"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, targetProp)) { |
| obj["target"] = targetProp |
| } |
| regionProp, err := expandComputeRegionAutoscalerRegion(d.Get("region"), d, config) |
| if err != nil { |
| return err |
| } else if v, ok := d.GetOkExists("region"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, regionProp)) { |
| obj["region"] = regionProp |
| } |
| |
| url, err := tpgresource.ReplaceVars(d, config, "{{ComputeBasePath}}projects/{{project}}/regions/{{region}}/autoscalers?autoscaler={{name}}") |
| if err != nil { |
| return err |
| } |
| |
| log.Printf("[DEBUG] Updating RegionAutoscaler %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 RegionAutoscaler %q: %s", d.Id(), err) |
| } else { |
| log.Printf("[DEBUG] Finished updating RegionAutoscaler %q: %#v", d.Id(), res) |
| } |
| |
| err = ComputeOperationWaitTime( |
| config, res, project, "Updating RegionAutoscaler", userAgent, |
| d.Timeout(schema.TimeoutUpdate)) |
| |
| if err != nil { |
| return err |
| } |
| |
| return resourceComputeRegionAutoscalerRead(d, meta) |
| } |
| |
| func resourceComputeRegionAutoscalerDelete(d *schema.ResourceData, meta interface{}) error { |
| config := meta.(*transport_tpg.Config) |
| userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) |
| if err != nil { |
| return err |
| } |
| |
| billingProject := "" |
| |
| project, err := tpgresource.GetProject(d, config) |
| if err != nil { |
| return fmt.Errorf("Error fetching project for RegionAutoscaler: %s", err) |
| } |
| billingProject = project |
| |
| url, err := tpgresource.ReplaceVars(d, config, "{{ComputeBasePath}}projects/{{project}}/regions/{{region}}/autoscalers/{{name}}") |
| if err != nil { |
| return err |
| } |
| |
| var obj map[string]interface{} |
| log.Printf("[DEBUG] Deleting RegionAutoscaler %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, "RegionAutoscaler") |
| } |
| |
| err = ComputeOperationWaitTime( |
| config, res, project, "Deleting RegionAutoscaler", userAgent, |
| d.Timeout(schema.TimeoutDelete)) |
| |
| if err != nil { |
| return err |
| } |
| |
| log.Printf("[DEBUG] Finished deleting RegionAutoscaler %q: %#v", d.Id(), res) |
| return nil |
| } |
| |
| func resourceComputeRegionAutoscalerImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { |
| config := meta.(*transport_tpg.Config) |
| if err := tpgresource.ParseImportId([]string{ |
| "^projects/(?P<project>[^/]+)/regions/(?P<region>[^/]+)/autoscalers/(?P<name>[^/]+)$", |
| "^(?P<project>[^/]+)/(?P<region>[^/]+)/(?P<name>[^/]+)$", |
| "^(?P<region>[^/]+)/(?P<name>[^/]+)$", |
| "^(?P<name>[^/]+)$", |
| }, d, config); err != nil { |
| return nil, err |
| } |
| |
| // Replace import id for the resource id |
| id, err := tpgresource.ReplaceVars(d, config, "projects/{{project}}/regions/{{region}}/autoscalers/{{name}}") |
| if err != nil { |
| return nil, fmt.Errorf("Error constructing id: %s", err) |
| } |
| d.SetId(id) |
| |
| return []*schema.ResourceData{d}, nil |
| } |
| |
| func flattenComputeRegionAutoscalerCreationTimestamp(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func flattenComputeRegionAutoscalerName(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func flattenComputeRegionAutoscalerDescription(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func flattenComputeRegionAutoscalerAutoscalingPolicy(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["min_replicas"] = |
| flattenComputeRegionAutoscalerAutoscalingPolicyMinReplicas(original["minNumReplicas"], d, config) |
| transformed["max_replicas"] = |
| flattenComputeRegionAutoscalerAutoscalingPolicyMaxReplicas(original["maxNumReplicas"], d, config) |
| transformed["cooldown_period"] = |
| flattenComputeRegionAutoscalerAutoscalingPolicyCooldownPeriod(original["coolDownPeriodSec"], d, config) |
| transformed["mode"] = |
| flattenComputeRegionAutoscalerAutoscalingPolicyMode(original["mode"], d, config) |
| transformed["scale_down_control"] = |
| flattenComputeRegionAutoscalerAutoscalingPolicyScaleDownControl(original["scaleDownControl"], d, config) |
| transformed["scale_in_control"] = |
| flattenComputeRegionAutoscalerAutoscalingPolicyScaleInControl(original["scaleInControl"], d, config) |
| transformed["cpu_utilization"] = |
| flattenComputeRegionAutoscalerAutoscalingPolicyCpuUtilization(original["cpuUtilization"], d, config) |
| transformed["metric"] = |
| flattenComputeRegionAutoscalerAutoscalingPolicyMetric(original["customMetricUtilizations"], d, config) |
| transformed["load_balancing_utilization"] = |
| flattenComputeRegionAutoscalerAutoscalingPolicyLoadBalancingUtilization(original["loadBalancingUtilization"], d, config) |
| transformed["scaling_schedules"] = |
| flattenComputeRegionAutoscalerAutoscalingPolicyScalingSchedules(original["scalingSchedules"], d, config) |
| return []interface{}{transformed} |
| } |
| func flattenComputeRegionAutoscalerAutoscalingPolicyMinReplicas(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 flattenComputeRegionAutoscalerAutoscalingPolicyMaxReplicas(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 flattenComputeRegionAutoscalerAutoscalingPolicyCooldownPeriod(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 flattenComputeRegionAutoscalerAutoscalingPolicyMode(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func flattenComputeRegionAutoscalerAutoscalingPolicyScaleDownControl(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["max_scaled_down_replicas"] = |
| flattenComputeRegionAutoscalerAutoscalingPolicyScaleDownControlMaxScaledDownReplicas(original["maxScaledDownReplicas"], d, config) |
| transformed["time_window_sec"] = |
| flattenComputeRegionAutoscalerAutoscalingPolicyScaleDownControlTimeWindowSec(original["timeWindowSec"], d, config) |
| return []interface{}{transformed} |
| } |
| func flattenComputeRegionAutoscalerAutoscalingPolicyScaleDownControlMaxScaledDownReplicas(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["fixed"] = |
| flattenComputeRegionAutoscalerAutoscalingPolicyScaleDownControlMaxScaledDownReplicasFixed(original["fixed"], d, config) |
| transformed["percent"] = |
| flattenComputeRegionAutoscalerAutoscalingPolicyScaleDownControlMaxScaledDownReplicasPercent(original["percent"], d, config) |
| return []interface{}{transformed} |
| } |
| func flattenComputeRegionAutoscalerAutoscalingPolicyScaleDownControlMaxScaledDownReplicasFixed(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 flattenComputeRegionAutoscalerAutoscalingPolicyScaleDownControlMaxScaledDownReplicasPercent(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 flattenComputeRegionAutoscalerAutoscalingPolicyScaleDownControlTimeWindowSec(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 flattenComputeRegionAutoscalerAutoscalingPolicyScaleInControl(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["max_scaled_in_replicas"] = |
| flattenComputeRegionAutoscalerAutoscalingPolicyScaleInControlMaxScaledInReplicas(original["maxScaledInReplicas"], d, config) |
| transformed["time_window_sec"] = |
| flattenComputeRegionAutoscalerAutoscalingPolicyScaleInControlTimeWindowSec(original["timeWindowSec"], d, config) |
| return []interface{}{transformed} |
| } |
| func flattenComputeRegionAutoscalerAutoscalingPolicyScaleInControlMaxScaledInReplicas(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["fixed"] = |
| flattenComputeRegionAutoscalerAutoscalingPolicyScaleInControlMaxScaledInReplicasFixed(original["fixed"], d, config) |
| transformed["percent"] = |
| flattenComputeRegionAutoscalerAutoscalingPolicyScaleInControlMaxScaledInReplicasPercent(original["percent"], d, config) |
| return []interface{}{transformed} |
| } |
| func flattenComputeRegionAutoscalerAutoscalingPolicyScaleInControlMaxScaledInReplicasFixed(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 flattenComputeRegionAutoscalerAutoscalingPolicyScaleInControlMaxScaledInReplicasPercent(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 flattenComputeRegionAutoscalerAutoscalingPolicyScaleInControlTimeWindowSec(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 flattenComputeRegionAutoscalerAutoscalingPolicyCpuUtilization(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["target"] = |
| flattenComputeRegionAutoscalerAutoscalingPolicyCpuUtilizationTarget(original["utilizationTarget"], d, config) |
| transformed["predictive_method"] = |
| flattenComputeRegionAutoscalerAutoscalingPolicyCpuUtilizationPredictiveMethod(original["predictiveMethod"], d, config) |
| return []interface{}{transformed} |
| } |
| func flattenComputeRegionAutoscalerAutoscalingPolicyCpuUtilizationTarget(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func flattenComputeRegionAutoscalerAutoscalingPolicyCpuUtilizationPredictiveMethod(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| if v == nil || tpgresource.IsEmptyValue(reflect.ValueOf(v)) { |
| return "NONE" |
| } |
| |
| return v |
| } |
| |
| func flattenComputeRegionAutoscalerAutoscalingPolicyMetric(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| if v == nil { |
| return v |
| } |
| l := v.([]interface{}) |
| transformed := make([]interface{}, 0, len(l)) |
| for _, raw := range l { |
| original := raw.(map[string]interface{}) |
| if len(original) < 1 { |
| // Do not include empty json objects coming back from the api |
| continue |
| } |
| transformed = append(transformed, map[string]interface{}{ |
| "name": flattenComputeRegionAutoscalerAutoscalingPolicyMetricName(original["metric"], d, config), |
| "single_instance_assignment": flattenComputeRegionAutoscalerAutoscalingPolicyMetricSingleInstanceAssignment(original["singleInstanceAssignment"], d, config), |
| "target": flattenComputeRegionAutoscalerAutoscalingPolicyMetricTarget(original["utilizationTarget"], d, config), |
| "type": flattenComputeRegionAutoscalerAutoscalingPolicyMetricType(original["utilizationTargetType"], d, config), |
| "filter": flattenComputeRegionAutoscalerAutoscalingPolicyMetricFilter(original["filter"], d, config), |
| }) |
| } |
| return transformed |
| } |
| func flattenComputeRegionAutoscalerAutoscalingPolicyMetricName(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func flattenComputeRegionAutoscalerAutoscalingPolicyMetricSingleInstanceAssignment(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func flattenComputeRegionAutoscalerAutoscalingPolicyMetricTarget(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func flattenComputeRegionAutoscalerAutoscalingPolicyMetricType(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func flattenComputeRegionAutoscalerAutoscalingPolicyMetricFilter(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func flattenComputeRegionAutoscalerAutoscalingPolicyLoadBalancingUtilization(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["target"] = |
| flattenComputeRegionAutoscalerAutoscalingPolicyLoadBalancingUtilizationTarget(original["utilizationTarget"], d, config) |
| return []interface{}{transformed} |
| } |
| func flattenComputeRegionAutoscalerAutoscalingPolicyLoadBalancingUtilizationTarget(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func flattenComputeRegionAutoscalerAutoscalingPolicyScalingSchedules(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| if v == nil { |
| return v |
| } |
| l := v.(map[string]interface{}) |
| transformed := make([]interface{}, 0, len(l)) |
| for k, raw := range l { |
| original := raw.(map[string]interface{}) |
| transformed = append(transformed, map[string]interface{}{ |
| "name": k, |
| "min_required_replicas": flattenComputeRegionAutoscalerAutoscalingPolicyScalingSchedulesMinRequiredReplicas(original["minRequiredReplicas"], d, config), |
| "schedule": flattenComputeRegionAutoscalerAutoscalingPolicyScalingSchedulesSchedule(original["schedule"], d, config), |
| "time_zone": flattenComputeRegionAutoscalerAutoscalingPolicyScalingSchedulesTimeZone(original["timeZone"], d, config), |
| "duration_sec": flattenComputeRegionAutoscalerAutoscalingPolicyScalingSchedulesDurationSec(original["durationSec"], d, config), |
| "disabled": flattenComputeRegionAutoscalerAutoscalingPolicyScalingSchedulesDisabled(original["disabled"], d, config), |
| "description": flattenComputeRegionAutoscalerAutoscalingPolicyScalingSchedulesDescription(original["description"], d, config), |
| }) |
| } |
| return transformed |
| } |
| func flattenComputeRegionAutoscalerAutoscalingPolicyScalingSchedulesMinRequiredReplicas(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 flattenComputeRegionAutoscalerAutoscalingPolicyScalingSchedulesSchedule(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func flattenComputeRegionAutoscalerAutoscalingPolicyScalingSchedulesTimeZone(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func flattenComputeRegionAutoscalerAutoscalingPolicyScalingSchedulesDurationSec(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 flattenComputeRegionAutoscalerAutoscalingPolicyScalingSchedulesDisabled(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func flattenComputeRegionAutoscalerAutoscalingPolicyScalingSchedulesDescription(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func flattenComputeRegionAutoscalerTarget(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func expandComputeRegionAutoscalerName(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeRegionAutoscalerDescription(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeRegionAutoscalerAutoscalingPolicy(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{}) |
| |
| transformedMinReplicas, err := expandComputeRegionAutoscalerAutoscalingPolicyMinReplicas(original["min_replicas"], d, config) |
| if err != nil { |
| return nil, err |
| } else { |
| transformed["minNumReplicas"] = transformedMinReplicas |
| } |
| |
| transformedMaxReplicas, err := expandComputeRegionAutoscalerAutoscalingPolicyMaxReplicas(original["max_replicas"], d, config) |
| if err != nil { |
| return nil, err |
| } else if val := reflect.ValueOf(transformedMaxReplicas); val.IsValid() && !tpgresource.IsEmptyValue(val) { |
| transformed["maxNumReplicas"] = transformedMaxReplicas |
| } |
| |
| transformedCooldownPeriod, err := expandComputeRegionAutoscalerAutoscalingPolicyCooldownPeriod(original["cooldown_period"], d, config) |
| if err != nil { |
| return nil, err |
| } else if val := reflect.ValueOf(transformedCooldownPeriod); val.IsValid() && !tpgresource.IsEmptyValue(val) { |
| transformed["coolDownPeriodSec"] = transformedCooldownPeriod |
| } |
| |
| transformedMode, err := expandComputeRegionAutoscalerAutoscalingPolicyMode(original["mode"], d, config) |
| if err != nil { |
| return nil, err |
| } else if val := reflect.ValueOf(transformedMode); val.IsValid() && !tpgresource.IsEmptyValue(val) { |
| transformed["mode"] = transformedMode |
| } |
| |
| transformedScaleDownControl, err := expandComputeRegionAutoscalerAutoscalingPolicyScaleDownControl(original["scale_down_control"], d, config) |
| if err != nil { |
| return nil, err |
| } else if val := reflect.ValueOf(transformedScaleDownControl); val.IsValid() && !tpgresource.IsEmptyValue(val) { |
| transformed["scaleDownControl"] = transformedScaleDownControl |
| } |
| |
| transformedScaleInControl, err := expandComputeRegionAutoscalerAutoscalingPolicyScaleInControl(original["scale_in_control"], d, config) |
| if err != nil { |
| return nil, err |
| } else if val := reflect.ValueOf(transformedScaleInControl); val.IsValid() && !tpgresource.IsEmptyValue(val) { |
| transformed["scaleInControl"] = transformedScaleInControl |
| } |
| |
| transformedCpuUtilization, err := expandComputeRegionAutoscalerAutoscalingPolicyCpuUtilization(original["cpu_utilization"], d, config) |
| if err != nil { |
| return nil, err |
| } else if val := reflect.ValueOf(transformedCpuUtilization); val.IsValid() && !tpgresource.IsEmptyValue(val) { |
| transformed["cpuUtilization"] = transformedCpuUtilization |
| } |
| |
| transformedMetric, err := expandComputeRegionAutoscalerAutoscalingPolicyMetric(original["metric"], d, config) |
| if err != nil { |
| return nil, err |
| } else if val := reflect.ValueOf(transformedMetric); val.IsValid() && !tpgresource.IsEmptyValue(val) { |
| transformed["customMetricUtilizations"] = transformedMetric |
| } |
| |
| transformedLoadBalancingUtilization, err := expandComputeRegionAutoscalerAutoscalingPolicyLoadBalancingUtilization(original["load_balancing_utilization"], d, config) |
| if err != nil { |
| return nil, err |
| } else if val := reflect.ValueOf(transformedLoadBalancingUtilization); val.IsValid() && !tpgresource.IsEmptyValue(val) { |
| transformed["loadBalancingUtilization"] = transformedLoadBalancingUtilization |
| } |
| |
| transformedScalingSchedules, err := expandComputeRegionAutoscalerAutoscalingPolicyScalingSchedules(original["scaling_schedules"], d, config) |
| if err != nil { |
| return nil, err |
| } else if val := reflect.ValueOf(transformedScalingSchedules); val.IsValid() && !tpgresource.IsEmptyValue(val) { |
| transformed["scalingSchedules"] = transformedScalingSchedules |
| } |
| |
| return transformed, nil |
| } |
| |
| func expandComputeRegionAutoscalerAutoscalingPolicyMinReplicas(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeRegionAutoscalerAutoscalingPolicyMaxReplicas(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeRegionAutoscalerAutoscalingPolicyCooldownPeriod(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeRegionAutoscalerAutoscalingPolicyMode(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeRegionAutoscalerAutoscalingPolicyScaleDownControl(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{}) |
| |
| transformedMaxScaledDownReplicas, err := expandComputeRegionAutoscalerAutoscalingPolicyScaleDownControlMaxScaledDownReplicas(original["max_scaled_down_replicas"], d, config) |
| if err != nil { |
| return nil, err |
| } else if val := reflect.ValueOf(transformedMaxScaledDownReplicas); val.IsValid() && !tpgresource.IsEmptyValue(val) { |
| transformed["maxScaledDownReplicas"] = transformedMaxScaledDownReplicas |
| } |
| |
| transformedTimeWindowSec, err := expandComputeRegionAutoscalerAutoscalingPolicyScaleDownControlTimeWindowSec(original["time_window_sec"], d, config) |
| if err != nil { |
| return nil, err |
| } else if val := reflect.ValueOf(transformedTimeWindowSec); val.IsValid() && !tpgresource.IsEmptyValue(val) { |
| transformed["timeWindowSec"] = transformedTimeWindowSec |
| } |
| |
| return transformed, nil |
| } |
| |
| func expandComputeRegionAutoscalerAutoscalingPolicyScaleDownControlMaxScaledDownReplicas(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{}) |
| |
| transformedFixed, err := expandComputeRegionAutoscalerAutoscalingPolicyScaleDownControlMaxScaledDownReplicasFixed(original["fixed"], d, config) |
| if err != nil { |
| return nil, err |
| } else if val := reflect.ValueOf(transformedFixed); val.IsValid() && !tpgresource.IsEmptyValue(val) { |
| transformed["fixed"] = transformedFixed |
| } |
| |
| transformedPercent, err := expandComputeRegionAutoscalerAutoscalingPolicyScaleDownControlMaxScaledDownReplicasPercent(original["percent"], d, config) |
| if err != nil { |
| return nil, err |
| } else if val := reflect.ValueOf(transformedPercent); val.IsValid() && !tpgresource.IsEmptyValue(val) { |
| transformed["percent"] = transformedPercent |
| } |
| |
| return transformed, nil |
| } |
| |
| func expandComputeRegionAutoscalerAutoscalingPolicyScaleDownControlMaxScaledDownReplicasFixed(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeRegionAutoscalerAutoscalingPolicyScaleDownControlMaxScaledDownReplicasPercent(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeRegionAutoscalerAutoscalingPolicyScaleDownControlTimeWindowSec(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeRegionAutoscalerAutoscalingPolicyScaleInControl(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{}) |
| |
| transformedMaxScaledInReplicas, err := expandComputeRegionAutoscalerAutoscalingPolicyScaleInControlMaxScaledInReplicas(original["max_scaled_in_replicas"], d, config) |
| if err != nil { |
| return nil, err |
| } else if val := reflect.ValueOf(transformedMaxScaledInReplicas); val.IsValid() && !tpgresource.IsEmptyValue(val) { |
| transformed["maxScaledInReplicas"] = transformedMaxScaledInReplicas |
| } |
| |
| transformedTimeWindowSec, err := expandComputeRegionAutoscalerAutoscalingPolicyScaleInControlTimeWindowSec(original["time_window_sec"], d, config) |
| if err != nil { |
| return nil, err |
| } else if val := reflect.ValueOf(transformedTimeWindowSec); val.IsValid() && !tpgresource.IsEmptyValue(val) { |
| transformed["timeWindowSec"] = transformedTimeWindowSec |
| } |
| |
| return transformed, nil |
| } |
| |
| func expandComputeRegionAutoscalerAutoscalingPolicyScaleInControlMaxScaledInReplicas(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{}) |
| |
| transformedFixed, err := expandComputeRegionAutoscalerAutoscalingPolicyScaleInControlMaxScaledInReplicasFixed(original["fixed"], d, config) |
| if err != nil { |
| return nil, err |
| } else if val := reflect.ValueOf(transformedFixed); val.IsValid() && !tpgresource.IsEmptyValue(val) { |
| transformed["fixed"] = transformedFixed |
| } |
| |
| transformedPercent, err := expandComputeRegionAutoscalerAutoscalingPolicyScaleInControlMaxScaledInReplicasPercent(original["percent"], d, config) |
| if err != nil { |
| return nil, err |
| } else if val := reflect.ValueOf(transformedPercent); val.IsValid() && !tpgresource.IsEmptyValue(val) { |
| transformed["percent"] = transformedPercent |
| } |
| |
| return transformed, nil |
| } |
| |
| func expandComputeRegionAutoscalerAutoscalingPolicyScaleInControlMaxScaledInReplicasFixed(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeRegionAutoscalerAutoscalingPolicyScaleInControlMaxScaledInReplicasPercent(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeRegionAutoscalerAutoscalingPolicyScaleInControlTimeWindowSec(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeRegionAutoscalerAutoscalingPolicyCpuUtilization(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{}) |
| |
| transformedTarget, err := expandComputeRegionAutoscalerAutoscalingPolicyCpuUtilizationTarget(original["target"], d, config) |
| if err != nil { |
| return nil, err |
| } else if val := reflect.ValueOf(transformedTarget); val.IsValid() && !tpgresource.IsEmptyValue(val) { |
| transformed["utilizationTarget"] = transformedTarget |
| } |
| |
| transformedPredictiveMethod, err := expandComputeRegionAutoscalerAutoscalingPolicyCpuUtilizationPredictiveMethod(original["predictive_method"], d, config) |
| if err != nil { |
| return nil, err |
| } else if val := reflect.ValueOf(transformedPredictiveMethod); val.IsValid() && !tpgresource.IsEmptyValue(val) { |
| transformed["predictiveMethod"] = transformedPredictiveMethod |
| } |
| |
| return transformed, nil |
| } |
| |
| func expandComputeRegionAutoscalerAutoscalingPolicyCpuUtilizationTarget(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeRegionAutoscalerAutoscalingPolicyCpuUtilizationPredictiveMethod(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeRegionAutoscalerAutoscalingPolicyMetric(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| l := v.([]interface{}) |
| req := make([]interface{}, 0, len(l)) |
| for _, raw := range l { |
| if raw == nil { |
| continue |
| } |
| original := raw.(map[string]interface{}) |
| transformed := make(map[string]interface{}) |
| |
| transformedName, err := expandComputeRegionAutoscalerAutoscalingPolicyMetricName(original["name"], d, config) |
| if err != nil { |
| return nil, err |
| } else if val := reflect.ValueOf(transformedName); val.IsValid() && !tpgresource.IsEmptyValue(val) { |
| transformed["metric"] = transformedName |
| } |
| |
| transformedSingleInstanceAssignment, err := expandComputeRegionAutoscalerAutoscalingPolicyMetricSingleInstanceAssignment(original["single_instance_assignment"], d, config) |
| if err != nil { |
| return nil, err |
| } else if val := reflect.ValueOf(transformedSingleInstanceAssignment); val.IsValid() && !tpgresource.IsEmptyValue(val) { |
| transformed["singleInstanceAssignment"] = transformedSingleInstanceAssignment |
| } |
| |
| transformedTarget, err := expandComputeRegionAutoscalerAutoscalingPolicyMetricTarget(original["target"], d, config) |
| if err != nil { |
| return nil, err |
| } else if val := reflect.ValueOf(transformedTarget); val.IsValid() && !tpgresource.IsEmptyValue(val) { |
| transformed["utilizationTarget"] = transformedTarget |
| } |
| |
| transformedType, err := expandComputeRegionAutoscalerAutoscalingPolicyMetricType(original["type"], d, config) |
| if err != nil { |
| return nil, err |
| } else if val := reflect.ValueOf(transformedType); val.IsValid() && !tpgresource.IsEmptyValue(val) { |
| transformed["utilizationTargetType"] = transformedType |
| } |
| |
| transformedFilter, err := expandComputeRegionAutoscalerAutoscalingPolicyMetricFilter(original["filter"], d, config) |
| if err != nil { |
| return nil, err |
| } else if val := reflect.ValueOf(transformedFilter); val.IsValid() && !tpgresource.IsEmptyValue(val) { |
| transformed["filter"] = transformedFilter |
| } |
| |
| req = append(req, transformed) |
| } |
| return req, nil |
| } |
| |
| func expandComputeRegionAutoscalerAutoscalingPolicyMetricName(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeRegionAutoscalerAutoscalingPolicyMetricSingleInstanceAssignment(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeRegionAutoscalerAutoscalingPolicyMetricTarget(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeRegionAutoscalerAutoscalingPolicyMetricType(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeRegionAutoscalerAutoscalingPolicyMetricFilter(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeRegionAutoscalerAutoscalingPolicyLoadBalancingUtilization(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{}) |
| |
| transformedTarget, err := expandComputeRegionAutoscalerAutoscalingPolicyLoadBalancingUtilizationTarget(original["target"], d, config) |
| if err != nil { |
| return nil, err |
| } else if val := reflect.ValueOf(transformedTarget); val.IsValid() && !tpgresource.IsEmptyValue(val) { |
| transformed["utilizationTarget"] = transformedTarget |
| } |
| |
| return transformed, nil |
| } |
| |
| func expandComputeRegionAutoscalerAutoscalingPolicyLoadBalancingUtilizationTarget(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeRegionAutoscalerAutoscalingPolicyScalingSchedules(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (map[string]interface{}, error) { |
| if v == nil { |
| return map[string]interface{}{}, nil |
| } |
| m := make(map[string]interface{}) |
| for _, raw := range v.(*schema.Set).List() { |
| original := raw.(map[string]interface{}) |
| transformed := make(map[string]interface{}) |
| |
| transformedMinRequiredReplicas, err := expandComputeRegionAutoscalerAutoscalingPolicyScalingSchedulesMinRequiredReplicas(original["min_required_replicas"], d, config) |
| if err != nil { |
| return nil, err |
| } else { |
| transformed["minRequiredReplicas"] = transformedMinRequiredReplicas |
| } |
| |
| transformedSchedule, err := expandComputeRegionAutoscalerAutoscalingPolicyScalingSchedulesSchedule(original["schedule"], d, config) |
| if err != nil { |
| return nil, err |
| } else if val := reflect.ValueOf(transformedSchedule); val.IsValid() && !tpgresource.IsEmptyValue(val) { |
| transformed["schedule"] = transformedSchedule |
| } |
| |
| transformedTimeZone, err := expandComputeRegionAutoscalerAutoscalingPolicyScalingSchedulesTimeZone(original["time_zone"], d, config) |
| if err != nil { |
| return nil, err |
| } else if val := reflect.ValueOf(transformedTimeZone); val.IsValid() && !tpgresource.IsEmptyValue(val) { |
| transformed["timeZone"] = transformedTimeZone |
| } |
| |
| transformedDurationSec, err := expandComputeRegionAutoscalerAutoscalingPolicyScalingSchedulesDurationSec(original["duration_sec"], d, config) |
| if err != nil { |
| return nil, err |
| } else if val := reflect.ValueOf(transformedDurationSec); val.IsValid() && !tpgresource.IsEmptyValue(val) { |
| transformed["durationSec"] = transformedDurationSec |
| } |
| |
| transformedDisabled, err := expandComputeRegionAutoscalerAutoscalingPolicyScalingSchedulesDisabled(original["disabled"], d, config) |
| if err != nil { |
| return nil, err |
| } else if val := reflect.ValueOf(transformedDisabled); val.IsValid() && !tpgresource.IsEmptyValue(val) { |
| transformed["disabled"] = transformedDisabled |
| } |
| |
| transformedDescription, err := expandComputeRegionAutoscalerAutoscalingPolicyScalingSchedulesDescription(original["description"], d, config) |
| if err != nil { |
| return nil, err |
| } else if val := reflect.ValueOf(transformedDescription); val.IsValid() && !tpgresource.IsEmptyValue(val) { |
| transformed["description"] = transformedDescription |
| } |
| |
| transformedName, err := tpgresource.ExpandString(original["name"], d, config) |
| if err != nil { |
| return nil, err |
| } |
| m[transformedName] = transformed |
| } |
| return m, nil |
| } |
| |
| func expandComputeRegionAutoscalerAutoscalingPolicyScalingSchedulesMinRequiredReplicas(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeRegionAutoscalerAutoscalingPolicyScalingSchedulesSchedule(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeRegionAutoscalerAutoscalingPolicyScalingSchedulesTimeZone(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeRegionAutoscalerAutoscalingPolicyScalingSchedulesDurationSec(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeRegionAutoscalerAutoscalingPolicyScalingSchedulesDisabled(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeRegionAutoscalerAutoscalingPolicyScalingSchedulesDescription(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeRegionAutoscalerTarget(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeRegionAutoscalerRegion(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| f, err := tpgresource.ParseGlobalFieldValue("regions", v.(string), "project", d, config, true) |
| if err != nil { |
| return nil, fmt.Errorf("Invalid value for region: %s", err) |
| } |
| return f.RelativeLink(), nil |
| } |