Skip to content

Commit daab7f0

Browse files
Add rollout option to osconfig patch deployment fixes hashicorp/terraform-provider-google#7124 (#3919) (#2449)
* Add rollout option to osconfig patch deployment * Add test * Set properties to required and correctly specify exactly one of * Fix typos Signed-off-by: Modular Magician <[email protected]>
1 parent 5634ed6 commit daab7f0

File tree

4 files changed

+239
-0
lines changed

4 files changed

+239
-0
lines changed

.changelog/3919.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:enhancement
2+
osconfig: added rollout field to `google_os_config_patch_deployment`
3+
```

google-beta/resource_os_config_patch_deployment.go

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -853,6 +853,55 @@ A timestamp in RFC3339 UTC "Zulu" format, accurate to nanoseconds. Example: "201
853853
},
854854
ExactlyOneOf: []string{"one_time_schedule", "recurring_schedule"},
855855
},
856+
"rollout": {
857+
Type: schema.TypeList,
858+
Optional: true,
859+
ForceNew: true,
860+
Description: `Rollout strategy of the patch job.`,
861+
MaxItems: 1,
862+
Elem: &schema.Resource{
863+
Schema: map[string]*schema.Schema{
864+
"disruption_budget": {
865+
Type: schema.TypeList,
866+
Required: true,
867+
ForceNew: true,
868+
Description: `The maximum number (or percentage) of VMs per zone to disrupt at any given moment. The number of VMs calculated from multiplying the percentage by the total number of VMs in a zone is rounded up.
869+
During patching, a VM is considered disrupted from the time the agent is notified to begin until patching has completed. This disruption time includes the time to complete reboot and any post-patch steps.
870+
A VM contributes to the disruption budget if its patching operation fails either when applying the patches, running pre or post patch steps, or if it fails to respond with a success notification before timing out. VMs that are not running or do not have an active agent do not count toward this disruption budget.
871+
For zone-by-zone rollouts, if the disruption budget in a zone is exceeded, the patch job stops, because continuing to the next zone requires completion of the patch process in the previous zone.
872+
For example, if the disruption budget has a fixed value of 10, and 8 VMs fail to patch in the current zone, the patch job continues to patch 2 VMs at a time until the zone is completed. When that zone is completed successfully, patching begins with 10 VMs at a time in the next zone. If 10 VMs in the next zone fail to patch, the patch job stops.`,
873+
MaxItems: 1,
874+
Elem: &schema.Resource{
875+
Schema: map[string]*schema.Schema{
876+
"fixed": {
877+
Type: schema.TypeInt,
878+
Optional: true,
879+
ForceNew: true,
880+
ValidateFunc: validation.IntAtLeast(1),
881+
Description: `Specifies a fixed value.`,
882+
ExactlyOneOf: []string{"rollout.0.disruption_budget.0.fixed", "rollout.0.disruption_budget.0.percentage"},
883+
},
884+
"percentage": {
885+
Type: schema.TypeInt,
886+
Optional: true,
887+
ForceNew: true,
888+
ValidateFunc: validation.IntBetween(0, 100),
889+
Description: `Specifies the relative value defined as a percentage, which will be multiplied by a reference value.`,
890+
ExactlyOneOf: []string{"rollout.0.disruption_budget.0.fixed", "rollout.0.disruption_budget.0.percentage"},
891+
},
892+
},
893+
},
894+
},
895+
"mode": {
896+
Type: schema.TypeString,
897+
Required: true,
898+
ForceNew: true,
899+
ValidateFunc: validation.StringInSlice([]string{"ZONE_BY_ZONE", "CONCURRENT_ZONES"}, false),
900+
Description: `Mode of the patch rollout. Possible values: ["ZONE_BY_ZONE", "CONCURRENT_ZONES"]`,
901+
},
902+
},
903+
},
904+
},
856905
"create_time": {
857906
Type: schema.TypeString,
858907
Computed: true,
@@ -927,6 +976,12 @@ func resourceOSConfigPatchDeploymentCreate(d *schema.ResourceData, meta interfac
927976
} else if v, ok := d.GetOkExists("recurring_schedule"); !isEmptyValue(reflect.ValueOf(recurringScheduleProp)) && (ok || !reflect.DeepEqual(v, recurringScheduleProp)) {
928977
obj["recurringSchedule"] = recurringScheduleProp
929978
}
979+
rolloutProp, err := expandOSConfigPatchDeploymentRollout(d.Get("rollout"), d, config)
980+
if err != nil {
981+
return err
982+
} else if v, ok := d.GetOkExists("rollout"); !isEmptyValue(reflect.ValueOf(rolloutProp)) && (ok || !reflect.DeepEqual(v, rolloutProp)) {
983+
obj["rollout"] = rolloutProp
984+
}
930985

931986
obj, err = resourceOSConfigPatchDeploymentEncoder(d, meta, obj)
932987
if err != nil {
@@ -1060,6 +1115,9 @@ func resourceOSConfigPatchDeploymentRead(d *schema.ResourceData, meta interface{
10601115
if err := d.Set("recurring_schedule", flattenOSConfigPatchDeploymentRecurringSchedule(res["recurringSchedule"], d, config)); err != nil {
10611116
return fmt.Errorf("Error reading PatchDeployment: %s", err)
10621117
}
1118+
if err := d.Set("rollout", flattenOSConfigPatchDeploymentRollout(res["rollout"], d, config)); err != nil {
1119+
return fmt.Errorf("Error reading PatchDeployment: %s", err)
1120+
}
10631121

10641122
return nil
10651123
}
@@ -1905,6 +1963,74 @@ func flattenOSConfigPatchDeploymentRecurringScheduleMonthlyMonthDay(v interface{
19051963
return v // let terraform core handle it otherwise
19061964
}
19071965

1966+
func flattenOSConfigPatchDeploymentRollout(v interface{}, d *schema.ResourceData, config *Config) interface{} {
1967+
if v == nil {
1968+
return nil
1969+
}
1970+
original := v.(map[string]interface{})
1971+
if len(original) == 0 {
1972+
return nil
1973+
}
1974+
transformed := make(map[string]interface{})
1975+
transformed["mode"] =
1976+
flattenOSConfigPatchDeploymentRolloutMode(original["mode"], d, config)
1977+
transformed["disruption_budget"] =
1978+
flattenOSConfigPatchDeploymentRolloutDisruptionBudget(original["disruptionBudget"], d, config)
1979+
return []interface{}{transformed}
1980+
}
1981+
func flattenOSConfigPatchDeploymentRolloutMode(v interface{}, d *schema.ResourceData, config *Config) interface{} {
1982+
return v
1983+
}
1984+
1985+
func flattenOSConfigPatchDeploymentRolloutDisruptionBudget(v interface{}, d *schema.ResourceData, config *Config) interface{} {
1986+
if v == nil {
1987+
return nil
1988+
}
1989+
original := v.(map[string]interface{})
1990+
if len(original) == 0 {
1991+
return nil
1992+
}
1993+
transformed := make(map[string]interface{})
1994+
transformed["fixed"] =
1995+
flattenOSConfigPatchDeploymentRolloutDisruptionBudgetFixed(original["fixed"], d, config)
1996+
transformed["percentage"] =
1997+
flattenOSConfigPatchDeploymentRolloutDisruptionBudgetPercentage(original["percentage"], d, config)
1998+
return []interface{}{transformed}
1999+
}
2000+
func flattenOSConfigPatchDeploymentRolloutDisruptionBudgetFixed(v interface{}, d *schema.ResourceData, config *Config) interface{} {
2001+
// Handles the string fixed64 format
2002+
if strVal, ok := v.(string); ok {
2003+
if intVal, err := strconv.ParseInt(strVal, 10, 64); err == nil {
2004+
return intVal
2005+
}
2006+
}
2007+
2008+
// number values are represented as float64
2009+
if floatVal, ok := v.(float64); ok {
2010+
intVal := int(floatVal)
2011+
return intVal
2012+
}
2013+
2014+
return v // let terraform core handle it otherwise
2015+
}
2016+
2017+
func flattenOSConfigPatchDeploymentRolloutDisruptionBudgetPercentage(v interface{}, d *schema.ResourceData, config *Config) interface{} {
2018+
// Handles the string fixed64 format
2019+
if strVal, ok := v.(string); ok {
2020+
if intVal, err := strconv.ParseInt(strVal, 10, 64); err == nil {
2021+
return intVal
2022+
}
2023+
}
2024+
2025+
// number values are represented as float64
2026+
if floatVal, ok := v.(float64); ok {
2027+
intVal := int(floatVal)
2028+
return intVal
2029+
}
2030+
2031+
return v // let terraform core handle it otherwise
2032+
}
2033+
19082034
func expandOSConfigPatchDeploymentDescription(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
19092035
return v, nil
19102036
}
@@ -3052,6 +3178,70 @@ func expandOSConfigPatchDeploymentRecurringScheduleMonthlyMonthDay(v interface{}
30523178
return v, nil
30533179
}
30543180

3181+
func expandOSConfigPatchDeploymentRollout(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
3182+
l := v.([]interface{})
3183+
if len(l) == 0 || l[0] == nil {
3184+
return nil, nil
3185+
}
3186+
raw := l[0]
3187+
original := raw.(map[string]interface{})
3188+
transformed := make(map[string]interface{})
3189+
3190+
transformedMode, err := expandOSConfigPatchDeploymentRolloutMode(original["mode"], d, config)
3191+
if err != nil {
3192+
return nil, err
3193+
} else if val := reflect.ValueOf(transformedMode); val.IsValid() && !isEmptyValue(val) {
3194+
transformed["mode"] = transformedMode
3195+
}
3196+
3197+
transformedDisruptionBudget, err := expandOSConfigPatchDeploymentRolloutDisruptionBudget(original["disruption_budget"], d, config)
3198+
if err != nil {
3199+
return nil, err
3200+
} else if val := reflect.ValueOf(transformedDisruptionBudget); val.IsValid() && !isEmptyValue(val) {
3201+
transformed["disruptionBudget"] = transformedDisruptionBudget
3202+
}
3203+
3204+
return transformed, nil
3205+
}
3206+
3207+
func expandOSConfigPatchDeploymentRolloutMode(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
3208+
return v, nil
3209+
}
3210+
3211+
func expandOSConfigPatchDeploymentRolloutDisruptionBudget(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
3212+
l := v.([]interface{})
3213+
if len(l) == 0 || l[0] == nil {
3214+
return nil, nil
3215+
}
3216+
raw := l[0]
3217+
original := raw.(map[string]interface{})
3218+
transformed := make(map[string]interface{})
3219+
3220+
transformedFixed, err := expandOSConfigPatchDeploymentRolloutDisruptionBudgetFixed(original["fixed"], d, config)
3221+
if err != nil {
3222+
return nil, err
3223+
} else if val := reflect.ValueOf(transformedFixed); val.IsValid() && !isEmptyValue(val) {
3224+
transformed["fixed"] = transformedFixed
3225+
}
3226+
3227+
transformedPercentage, err := expandOSConfigPatchDeploymentRolloutDisruptionBudgetPercentage(original["percentage"], d, config)
3228+
if err != nil {
3229+
return nil, err
3230+
} else if val := reflect.ValueOf(transformedPercentage); val.IsValid() && !isEmptyValue(val) {
3231+
transformed["percentage"] = transformedPercentage
3232+
}
3233+
3234+
return transformed, nil
3235+
}
3236+
3237+
func expandOSConfigPatchDeploymentRolloutDisruptionBudgetFixed(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
3238+
return v, nil
3239+
}
3240+
3241+
func expandOSConfigPatchDeploymentRolloutDisruptionBudgetPercentage(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
3242+
return v, nil
3243+
}
3244+
30553245
func resourceOSConfigPatchDeploymentEncoder(d *schema.ResourceData, meta interface{}, obj map[string]interface{}) (map[string]interface{}, error) {
30563246
schedule := obj["recurringSchedule"].(map[string]interface{})
30573247
if schedule["monthly"] != nil {

google-beta/resource_os_config_patch_deployment_generated_test.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,13 @@ resource "google_os_config_patch_deployment" "patch" {
286286
}
287287
}
288288
}
289+
290+
rollout {
291+
mode = "ZONE_BY_ZONE"
292+
disruption_budget {
293+
fixed = 1
294+
}
295+
}
289296
}
290297
`, context)
291298
}

