Refactor the code a bit to make it more idiomatic

This commit is contained in:
Sander van Harmelen 2020-05-01 11:05:08 +02:00 committed by Brian Dwyer
parent 2f4067cf70
commit a614056925
3 changed files with 67 additions and 66 deletions

View File

@ -106,7 +106,7 @@ type provisioner struct {
OSType string OSType string
RecreateClient bool RecreateClient bool
PreventSudo bool PreventSudo bool
RetryOnExitCode []int RetryOnExitCode map[int]bool
RunList []string RunList []string
SecretKey string SecretKey string
ServerURL string ServerURL string
@ -117,7 +117,7 @@ type provisioner struct {
UserKey string UserKey string
Vaults map[string][]string Vaults map[string][]string
Version string Version string
WaitForRetry int WaitForRetry time.Duration
cleanupUserKeyCmd string cleanupUserKeyCmd string
createConfigFiles provisionFn createConfigFiles provisionFn
@ -334,10 +334,6 @@ func applyFn(ctx context.Context) error {
retryCtx, cancel := context.WithTimeout(ctx, comm.Timeout()) retryCtx, cancel := context.WithTimeout(ctx, comm.Timeout())
defer cancel() defer cancel()
// Graceful retry of RFC062 exit codes
var attempt int
retry:
// Wait and retry until we establish the connection // Wait and retry until we establish the connection
err = communicator.Retry(retryCtx, func() error { err = communicator.Retry(retryCtx, func() error {
return comm.Connect(o) return comm.Connect(o)
@ -357,55 +353,65 @@ retry:
} }
defer once.Do(cleanupUserKey) defer once.Do(cleanupUserKey)
if attempt == 0 { if !p.SkipInstall {
if !p.SkipInstall { if err := p.installChefClient(o, comm); err != nil {
if err := p.installChefClient(o, comm); err != nil { return err
}
}
o.Output("Creating configuration files...")
if err := p.createConfigFiles(o, comm); err != nil {
return err
}
if !p.SkipRegister {
if p.FetchChefCertificates {
o.Output("Fetch Chef certificates...")
if err := p.fetchChefCertificates(o, comm); err != nil {
return err return err
} }
} }
o.Output("Creating configuration files...") o.Output("Generate the private key...")
if err := p.createConfigFiles(o, comm); err != nil { if err := p.generateClientKey(o, comm); err != nil {
return err
}
}
if p.Vaults != nil {
o.Output("Configure Chef vaults...")
if err := p.configureVaults(o, comm); err != nil {
return err
}
}
// Cleanup the user key before we run Chef-Client to prevent issues
// with rights caused by changing settings during the run.
once.Do(cleanupUserKey)
o.Output("Starting initial Chef-Client run...")
for attempt := 0; attempt < p.MaxRetries; attempt++ {
// Make sure to (re)connect before trying to run Chef-Client.
if err := communicator.Retry(retryCtx, func() error {
return comm.Connect(o)
}); err != nil {
return err return err
} }
if !p.SkipRegister { err = p.runChefClient(o, comm)
if p.FetchChefCertificates { if err == nil {
o.Output("Fetch Chef certificates...") return nil
if err := p.fetchChefCertificates(o, comm); err != nil {
return err
}
}
o.Output("Generate the private key...")
if err := p.generateClientKey(o, comm); err != nil {
return err
}
} }
if p.Vaults != nil { // Allow RFC062 Exit Codes:
o.Output("Configure Chef vaults...")
if err := p.configureVaults(o, comm); err != nil {
return err
}
}
// Cleanup the user key before we run Chef-Client to prevent issues
// with rights caused by changing settings during the run.
once.Do(cleanupUserKey)
o.Output("Starting initial Chef-Client run...")
}
if err := p.runChefClient(o, comm); err != nil {
// Allow RFC062 Exit Codes
// https://github.com/chef/chef-rfc/blob/master/rfc062-exit-status.md // https://github.com/chef/chef-rfc/blob/master/rfc062-exit-status.md
exitError, ok := err.(*remote.ExitError) exitError, ok := err.(*remote.ExitError)
if !ok { if !ok {
return fmt.Errorf("Expected remote.ExitError but got: %w", err) return err
} }
exitStatus := exitError.ExitStatus
switch exitStatus { switch exitError.ExitStatus {
case 35: case 35:
o.Output("Reboot has been scheduled in the run state") o.Output("Reboot has been scheduled in the run state")
err = nil err = nil
@ -417,23 +423,13 @@ retry:
err = nil err = nil
} }
if len(p.RetryOnExitCode) == 0 || attempt == p.MaxRetries { if p.RetryOnExitCode[exitError.ExitStatus] {
return err o.Output(fmt.Sprintf("Waiting %s before retrying Chef-Client run...", p.WaitForRetry))
time.Sleep(p.WaitForRetry)
} }
for _, code := range p.RetryOnExitCode {
if code == exitStatus {
o.Output(fmt.Sprintf("Waiting %v seconds before reconnecting & re-running Chef...", p.WaitForRetry))
time.Sleep(time.Duration(p.WaitForRetry) * time.Second)
attempt++
goto retry
}
}
return err
} }
return nil return err
} }
func validateFn(c *terraform.ResourceConfig) (ws []string, es []error) { func validateFn(c *terraform.ResourceConfig) (ws []string, es []error) {
@ -795,7 +791,7 @@ func decodeConfig(d *schema.ResourceData) (*provisioner, error) {
OSType: d.Get("os_type").(string), OSType: d.Get("os_type").(string),
RecreateClient: d.Get("recreate_client").(bool), RecreateClient: d.Get("recreate_client").(bool),
PreventSudo: d.Get("prevent_sudo").(bool), PreventSudo: d.Get("prevent_sudo").(bool),
RetryOnExitCode: getIntList(d.Get("retry_on_exit_code")), RetryOnExitCode: getIntListAsMap(d.Get("retry_on_exit_code")),
RunList: getStringList(d.Get("run_list")), RunList: getStringList(d.Get("run_list")),
SecretKey: d.Get("secret_key").(string), SecretKey: d.Get("secret_key").(string),
ServerURL: d.Get("server_url").(string), ServerURL: d.Get("server_url").(string),
@ -805,7 +801,7 @@ func decodeConfig(d *schema.ResourceData) (*provisioner, error) {
UserName: d.Get("user_name").(string), UserName: d.Get("user_name").(string),
UserKey: d.Get("user_key").(string), UserKey: d.Get("user_key").(string),
Version: d.Get("version").(string), Version: d.Get("version").(string),
WaitForRetry: d.Get("wait_for_retry").(int), WaitForRetry: time.Duration(d.Get("wait_for_retry").(int)) * time.Second,
} }
// Make sure the supplied URL has a trailing slash // Make sure the supplied URL has a trailing slash
@ -855,8 +851,8 @@ func decodeConfig(d *schema.ResourceData) (*provisioner, error) {
return p, nil return p, nil
} }
func getIntList(v interface{}) []int { func getIntListAsMap(v interface{}) map[int]bool {
var result []int result := make(map[int]bool)
switch v := v.(type) { switch v := v.(type) {
case nil: case nil:
@ -864,7 +860,7 @@ func getIntList(v interface{}) []int {
case []interface{}: case []interface{}:
for _, vv := range v { for _, vv := range v {
if vv, ok := vv.(int); ok { if vv, ok := vv.(int); ok {
result = append(result, vv) result[vv] = true
} }
} }
return result return result

View File

@ -58,7 +58,7 @@ func (c *Communicator) Connect(o terraform.UIOutput) error {
params := winrm.DefaultParameters params := winrm.DefaultParameters
params.Timeout = formatDuration(c.Timeout()) params.Timeout = formatDuration(c.Timeout())
if c.connInfo.NTLM == true { if c.connInfo.NTLM {
params.TransportDecorator = func() winrm.Transporter { return &winrm.ClientNTLM{} } params.TransportDecorator = func() winrm.Transporter { return &winrm.ClientNTLM{} }
} }
@ -189,7 +189,7 @@ func (c *Communicator) newCopyClient() (*winrmcp.Winrmcp, error) {
MaxOperationsPerShell: 15, // lowest common denominator MaxOperationsPerShell: 15, // lowest common denominator
} }
if c.connInfo.NTLM == true { if c.connInfo.NTLM {
config.TransportDecorator = func() winrm.Transporter { return &winrm.ClientNTLM{} } config.TransportDecorator = func() winrm.Transporter { return &winrm.ClientNTLM{} }
} }

View File

@ -111,7 +111,8 @@ The following arguments are supported:
* `https_proxy (string)` - (Optional) The proxy server for Chef Client HTTPS connections. * `https_proxy (string)` - (Optional) The proxy server for Chef Client HTTPS connections.
* `max_retries (integer)` - (Optional) The number of times to retry the provisioning process after receiving an exit code in the `retry_on_error` list. Defaults to `1` * `max_retries (integer)` - (Optional) The number of times to retry the provisioning process
after receiving an exit code in the `retry_on_error` list. Defaults to `1`
* `named_run_list (string)` - (Optional) The name of an alternate run-list to invoke during the * `named_run_list (string)` - (Optional) The name of an alternate run-list to invoke during the
initial Chef Client run. The run-list must already exist in the Policyfile that defines initial Chef Client run. The run-list must already exist in the Policyfile that defines
@ -135,7 +136,9 @@ The following arguments are supported:
* `recreate_client (boolean)` - (Optional) If `true`, first delete any existing Chef Node and * `recreate_client (boolean)` - (Optional) If `true`, first delete any existing Chef Node and
Client before registering the new Chef Client. Client before registering the new Chef Client.
* `retry_on_error (list of integers)` - (Optional) The error codes upon which Terraform should gracefully retry the provisioning process. Intended for use with [Chef RFC062 codes.](https://github.com/chef-boneyard/chef-rfc/blob/69a19f632cceffe965bafaad6765e3376068fd5b/rfc062-exit-status.md) * `retry_on_error (list of integers)` - (Optional) The error codes upon which Terraform should
gracefully retry the provisioning process. Intended for use with
[Chef RFC062 codes](https://github.com/chef-boneyard/chef-rfc/blob/master/rfc062-exit-status.md).
* `run_list (array)` - (Optional) A list with recipes that will be invoked during the initial * `run_list (array)` - (Optional) A list with recipes that will be invoked during the initial
Chef Client run. The run-list will also be saved to the Chef Server after a successful Chef Client run. The run-list will also be saved to the Chef Server after a successful
@ -176,4 +179,6 @@ The following arguments are supported:
* `version (string)` - (Optional) The Chef Client version to install on the remote machine. * `version (string)` - (Optional) The Chef Client version to install on the remote machine.
If not set, the latest available version will be installed. If not set, the latest available version will be installed.
* `wait_for_retry (integer)` - (Optional) - Amount of time in seconds to wait before retrying the provisionining process after receiving an exit code in the `retry_on_error` list. Defaults to `30`. * `wait_for_retry (integer)` - (Optional) - Amount of time in seconds to wait before
retrying the provisionining process after receiving an exit code in the `retry_on_error`
list. Defaults to `30`.