Skip to content

Commit

Permalink
Shared reservation (#5547) (#10899)
Browse files Browse the repository at this point in the history
* Adding shareSetting to create SherdReservations.

* Add ShareSetting to create sharedReservation.

* fixing the update test

* fixing sharedReservation test

* adding shareType local to instance test.

* fixing shareType issue.

* fixing shareType issue.

* fix ShareType issue.

* fix shareType issue.

* unde recent changes.

* provide digit validation for project_number.

* set ignore_read=true for shareSettings to enable project_id.

Signed-off-by: Modular Magician <magic-modules@google.com>
  • Loading branch information
modular-magician committed Jan 12, 2022
1 parent 8ae7e58 commit c0b9f8a
Show file tree
Hide file tree
Showing 9 changed files with 246 additions and 27 deletions.
3 changes: 3 additions & 0 deletions .changelog/5547.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
compute: Added `shareSettings` in `google_compute_reservation`
```
1 change: 0 additions & 1 deletion google/resource_compute_instance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5594,7 +5594,6 @@ resource "google_compute_reservation" "reservation" {
machine_type = "n1-standard-1"
}
}
specific_reservation_required = true
}
Expand Down
106 changes: 106 additions & 0 deletions google/resource_compute_reservation.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,47 @@ for information on available CPU platforms.`,
ForceNew: true,
Description: `An optional description of this resource.`,
},
"share_settings": {
Type: schema.TypeList,
Computed: true,
Optional: true,
ForceNew: true,
Description: `The share setting for reservations.`,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"project_map": {
Type: schema.TypeSet,
Optional: true,
ForceNew: true,
Description: `A map of project number and project config. This is only valid when shareType's value is SPECIFIC_PROJECTS.`,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"project_id": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
Description: `The project id/number, should be same as the key of this project config in the project map.`,
},
},
},
},
"share_type": {
Type: schema.TypeString,
Computed: true,
Optional: true,
ForceNew: true,
ValidateFunc: validation.StringInSlice([]string{"LOCAL", "SPECIFIC_PROJECTS", ""}, false),
Description: `Type of sharing for this shared-reservation Possible values: ["LOCAL", "SPECIFIC_PROJECTS"]`,
},
},
},
},
"specific_reservation_required": {
Type: schema.TypeBool,
Optional: true,
Expand Down Expand Up @@ -234,6 +275,12 @@ func resourceComputeReservationCreate(d *schema.ResourceData, meta interface{})
} else if v, ok := d.GetOkExists("specific_reservation_required"); !isEmptyValue(reflect.ValueOf(specificReservationRequiredProp)) && (ok || !reflect.DeepEqual(v, specificReservationRequiredProp)) {
obj["specificReservationRequired"] = specificReservationRequiredProp
}
shareSettingsProp, err := expandComputeReservationShareSettings(d.Get("share_settings"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("share_settings"); !isEmptyValue(reflect.ValueOf(shareSettingsProp)) && (ok || !reflect.DeepEqual(v, shareSettingsProp)) {
obj["shareSettings"] = shareSettingsProp
}
specificReservationProp, err := expandComputeReservationSpecificReservation(d.Get("specific_reservation"), d, config)
if err != nil {
return err
Expand Down Expand Up @@ -687,6 +734,65 @@ func expandComputeReservationSpecificReservationRequired(v interface{}, d Terraf
return v, nil
}

func expandComputeReservationShareSettings(v interface{}, d TerraformResourceData, config *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{})

transformedShareType, err := expandComputeReservationShareSettingsShareType(original["share_type"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedShareType); val.IsValid() && !isEmptyValue(val) {
transformed["shareType"] = transformedShareType
}

transformedProjectMap, err := expandComputeReservationShareSettingsProjectMap(original["project_map"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedProjectMap); val.IsValid() && !isEmptyValue(val) {
transformed["projectMap"] = transformedProjectMap
}

return transformed, nil
}

func expandComputeReservationShareSettingsShareType(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
return v, nil
}

func expandComputeReservationShareSettingsProjectMap(v interface{}, d TerraformResourceData, config *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{})

transformedProjectId, err := expandComputeReservationShareSettingsProjectMapProjectId(original["project_id"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedProjectId); val.IsValid() && !isEmptyValue(val) {
transformed["projectId"] = transformedProjectId
}

transformedId, err := expandString(original["id"], d, config)
if err != nil {
return nil, err
}
m[transformedId] = transformed
}
return m, nil
}

func expandComputeReservationShareSettingsProjectMapProjectId(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
return v, nil
}

func expandComputeReservationSpecificReservation(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
l := v.([]interface{})
if len(l) == 0 || l[0] == nil {
Expand Down
87 changes: 86 additions & 1 deletion google/resource_compute_reservation_generated_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func TestAccComputeReservation_reservationBasicExample(t *testing.T) {
ResourceName: "google_compute_reservation.gce_reservation",
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"zone"},
ImportStateVerifyIgnore: []string{"share_settings", "zone"},
},
},
})
Expand All @@ -65,6 +65,91 @@ resource "google_compute_reservation" "gce_reservation" {
`, context)
}

func TestAccComputeReservation_sharedReservationBasicExample(t *testing.T) {
skipIfVcr(t)
t.Parallel()

context := map[string]interface{}{
"project": getTestProjectFromEnv(),
"org_id": getTestOrgFromEnv(t),
"billing_account": getTestBillingAccountFromEnv(t),
"random_suffix": randString(t, 10),
}

vcrTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckComputeReservationDestroyProducer(t),
Steps: []resource.TestStep{
{
Config: testAccComputeReservation_sharedReservationBasicExample(context),
},
{
ResourceName: "google_compute_reservation.gce_reservation",
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"share_settings", "zone"},
},
},
})
}

func testAccComputeReservation_sharedReservationBasicExample(context map[string]interface{}) string {
return Nprintf(`
resource "google_project" "owner_project" {
project_id = "tf-test%{random_suffix}"
name = "tf-test%{random_suffix}"
org_id = "%{org_id}"
billing_account = "%{billing_account}"
}
resource "google_project_service" "compute" {
project = google_project.owner_project.project_id
service = "compute.googleapis.com"
disable_on_destroy = false
}
resource "google_project" "guest_project" {
project_id = "tf-test-2%{random_suffix}"
name = "tf-test-2%{random_suffix}"
org_id = "%{org_id}"
}
resource "google_organization_policy" "shared_reservation_org_policy" {
org_id = "%{org_id}"
constraint = "constraints/compute.sharedReservationsOwnerProjects"
list_policy {
allow {
values = ["projects/${google_project.owner_project.number}"]
}
}
}
resource "google_compute_reservation" "gce_reservation" {
project = google_project.owner_project.project_id
name = "tf-test-gce-shared-reservation%{random_suffix}"
zone = "us-central1-a"
specific_reservation {
count = 1
instance_properties {
min_cpu_platform = "Intel Cascade Lake"
machine_type = "n2-standard-2"
}
}
share_settings {
share_type = "SPECIFIC_PROJECTS"
project_map {
id = google_project.guest_project.project_id
project_id = google_project.guest_project.project_id
}
}
depends_on = [google_organization_policy.shared_reservation_org_policy,google_project_service.compute]
}
`, context)
}

func testAccCheckComputeReservationDestroyProducer(t *testing.T) func(s *terraform.State) error {
return func(s *terraform.State) error {
for name, rs := range s.RootModule().Resources {
Expand Down
2 changes: 1 addition & 1 deletion google/resource_compute_subnetwork.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ access Google APIs and services by using Private Google Access.`,
ForceNew: true,
Description: `The purpose of the resource. A subnetwork with purpose set to
INTERNAL_HTTPS_LOAD_BALANCER is a user-created subnetwork that is
reserved for Internal HTTP(S) Load Balancing.
reserved for Internal HTTP(S) Load Balancing.
If set to INTERNAL_HTTPS_LOAD_BALANCER you must also set the 'role' field.`,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -974,7 +974,7 @@ The following arguments are supported:
* `idle_timeout_sec` -
(Optional)
Specifies how long to keep a Connection Tracking entry while there is
no matching traffic (in seconds).
no matching traffic (in seconds).
For L4 ILB the minimum(default) is 10 minutes and maximum is 16 hours.
For NLB the minimum(default) is 60 seconds and the maximum is 16 hours.

Expand Down
26 changes: 26 additions & 0 deletions website/docs/r/compute_reservation.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -165,10 +165,36 @@ The following arguments are supported:
consume this reservation. Otherwise, it can be consumed by VMs with
affinity for any reservation. Defaults to false.

* `share_settings` -
(Optional)
The share setting for reservations.
Structure is [documented below](#nested_share_settings).

* `project` - (Optional) The ID of the project in which the resource belongs.
If it is not provided, the provider project is used.


<a name="nested_share_settings"></a>The `share_settings` block supports:

* `share_type` -
(Optional)
Type of sharing for this shared-reservation
Possible values are `LOCAL` and `SPECIFIC_PROJECTS`.

* `project_map` -
(Optional)
A map of project number and project config. This is only valid when shareType's value is SPECIFIC_PROJECTS.
Structure is [documented below](#nested_project_map).


<a name="nested_project_map"></a>The `project_map` block supports:

* `id` - (Required) The identifier for this object. Format specified above.

* `project_id` -
(Optional)
The project id/number, should be same as the key of this project config in the project map.

## Attributes Reference

In addition to the arguments listed above, the following computed attributes are exported:
Expand Down
2 changes: 1 addition & 1 deletion website/docs/r/compute_subnetwork.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ The following arguments are supported:
(Optional)
The purpose of the resource. A subnetwork with purpose set to
INTERNAL_HTTPS_LOAD_BALANCER is a user-created subnetwork that is
reserved for Internal HTTP(S) Load Balancing.
reserved for Internal HTTP(S) Load Balancing.
If set to INTERNAL_HTTPS_LOAD_BALANCER you must also set the `role` field.

* `role` -
Expand Down
44 changes: 22 additions & 22 deletions website/docs/r/os_config_os_policy_assignment.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -702,6 +702,28 @@ The `disruption_budget` block supports:
(Optional)
Specifies the relative value defined as a percentage, which will be multiplied by a reference value.

The `validate` block supports:

* `interpreter` -
(Required)
Required. The script interpreter to use. Possible values: INTERPRETER_UNSPECIFIED, NONE, SHELL, POWERSHELL

* `args` -
(Optional)
Optional arguments to pass to the source during execution.

* `file` -
(Optional)
Required. A deb package.

* `output_file_path` -
(Optional)
Only recorded for enforce Exec. Path to an output file (that is created by this Exec) whose content will be recorded in OSPolicyResourceCompliance after a successful run. Absence or failure to read this file will result in this ExecResource being non-compliant. Output file size is limited to 100K bytes.

* `script` -
(Optional)
An inline script. The size of the script is limited to 1024 characters.

- - -

* `description` -
Expand Down Expand Up @@ -993,28 +1015,6 @@ The `remote` block supports:
(Optional)
SHA256 checksum of the remote file.

The `enforce` block supports:

* `interpreter` -
(Required)
Required. The script interpreter to use. Possible values: INTERPRETER_UNSPECIFIED, NONE, SHELL, POWERSHELL

* `args` -
(Optional)
Optional arguments to pass to the source during execution.

* `file` -
(Optional)
Required. A deb package.

* `output_file_path` -
(Optional)
Only recorded for enforce Exec. Path to an output file (that is created by this Exec) whose content will be recorded in OSPolicyResourceCompliance after a successful run. Absence or failure to read this file will result in this ExecResource being non-compliant. Output file size is limited to 100K bytes.

* `script` -
(Optional)
An inline script. The size of the script is limited to 1024 characters.

## Attributes Reference

In addition to the arguments listed above, the following computed attributes are exported:
Expand Down

0 comments on commit c0b9f8a

Please sign in to comment.