Skip to content

Commit

Permalink
Merge pull request #22745 from chef-partners/master
Browse files Browse the repository at this point in the history
Habitat License Acceptance changes
  • Loading branch information
Pam Selle authored Sep 9, 2019
2 parents fb1aefe + 50a6c69 commit 7a9f271
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 7 deletions.
40 changes: 39 additions & 1 deletion builtin/provisioners/habitat/resource_provisioner.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"strings"
"text/template"

version "github.com/hashicorp/go-version"
"github.com/hashicorp/terraform/communicator"
"github.com/hashicorp/terraform/communicator/remote"
"github.com/hashicorp/terraform/helper/schema"
Expand Down Expand Up @@ -60,6 +61,7 @@ type provisioner struct {
Organization string
BuilderAuthToken string
SupOptions string
AcceptLicense bool
}

func Provisioner() terraform.ResourceProvisioner {
Expand Down Expand Up @@ -88,6 +90,10 @@ func Provisioner() terraform.ResourceProvisioner {
Optional: true,
Default: true,
},
"accept_license": &schema.Schema{
Type: schema.TypeBool,
Required: true,
},
"permanent_peer": &schema.Schema{
Type: schema.TypeBool,
Optional: true,
Expand Down Expand Up @@ -290,6 +296,26 @@ func validateFn(c *terraform.ResourceConfig) (ws []string, es []error) {
}
}

v, ok := c.Get("version")
if ok && v != nil && strings.TrimSpace(v.(string)) != "" {
if _, err := version.NewVersion(v.(string)); err != nil {
es = append(es, errors.New(v.(string)+" is not a valid version."))
}
}

acceptLicense, ok := c.Get("accept_license")
if ok && !acceptLicense.(bool) {
if v != nil && strings.TrimSpace(v.(string)) != "" {
versionOld, _ := version.NewVersion("0.79.0")
versionRequired, _ := version.NewVersion(v.(string))
if versionRequired.GreaterThan(versionOld) {
es = append(es, errors.New("Habitat end user license agreement needs to be accepted, set the accept_license argument to true to accept"))
}
} else { // blank means latest version
es = append(es, errors.New("Habitat end user license agreement needs to be accepted, set the accept_license argument to true to accept"))
}
}

// Validate service level configs
services, ok := c.Get("service")
if ok {
Expand All @@ -299,7 +325,6 @@ func validateFn(c *terraform.ResourceConfig) (ws []string, es []error) {
es = append(es, fmt.Errorf("service %d: must be a block", i))
continue
}

strategy, ok := service["strategy"].(string)
if ok && !updateStrategies[strategy] {
es = append(es, errors.New(strategy+" is not a valid update strategy."))
Expand Down Expand Up @@ -357,6 +382,7 @@ func decodeConfig(d *schema.ResourceData) (*provisioner, error) {
Peer: d.Get("peer").(string),
Services: getServices(d.Get("service").(*schema.Set).List()),
UseSudo: d.Get("use_sudo").(bool),
AcceptLicense: d.Get("accept_license").(bool),
ServiceType: d.Get("service_type").(string),
ServiceName: d.Get("service_name").(string),
RingKey: d.Get("ring_key").(string),
Expand Down Expand Up @@ -467,6 +493,17 @@ func (p *provisioner) installHab(o terraform.UIOutput, comm communicator.Communi
return err
}

// Accept the license
if p.AcceptLicense {
command = fmt.Sprintf("export HAB_LICENSE=accept; hab -V")
if p.UseSudo {
command = fmt.Sprintf("sudo HAB_LICENSE=accept hab -V")
}
if err := p.runCommand(o, comm, command); err != nil {
return err
}
}

if err := p.createHabUser(o, comm); err != nil {
return err
}
Expand Down Expand Up @@ -608,6 +645,7 @@ func (p *provisioner) createHabUser(o terraform.UIOutput, comm communicator.Comm
if p.UseSudo {
command = fmt.Sprintf("sudo %s", command)
}

if err := p.runCommand(o, comm, command); err != nil {
return err
}
Expand Down
13 changes: 8 additions & 5 deletions builtin/provisioners/habitat/resource_provisioner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ func TestProvisioner(t *testing.T) {

func TestResourceProvisioner_Validate_good(t *testing.T) {
c := testConfig(t, map[string]interface{}{
"peer": "1.2.3.4",
"version": "0.32.0",
"service_type": "systemd",
"peer": "1.2.3.4",
"version": "0.32.0",
"service_type": "systemd",
"accept_license": false,
})

warn, errs := Provisioner().Validate(c)
Expand All @@ -42,13 +43,15 @@ func TestResourceProvisioner_Validate_bad(t *testing.T) {
if len(warn) > 0 {
t.Fatalf("Warnings: %v", warn)
}
if len(errs) != 1 {
t.Fatalf("Should have one error")
//Two errors, one for service_type, other for missing required accept_license argument
if len(errs) != 2 {
t.Fatalf("Should have one errors, got %d", len(errs))
}
}

func TestResourceProvisioner_Validate_bad_service_config(t *testing.T) {
c := testConfig(t, map[string]interface{}{
"accept_license": true,
"service": []interface{}{
map[string]interface{}{
"name": "core/foo",
Expand Down
3 changes: 3 additions & 0 deletions website/docs/provisioners/chef.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ The `chef` provisioner has some prerequisites for specific connection types:
* For `ssh` type connections, `cURL` must be available on the remote host.
* For `winrm` connections, `PowerShell 2.0` must be available on the remote host.

[Chef end user license agreement](https://www.chef.io/end-user-license-agreement/) must be accepted by setting `chef_license` to `accept` in `client_options` argument unless you are installing an old version of Chef client.

Without these prerequisites, your provisioning execution will fail.

## Example usage
Expand All @@ -47,6 +49,7 @@ resource "aws_instance" "web" {
EOF
environment = "_default"
client_options = ["chef_license 'accept'"]
run_list = ["cookbook::recipe"]
node_name = "webserver1"
secret_key = "${file("../encrypted_data_bag_secret")}"
Expand Down
4 changes: 3 additions & 1 deletion website/docs/provisioners/habitat.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ resource "aws_instance" "redis" {
peer = "${aws_instance.redis.0.private_ip}"
use_sudo = true
service_type = "systemd"
accept_license = true
service {
name = "core/redis"
Expand All @@ -51,6 +52,7 @@ resource "aws_instance" "redis" {
There are 2 configuration levels, `supervisor` and `service`. Configuration placed directly within the `provisioner` block are supervisor configurations, and a provisioner can define zero or more services to run, and each service will have a `service` block within the `provisioner`. A `service` block can also contain zero or more `bind` blocks to create service group bindings.

### Supervisor Arguments
* `accept_license (bool)` - (Required) Set to true to accept [Habitat end user license agreement](https://www.chef.io/end-user-license-agreement/)
* `version (string)` - (Optional) The Habitat version to install on the remote machine. If not specified, the latest available version is used.
* `use_sudo (bool)` - (Optional) Use `sudo` when executing remote commands. Required when the user specified in the `connection` block is not `root`. (Defaults to `true`)
* `service_type (string)` - (Optional) Method used to run the Habitat supervisor. Valid options are `unmanaged` and `systemd`. (Defaults to `systemd`)
Expand Down Expand Up @@ -89,4 +91,4 @@ bind {
* `application (string)` - (Optional) The application name. (Defaults to none)
* `environment (string)` - (Optional) The environment name. (Defaults to none)
* `override_name (string)` - (Optional) The name for the state directory if there is more than one Supervisor running. (Defaults to `default`)
* `service_key (string)` - (Optional) The key content of a service private key, if using service group encryption. Easiest to source from a file (eg `service_key = "${file("conf/redis.default@org-123456789.box.key")}"`) (Defaults to none)
* `service_key (string)` - (Optional) The key content of a service private key, if using service group encryption. Easiest to source from a file (eg `service_key = "${file("conf/redis.default@org-123456789.box.key")}"`) (Defaults to none)

0 comments on commit 7a9f271

Please # to comment.