website/docs/r/os_config_patch_deployment.html.markdown

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,13 @@ resource "google_os_config_patch_deployment" "patch" {
237237
}
238238
}
239239
}
240+
241+
rollout {
242+
mode = "ZONE_BY_ZONE"
243+
disruption_budget {
244+
fixed = 1
245+
}
246+
}
240247
}
241248
```
242249

@@ -320,6 +327,11 @@ The `group_labels` block supports:
320327
Schedule recurring executions.
321328
Structure is documented below.
322329

330+
* `rollout` -
331+
(Optional)
332+
Rollout strategy of the patch job.
333+
Structure is documented below.
334+
323335
* `project` - (Optional) The ID of the project in which the resource belongs.
324336
If it is not provided, the provider project is used.
325337

@@ -733,6 +745,33 @@ The `week_day_of_month` block supports:
733745
A day of the week.
734746
Possible values are `MONDAY`, `TUESDAY`, `WEDNESDAY`, `THURSDAY`, `FRIDAY`, `SATURDAY`, and `SUNDAY`.
735747

748+
The `rollout` block supports:
749+
750+
* `mode` -
751+
(Required)
752+
Mode of the patch rollout.
753+
Possible values are `ZONE_BY_ZONE` and `CONCURRENT_ZONES`.
754+
755+
* `disruption_budget` -
756+
(Required)
757+
The maximum number (or percentage) of VMs per zone to disrupt at any given moment. The number of VMs calculated from multiplying the percentage by the total number of VMs in a zone is rounded up.
758+
During patching, a VM is considered disrupted from the time the agent is notified to begin until patching has completed. This disruption time includes the time to complete reboot and any post-patch steps.
759+
A VM contributes to the disruption budget if its patching operation fails either when applying the patches, running pre or post patch steps, or if it fails to respond with a success notification before timing out. VMs that are not running or do not have an active agent do not count toward this disruption budget.
760+
For zone-by-zone rollouts, if the disruption budget in a zone is exceeded, the patch job stops, because continuing to the next zone requires completion of the patch process in the previous zone.
761+
For example, if the disruption budget has a fixed value of 10, and 8 VMs fail to patch in the current zone, the patch job continues to patch 2 VMs at a time until the zone is completed. When that zone is completed successfully, patching begins with 10 VMs at a time in the next zone. If 10 VMs in the next zone fail to patch, the patch job stops.
762+
Structure is documented below.
763+
764+
765+
The `disruption_budget` block supports:
766+
767+
* `fixed` -
768+
(Optional)
769+
Specifies a fixed value.
770+
771+
* `percentage` -
772+
(Optional)
773+
Specifies the relative value defined as a percentage, which will be multiplied by a reference value.
774+
736775
## Attributes Reference
737776

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

0 commit comments

Comments
 (0)