Merge pull request #3896 from hashicorp/phinze/chef-keys-as-contents

chef: read key contents instead of paths
This commit is contained in:
Sander van Harmelen 2015-11-16 21:44:09 +01:00
commit 0cdc81f390
3 changed files with 53 additions and 42 deletions

View File

@ -8,7 +8,7 @@ import (
"io"
"log"
"os"
"path"
"path/filepath"
"regexp"
"strings"
"text/template"
@ -16,6 +16,7 @@ import (
"github.com/hashicorp/terraform/communicator"
"github.com/hashicorp/terraform/communicator/remote"
"github.com/hashicorp/terraform/helper/pathorcontents"
"github.com/hashicorp/terraform/terraform"
"github.com/mitchellh/go-homedir"
"github.com/mitchellh/go-linereader"
@ -79,18 +80,22 @@ type Provisioner struct {
OSType string `mapstructure:"os_type"`
PreventSudo bool `mapstructure:"prevent_sudo"`
RunList []string `mapstructure:"run_list"`
SecretKeyPath string `mapstructure:"secret_key_path"`
SecretKey string `mapstructure:"secret_key"`
ServerURL string `mapstructure:"server_url"`
SkipInstall bool `mapstructure:"skip_install"`
SSLVerifyMode string `mapstructure:"ssl_verify_mode"`
ValidationClientName string `mapstructure:"validation_client_name"`
ValidationKeyPath string `mapstructure:"validation_key_path"`
ValidationKey string `mapstructure:"validation_key"`
Version string `mapstructure:"version"`
installChefClient func(terraform.UIOutput, communicator.Communicator) error
createConfigFiles func(terraform.UIOutput, communicator.Communicator) error
runChefClient func(terraform.UIOutput, communicator.Communicator) error
useSudo bool
// Deprecated Fields
SecretKeyPath string `mapstructure:"secret_key_path"`
ValidationKeyPath string `mapstructure:"validation_key_path"`
}
// ResourceProvisioner represents a generic chef provisioner
@ -189,8 +194,9 @@ func (r *ResourceProvisioner) Validate(c *terraform.ResourceConfig) (ws []string
if p.ValidationClientName == "" {
es = append(es, fmt.Errorf("Key not found: validation_client_name"))
}
if p.ValidationKeyPath == "" {
es = append(es, fmt.Errorf("Key not found: validation_key_path"))
if p.ValidationKey == "" && p.ValidationKeyPath == "" {
es = append(es, fmt.Errorf(
"One of validation_key or the deprecated validation_key_path must be provided"))
}
if p.UsePolicyfile && p.PolicyName == "" {
es = append(es, fmt.Errorf("Policyfile enabled but key not found: policy_name"))
@ -198,6 +204,14 @@ func (r *ResourceProvisioner) Validate(c *terraform.ResourceConfig) (ws []string
if p.UsePolicyfile && p.PolicyGroup == "" {
es = append(es, fmt.Errorf("Policyfile enabled but key not found: policy_group"))
}
if p.ValidationKeyPath != "" {
ws = append(ws, "validation_key_path is deprecated, please use "+
"validation_key instead and load the key contents via file()")
}
if p.SecretKeyPath != "" {
ws = append(ws, "secret_key_path is deprecated, please use "+
"secret_key instead and load the key contents via file()")
}
return ws, es
}
@ -247,20 +261,12 @@ func (r *ResourceProvisioner) decodeConfig(c *terraform.ResourceConfig) (*Provis
p.OhaiHints[i] = hintPath
}
if p.ValidationKeyPath != "" {
keyPath, err := homedir.Expand(p.ValidationKeyPath)
if err != nil {
return nil, fmt.Errorf("Error expanding the validation key path: %v", err)
}
p.ValidationKeyPath = keyPath
if p.ValidationKey == "" && p.ValidationKeyPath != "" {
p.ValidationKey = p.ValidationKeyPath
}
if p.SecretKeyPath != "" {
keyPath, err := homedir.Expand(p.SecretKeyPath)
if err != nil {
return nil, fmt.Errorf("Error expanding the secret key path: %v", err)
}
p.SecretKeyPath = keyPath
if p.SecretKey == "" && p.SecretKeyPath != "" {
p.SecretKey = p.SecretKeyPath
}
if attrs, ok := c.Config["attributes"]; ok {
@ -316,7 +322,7 @@ func (p *Provisioner) runChefClientFunc(
chefCmd string,
confDir string) func(terraform.UIOutput, communicator.Communicator) error {
return func(o terraform.UIOutput, comm communicator.Communicator) error {
fb := path.Join(confDir, firstBoot)
fb := filepath.Join(confDir, firstBoot)
var cmd string
// Policyfiles do not support chef environments, so don't pass the `-E` flag.
@ -331,8 +337,8 @@ func (p *Provisioner) runChefClientFunc(
return fmt.Errorf("Error creating logfile directory %s: %v", logfileDir, err)
}
logFile := path.Join(logfileDir, p.NodeName)
f, err := os.Create(path.Join(logFile))
logFile := filepath.Join(logfileDir, p.NodeName)
f, err := os.Create(filepath.Join(logFile))
if err != nil {
return fmt.Errorf("Error creating logfile %s: %v", logFile, err)
}
@ -348,7 +354,7 @@ func (p *Provisioner) runChefClientFunc(
// Output implementation of terraform.UIOutput interface
func (p *Provisioner) Output(output string) {
logFile := path.Join(logfileDir, p.NodeName)
logFile := filepath.Join(logfileDir, p.NodeName)
f, err := os.OpenFile(logFile, os.O_APPEND|os.O_WRONLY, 0666)
if err != nil {
log.Printf("Error creating logfile %s: %v", logFile, err)
@ -376,28 +382,25 @@ func (p *Provisioner) deployConfigFiles(
o terraform.UIOutput,
comm communicator.Communicator,
confDir string) error {
// Open the validation key file
f, err := os.Open(p.ValidationKeyPath)
contents, _, err := pathorcontents.Read(p.ValidationKey)
if err != nil {
return err
}
defer f.Close()
f := strings.NewReader(contents)
// Copy the validation key to the new instance
if err := comm.Upload(path.Join(confDir, validationKey), f); err != nil {
if err := comm.Upload(filepath.Join(confDir, validationKey), f); err != nil {
return fmt.Errorf("Uploading %s failed: %v", validationKey, err)
}
if p.SecretKeyPath != "" {
// Open the secret key file
s, err := os.Open(p.SecretKeyPath)
if p.SecretKey != "" {
contents, _, err := pathorcontents.Read(p.SecretKey)
if err != nil {
return err
}
defer s.Close()
s := strings.NewReader(contents)
// Copy the secret key to the new instance
if err := comm.Upload(path.Join(confDir, secretKey), s); err != nil {
if err := comm.Upload(filepath.Join(confDir, secretKey), s); err != nil {
return fmt.Errorf("Uploading %s failed: %v", secretKey, err)
}
}
@ -417,7 +420,7 @@ func (p *Provisioner) deployConfigFiles(
}
// Copy the client config to the new instance
if err := comm.Upload(path.Join(confDir, clienrb), &buf); err != nil {
if err := comm.Upload(filepath.Join(confDir, clienrb), &buf); err != nil {
return fmt.Errorf("Uploading %s failed: %v", clienrb, err)
}
@ -446,7 +449,7 @@ func (p *Provisioner) deployConfigFiles(
}
// Copy the first-boot.json to the new instance
if err := comm.Upload(path.Join(confDir, firstBoot), bytes.NewReader(d)); err != nil {
if err := comm.Upload(filepath.Join(confDir, firstBoot), bytes.NewReader(d)); err != nil {
return fmt.Errorf("Uploading %s failed: %v", firstBoot, err)
}
@ -466,8 +469,8 @@ func (p *Provisioner) deployOhaiHints(
defer f.Close()
// Copy the hint to the new instance
if err := comm.Upload(path.Join(hintDir, path.Base(hint)), f); err != nil {
return fmt.Errorf("Uploading %s failed: %v", path.Base(hint), err)
if err := comm.Upload(filepath.Join(hintDir, filepath.Base(hint)), f); err != nil {
return fmt.Errorf("Uploading %s failed: %v", filepath.Base(hint), err)
}
}

View File

@ -22,7 +22,7 @@ func TestResourceProvider_Validate_good(t *testing.T) {
"run_list": []interface{}{"cookbook::recipe"},
"server_url": "https://chef.local",
"validation_client_name": "validator",
"validation_key_path": "validator.pem",
"validation_key": "contentsofsomevalidator.pem",
})
r := new(ResourceProvisioner)
warn, errs := r.Validate(c)

View File

@ -36,10 +36,10 @@ resource "aws_instance" "web" {
environment = "_default"
run_list = ["cookbook::recipe"]
node_name = "webserver1"
secret_key_path = "../encrypted_data_bag_secret"
secret_key = "${file("../encrypted_data_bag_secret")}"
server_url = "https://chef.company.com/organizations/org1"
validation_client_name = "chef-validator"
validation_key_path = "../chef-validator.pem"
validation_key = "${file("../chef-validator.pem")}"
version = "12.4.1"
}
}
@ -83,9 +83,10 @@ The following arguments are supported:
Chef Client run. The run-list will also be saved to the Chef Server after a successful
initial run.
* `secret_key_path (string)` - (Optional) The path to the secret key that is used
* `secret_key (string)` - (Optional) The contents of the secret key that is used
by the client to decrypt data bags on the Chef Server. The key will be uploaded to the remote
machine.
machine. These can be loaded from a file on disk using the [`file()` interpolation
function](/docs/configuration/interpolation.html#file_path_).
* `server_url (string)` - (Required) The URL to the Chef server. This includes the path to
the organization. See the example.
@ -100,9 +101,16 @@ The following arguments are supported:
* `validation_client_name (string)` - (Required) The name of the validation client to use
for the initial communication with the Chef Server.
* `validation_key_path (string)` - (Required) The path to the validation key that is needed
* `validation_key (string)` - (Required) The contents of the validation key that is needed
by the node to register itself with the Chef Server. The key will be uploaded to the remote
machine.
machine. These can be loaded from a file on disk using the [`file()`
interpolation function](/docs/configuration/interpolation.html#file_path_).
* `version (string)` - (Optional) The Chef Client version to install on the remote machine.
If not set the latest available version will be installed.
These are supported for backwards compatibility and may be removed in a
future version:
* `validation_key_path (string)` - __Deprecated: please use `validation_key` instead__.
* `secret_key_path (string)` - __Deprecated: please use `secret_key` instead__.