-
Notifications
You must be signed in to change notification settings - Fork 71
Add instance_max_run_duration_seconds config #242
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -217,6 +217,11 @@ type Config struct { | |
| OnHostMaintenance string `mapstructure:"on_host_maintenance" required:"false"` | ||
| // If true, launch a preemptible instance. | ||
| Preemptible bool `mapstructure:"preemptible" required:"false"` | ||
| // If set, the instance will be automatically terminated after the specified amount of seconds. | ||
| // instance_termination_action must be set if this property is set. | ||
| InstanceMaxRunDurationSeconds int64 `mapstructure:"instance_max_run_duration_seconds" required:"false"` | ||
| // The termination action for this VM, which can be either STOP or DELETE. | ||
| InstanceTerminationAction string `mapstructure:"instance_termination_action" required:"false"` | ||
| // Sets a node affinity label for the launched instance (eg. for sole tenancy). | ||
| // Please see [Provisioning VMs on | ||
| // sole-tenant nodes](https://cloud.google.com/compute/docs/nodes/provisioning-sole-tenant-vms) | ||
|
|
@@ -632,6 +637,18 @@ func (c *Config) Prepare(raws ...interface{}) ([]string, error) { | |
| c.WindowsPasswordTimeout = 3 * time.Minute | ||
| } | ||
|
|
||
| if c.InstanceMaxRunDurationSeconds < 0 { | ||
| errs = packersdk.MultiErrorAppend(fmt.Errorf("'instance_max_run_duration_seconds' must be positive")) | ||
| } | ||
|
|
||
| if c.InstanceMaxRunDurationSeconds > 0 && c.InstanceTerminationAction == "" { | ||
| errs = packersdk.MultiErrorAppend(fmt.Errorf("'instance_termination_action' must be set if 'instance_max_run_duration_seconds' is set")) | ||
| } | ||
|
|
||
| if c.InstanceTerminationAction != "" && !(c.InstanceTerminationAction == "STOP" || c.InstanceTerminationAction == "DELETE") { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It might be worth adding constants for these values. that aside would it make sense to defaulting to STOP after x days. |
||
| errs = packersdk.MultiErrorAppend(fmt.Errorf("'instance_termination_action' must be 'STOP' or 'DELETE'")) | ||
| } | ||
|
|
||
| return warnings, errs | ||
| } | ||
|
|
||
|
|
||
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -712,6 +712,72 @@ func TestConfigPrepareImageArchitecture(t *testing.T) { | |
| } | ||
| } | ||
|
|
||
| func TestConfigInstanceMaxRunDurationSeconds(t *testing.T) { | ||
| cases := []struct { | ||
| Keys []string | ||
| Values []interface{} | ||
| Err bool | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Very nitpicky but in terms of self-documentation, it would imho be better if this field was called |
||
| }{ | ||
| { | ||
| []string{"instance_max_run_duration_seconds", "instance_termination_action"}, | ||
| []interface{}{5, "STOP"}, | ||
| false, | ||
| }, | ||
| { | ||
| []string{"instance_max_run_duration_seconds", "instance_termination_action"}, | ||
| []interface{}{5, "DELETE"}, | ||
| false, | ||
| }, | ||
| { | ||
| []string{"instance_max_run_duration_seconds"}, | ||
| []interface{}{1}, | ||
| true, | ||
| }, | ||
| { | ||
| []string{"instance_max_run_duration_seconds"}, | ||
| []interface{}{-1}, | ||
| false, | ||
| }, | ||
| { | ||
| []string{"instance_max_run_duration_seconds", "instance_termination_action"}, | ||
| []interface{}{5, "BAD_VALUE"}, | ||
| true, | ||
| }, | ||
| { | ||
| []string{"instance_max_run_duration_seconds", "instance_termination_action"}, | ||
| []interface{}{5, ""}, | ||
| true, | ||
| }, | ||
| } | ||
|
|
||
| for _, tc := range cases { | ||
| raw, tempfile := testConfig(t) | ||
| defer os.Remove(tempfile) | ||
|
|
||
| errStr := "" | ||
| for k := range tc.Keys { | ||
|
|
||
| // Create the string for error reporting | ||
| // convert value to string if it can be converted | ||
| errStr += fmt.Sprintf("%s:%v, ", tc.Keys[k], tc.Values[k]) | ||
| if tc.Values[k] == nil { | ||
| delete(raw, tc.Keys[k]) | ||
| } else { | ||
| raw[tc.Keys[k]] = tc.Values[k] | ||
| } | ||
| } | ||
|
|
||
| var c Config | ||
| warns, errs := c.Prepare(raw) | ||
|
|
||
| if tc.Err { | ||
| testConfigErr(t, warns, errs, strings.TrimRight(errStr, ", ")) | ||
| } else { | ||
| testConfigOk(t, warns, errs) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // Helper stuff below | ||
|
|
||
| func testConfig(t *testing.T) (config map[string]interface{}, tempAccountFile string) { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My suggestion here would be to include a high default value and possibly validate the the provided value is not lower than the default timeouts set for SSH or other Packer processes. To avoid terminating the machine before establishing a connection. It might not be so straightforward to know all the timeouts so I would suggest documenting it as well. Within the configuration option that at minimum the value should be set to X number of seconds. Possibly even hours or days.
I’ll leave this question for @lbajolet-hashicorp Should this be an unsigned int?
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems that if it is not straightforward to know all the timeouts, setting a high default without checking the other config values would be the best path forward to me. I could set the default to something like 2 days and add documentation to the config values. I also like the idea of setting the default termination option to
STOPso I'll add that.Probably. I don't believe that
maxRunDurationcan be negative.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah regarding the timeout situation I tend to agree with @phoenixuprising, it will be tricky to infer a good value here, especially since things can be set from other attributes, and having something that is coherent and long-term viable is troublesome.
I do agree that this could be a
uint, but I assume the rationale for it being anint64is because it is the type expected by the SDK/API? I don't mind this being either personally, but if we're dealing with a signed number, I would suggest adding a sanity check duringPrepareto make sure it is always positive, as is the case in the current state of the code.Note: an argument could still be made in favour of a
uinthere, as then the type explicitly prevents negative values, so later changes in the codebase bear less risk of unintentional breakage, ultimately the choice is yours @phoenixuprising.I like the idea of having a high enough default value, you suggest 2 days, I would even go lower and suggest something like 1 day, I would think this is reasonable enough for the vast majority of our users, and will fix that problem automagically for everyone.
Regarding the default termination option, I wonder if
STOPis the right default here though, my read on this is that we want to reduce cost if a build gets stuck for too long, therefore I would maybe go withDELETEas the default option, so the instance is wiped if this happens, as to not incur extra cost.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note: if we pick a non-zero default value here, we should probably amend the documentation for the attribute so the default value is clearly stated, along with a way to disable that behaviour.