Merge branch 'master' of github.com:hashicorp/terraform
* 'master' of github.com:hashicorp/terraform: provider/datadog: Update to datadog_monitor still used d.GetOk (#12497) Check instance is running before trying to attach (#12459) Fix aws_dms_replication_task diff for json with whitespace. (#12380) add "name" to exported attributes (#12483) provider/aws: Adding an acceptance test to for ForceNew on ecs_task_definition volumes provider/aws: (#10587) Changing volumes in ECS task definition should force new revision. provider/aws: Change aws_spot_fleet_request tests to use the correct hash values in test cases Small doc updates (#12165) Improve description of consul_catalog_entry (#12162) provider/aws: Only send iops when creating io1 devices. Fix docs (#12392) provider/google: initial commit for node pool resource (#11802) Fix spurious user_data diffs Properly handle 'vpc_security_group_ids', drop phantom 'security_groups' Default 'ebs_optimized' and 'monitoring' to false
This commit is contained in:
commit
71c0c27b1e
|
@ -1,6 +1,8 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
|
@ -42,3 +44,17 @@ func suppressAwsDbEngineVersionDiffs(k, old, new string, d *schema.ResourceData)
|
|||
// Throw a diff by default
|
||||
return false
|
||||
}
|
||||
|
||||
func suppressEquivalentJsonDiffs(k, old, new string, d *schema.ResourceData) bool {
|
||||
ob := bytes.NewBufferString("")
|
||||
if err := json.Compact(ob, []byte(old)); err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
nb := bytes.NewBufferString("")
|
||||
if err := json.Compact(nb, []byte(new)); err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return jsonBytesEqual(ob.Bytes(), nb.Bytes())
|
||||
}
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
)
|
||||
|
||||
func TestSuppressEquivalentJsonDiffsWhitespaceAndNoWhitespace(t *testing.T) {
|
||||
d := new(schema.ResourceData)
|
||||
|
||||
noWhitespace := `{"test":"test"}`
|
||||
whitespace := `
|
||||
{
|
||||
"test": "test"
|
||||
}`
|
||||
|
||||
if !suppressEquivalentJsonDiffs("", noWhitespace, whitespace, d) {
|
||||
t.Errorf("Expected suppressEquivalentJsonDiffs to return true for %s == %s", noWhitespace, whitespace)
|
||||
}
|
||||
|
||||
noWhitespaceDiff := `{"test":"test"}`
|
||||
whitespaceDiff := `
|
||||
{
|
||||
"test": "tested"
|
||||
}`
|
||||
|
||||
if suppressEquivalentJsonDiffs("", noWhitespaceDiff, whitespaceDiff, d) {
|
||||
t.Errorf("Expected suppressEquivalentJsonDiffs to return false for %s == %s", noWhitespaceDiff, whitespaceDiff)
|
||||
}
|
||||
}
|
|
@ -57,9 +57,10 @@ func resourceAwsDmsReplicationTask() *schema.Resource {
|
|||
ValidateFunc: validateDmsReplicationTaskId,
|
||||
},
|
||||
"replication_task_settings": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ValidateFunc: validateJsonString,
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ValidateFunc: validateJsonString,
|
||||
DiffSuppressFunc: suppressEquivalentJsonDiffs,
|
||||
},
|
||||
"source_endpoint_arn": {
|
||||
Type: schema.TypeString,
|
||||
|
@ -68,9 +69,10 @@ func resourceAwsDmsReplicationTask() *schema.Resource {
|
|||
ValidateFunc: validateArn,
|
||||
},
|
||||
"table_mappings": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ValidateFunc: validateJsonString,
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ValidateFunc: validateJsonString,
|
||||
DiffSuppressFunc: suppressEquivalentJsonDiffs,
|
||||
},
|
||||
"tags": {
|
||||
Type: schema.TypeMap,
|
||||
|
|
|
@ -70,11 +70,13 @@ func resourceAwsEcsTaskDefinition() *schema.Resource {
|
|||
"name": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"host_path": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -135,6 +135,41 @@ func TestAccAWSEcsTaskDefinition_constraint(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestAccAWSEcsTaskDefinition_changeVolumesForcesNewResource(t *testing.T) {
|
||||
var before ecs.TaskDefinition
|
||||
var after ecs.TaskDefinition
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAWSEcsTaskDefinitionDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccAWSEcsTaskDefinition,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSEcsTaskDefinitionExists("aws_ecs_task_definition.jenkins", &before),
|
||||
),
|
||||
},
|
||||
{
|
||||
Config: testAccAWSEcsTaskDefinitionUpdatedVolume,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSEcsTaskDefinitionExists("aws_ecs_task_definition.jenkins", &after),
|
||||
testAccCheckEcsTaskDefinitionRecreated(t, &before, &after),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckEcsTaskDefinitionRecreated(t *testing.T,
|
||||
before, after *ecs.TaskDefinition) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
if *before.Revision == *after.Revision {
|
||||
t.Fatalf("Expected change of TaskDefinition Revisions, but both were %v", before.Revision)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckAWSTaskDefinitionConstraintsAttrs(def *ecs.TaskDefinition) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
if len(def.PlacementConstraints) != 1 {
|
||||
|
@ -319,6 +354,55 @@ TASK_DEFINITION
|
|||
}
|
||||
`
|
||||
|
||||
var testAccAWSEcsTaskDefinitionUpdatedVolume = `
|
||||
resource "aws_ecs_task_definition" "jenkins" {
|
||||
family = "terraform-acc-test"
|
||||
container_definitions = <<TASK_DEFINITION
|
||||
[
|
||||
{
|
||||
"cpu": 10,
|
||||
"command": ["sleep", "10"],
|
||||
"entryPoint": ["/"],
|
||||
"environment": [
|
||||
{"name": "VARNAME", "value": "VARVAL"}
|
||||
],
|
||||
"essential": true,
|
||||
"image": "jenkins",
|
||||
"links": ["mongodb"],
|
||||
"memory": 128,
|
||||
"name": "jenkins",
|
||||
"portMappings": [
|
||||
{
|
||||
"containerPort": 80,
|
||||
"hostPort": 8080
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"cpu": 10,
|
||||
"command": ["sleep", "10"],
|
||||
"entryPoint": ["/"],
|
||||
"essential": true,
|
||||
"image": "mongodb",
|
||||
"memory": 128,
|
||||
"name": "mongodb",
|
||||
"portMappings": [
|
||||
{
|
||||
"containerPort": 28017,
|
||||
"hostPort": 28017
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
TASK_DEFINITION
|
||||
|
||||
volume {
|
||||
name = "jenkins-home"
|
||||
host_path = "/ecs/jenkins"
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
var testAccAWSEcsTaskDefinitionWithScratchVolume = `
|
||||
resource "aws_ecs_task_definition" "sleep" {
|
||||
family = "terraform-acc-sc-volume-test"
|
||||
|
|
|
@ -1034,10 +1034,15 @@ func readBlockDeviceMappingsFromConfig(
|
|||
|
||||
if v, ok := bd["volume_type"].(string); ok && v != "" {
|
||||
ebs.VolumeType = aws.String(v)
|
||||
}
|
||||
|
||||
if v, ok := bd["iops"].(int); ok && v > 0 {
|
||||
ebs.Iops = aws.Int64(int64(v))
|
||||
if "io1" == strings.ToLower(v) {
|
||||
// Condition: This parameter is required for requests to create io1
|
||||
// volumes; it is not used in requests to create gp2, st1, sc1, or
|
||||
// standard volumes.
|
||||
// See: http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_EbsBlockDevice.html
|
||||
if v, ok := bd["iops"].(int); ok && v > 0 {
|
||||
ebs.Iops = aws.Int64(int64(v))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
blockDevices = append(blockDevices, &ec2.BlockDeviceMapping{
|
||||
|
|
|
@ -1060,7 +1060,6 @@ resource "aws_instance" "foo" {
|
|||
root_block_device {
|
||||
volume_type = "gp2"
|
||||
volume_size = 11
|
||||
iops = 330
|
||||
}
|
||||
}
|
||||
`
|
||||
|
|
|
@ -2,9 +2,6 @@ package aws
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha1"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"log"
|
||||
"strconv"
|
||||
|
@ -168,6 +165,7 @@ func resourceAwsSpotFleetRequest() *schema.Resource {
|
|||
"ebs_optimized": &schema.Schema{
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: false,
|
||||
},
|
||||
"iam_instance_profile": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
|
@ -194,6 +192,7 @@ func resourceAwsSpotFleetRequest() *schema.Resource {
|
|||
"monitoring": &schema.Schema{
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: false,
|
||||
},
|
||||
"placement_group": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
|
@ -213,8 +212,7 @@ func resourceAwsSpotFleetRequest() *schema.Resource {
|
|||
StateFunc: func(v interface{}) string {
|
||||
switch v.(type) {
|
||||
case string:
|
||||
hash := sha1.Sum([]byte(v.(string)))
|
||||
return hex.EncodeToString(hash[:])
|
||||
return userDataHashSum(v.(string))
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
|
@ -323,8 +321,7 @@ func buildSpotFleetLaunchSpecification(d map[string]interface{}, meta interface{
|
|||
}
|
||||
|
||||
if v, ok := d["user_data"]; ok {
|
||||
opts.UserData = aws.String(
|
||||
base64Encode([]byte(v.(string))))
|
||||
opts.UserData = aws.String(base64Encode([]byte(v.(string))))
|
||||
}
|
||||
|
||||
if v, ok := d["key_name"]; ok {
|
||||
|
@ -339,21 +336,11 @@ func buildSpotFleetLaunchSpecification(d map[string]interface{}, meta interface{
|
|||
opts.WeightedCapacity = aws.Float64(wc)
|
||||
}
|
||||
|
||||
var groups []*string
|
||||
if v, ok := d["security_groups"]; ok {
|
||||
sgs := v.(*schema.Set).List()
|
||||
for _, v := range sgs {
|
||||
str := v.(string)
|
||||
groups = append(groups, aws.String(str))
|
||||
}
|
||||
}
|
||||
|
||||
var groupIds []*string
|
||||
var securityGroupIds []*string
|
||||
if v, ok := d["vpc_security_group_ids"]; ok {
|
||||
if s := v.(*schema.Set); s.Len() > 0 {
|
||||
for _, v := range s.List() {
|
||||
opts.SecurityGroups = append(opts.SecurityGroups, &ec2.GroupIdentifier{GroupId: aws.String(v.(string))})
|
||||
groupIds = append(groupIds, aws.String(v.(string)))
|
||||
securityGroupIds = append(securityGroupIds, aws.String(v.(string)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -378,11 +365,15 @@ func buildSpotFleetLaunchSpecification(d map[string]interface{}, meta interface{
|
|||
DeleteOnTermination: aws.Bool(true),
|
||||
DeviceIndex: aws.Int64(int64(0)),
|
||||
SubnetId: aws.String(subnetId.(string)),
|
||||
Groups: groupIds,
|
||||
Groups: securityGroupIds,
|
||||
}
|
||||
|
||||
opts.NetworkInterfaces = []*ec2.InstanceNetworkInterfaceSpecification{ni}
|
||||
opts.SubnetId = aws.String("")
|
||||
} else {
|
||||
for _, id := range securityGroupIds {
|
||||
opts.SecurityGroups = append(opts.SecurityGroups, &ec2.GroupIdentifier{GroupId: id})
|
||||
}
|
||||
}
|
||||
|
||||
blockDevices, err := readSpotFleetBlockDeviceMappingsFromConfig(d, conn)
|
||||
|
@ -730,24 +721,20 @@ func resourceAwsSpotFleetRequestRead(d *schema.ResourceData, meta interface{}) e
|
|||
return nil
|
||||
}
|
||||
|
||||
func launchSpecsToSet(ls []*ec2.SpotFleetLaunchSpecification, conn *ec2.EC2) *schema.Set {
|
||||
specs := &schema.Set{F: hashLaunchSpecification}
|
||||
for _, val := range ls {
|
||||
dn, err := fetchRootDeviceName(aws.StringValue(val.ImageId), conn)
|
||||
func launchSpecsToSet(launchSpecs []*ec2.SpotFleetLaunchSpecification, conn *ec2.EC2) *schema.Set {
|
||||
specSet := &schema.Set{F: hashLaunchSpecification}
|
||||
for _, spec := range launchSpecs {
|
||||
rootDeviceName, err := fetchRootDeviceName(aws.StringValue(spec.ImageId), conn)
|
||||
if err != nil {
|
||||
log.Panic(err)
|
||||
} else {
|
||||
ls := launchSpecToMap(val, dn)
|
||||
specs.Add(ls)
|
||||
}
|
||||
|
||||
specSet.Add(launchSpecToMap(spec, rootDeviceName))
|
||||
}
|
||||
return specs
|
||||
return specSet
|
||||
}
|
||||
|
||||
func launchSpecToMap(
|
||||
l *ec2.SpotFleetLaunchSpecification,
|
||||
rootDevName *string,
|
||||
) map[string]interface{} {
|
||||
func launchSpecToMap(l *ec2.SpotFleetLaunchSpecification, rootDevName *string) map[string]interface{} {
|
||||
m := make(map[string]interface{})
|
||||
|
||||
m["root_block_device"] = rootBlockDeviceToSet(l.BlockDeviceMappings, rootDevName)
|
||||
|
@ -779,10 +766,7 @@ func launchSpecToMap(
|
|||
}
|
||||
|
||||
if l.UserData != nil {
|
||||
ud_dec, err := base64.StdEncoding.DecodeString(aws.StringValue(l.UserData))
|
||||
if err == nil {
|
||||
m["user_data"] = string(ud_dec)
|
||||
}
|
||||
m["user_data"] = userDataHashSum(aws.StringValue(l.UserData))
|
||||
}
|
||||
|
||||
if l.KeyName != nil {
|
||||
|
@ -797,11 +781,23 @@ func launchSpecToMap(
|
|||
m["subnet_id"] = aws.StringValue(l.SubnetId)
|
||||
}
|
||||
|
||||
securityGroupIds := &schema.Set{F: schema.HashString}
|
||||
if len(l.NetworkInterfaces) > 0 {
|
||||
// This resource auto-creates one network interface when associate_public_ip_address is true
|
||||
for _, group := range l.NetworkInterfaces[0].Groups {
|
||||
securityGroupIds.Add(aws.StringValue(group))
|
||||
}
|
||||
} else {
|
||||
for _, group := range l.SecurityGroups {
|
||||
securityGroupIds.Add(aws.StringValue(group.GroupId))
|
||||
}
|
||||
}
|
||||
m["vpc_security_group_ids"] = securityGroupIds
|
||||
|
||||
if l.WeightedCapacity != nil {
|
||||
m["weighted_capacity"] = strconv.FormatFloat(*l.WeightedCapacity, 'f', 0, 64)
|
||||
}
|
||||
|
||||
// m["security_groups"] = securityGroupsToSet(l.SecutiryGroups)
|
||||
return m
|
||||
}
|
||||
|
||||
|
@ -1009,7 +1005,6 @@ func hashLaunchSpecification(v interface{}) int {
|
|||
}
|
||||
buf.WriteString(fmt.Sprintf("%s-", m["instance_type"].(string)))
|
||||
buf.WriteString(fmt.Sprintf("%s-", m["spot_price"].(string)))
|
||||
buf.WriteString(fmt.Sprintf("%s-", m["user_data"].(string)))
|
||||
return hashcode.String(buf.String())
|
||||
}
|
||||
|
||||
|
|
|
@ -100,9 +100,9 @@ func TestAccAWSSpotFleetRequest_lowestPriceAzInGivenList(t *testing.T) {
|
|||
resource.TestCheckResourceAttr(
|
||||
"aws_spot_fleet_request.foo", "launch_specification.#", "2"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_spot_fleet_request.foo", "launch_specification.1590006269.availability_zone", "us-west-2a"),
|
||||
"aws_spot_fleet_request.foo", "launch_specification.335709043.availability_zone", "us-west-2a"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_spot_fleet_request.foo", "launch_specification.3809475891.availability_zone", "us-west-2b"),
|
||||
"aws_spot_fleet_request.foo", "launch_specification.1671188867.availability_zone", "us-west-2b"),
|
||||
),
|
||||
},
|
||||
},
|
||||
|
@ -154,13 +154,13 @@ func TestAccAWSSpotFleetRequest_multipleInstanceTypesInSameAz(t *testing.T) {
|
|||
resource.TestCheckResourceAttr(
|
||||
"aws_spot_fleet_request.foo", "launch_specification.#", "2"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_spot_fleet_request.foo", "launch_specification.1590006269.instance_type", "m1.small"),
|
||||
"aws_spot_fleet_request.foo", "launch_specification.335709043.instance_type", "m1.small"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_spot_fleet_request.foo", "launch_specification.1590006269.availability_zone", "us-west-2a"),
|
||||
"aws_spot_fleet_request.foo", "launch_specification.335709043.availability_zone", "us-west-2a"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_spot_fleet_request.foo", "launch_specification.3079734941.instance_type", "m3.large"),
|
||||
"aws_spot_fleet_request.foo", "launch_specification.590403189.instance_type", "m3.large"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_spot_fleet_request.foo", "launch_specification.3079734941.availability_zone", "us-west-2a"),
|
||||
"aws_spot_fleet_request.foo", "launch_specification.590403189.availability_zone", "us-west-2a"),
|
||||
),
|
||||
},
|
||||
},
|
||||
|
@ -214,13 +214,13 @@ func TestAccAWSSpotFleetRequest_overriddingSpotPrice(t *testing.T) {
|
|||
resource.TestCheckResourceAttr(
|
||||
"aws_spot_fleet_request.foo", "launch_specification.#", "2"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_spot_fleet_request.foo", "launch_specification.522395050.spot_price", "0.01"),
|
||||
"aws_spot_fleet_request.foo", "launch_specification.4143232216.spot_price", "0.01"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_spot_fleet_request.foo", "launch_specification.522395050.instance_type", "m3.large"),
|
||||
"aws_spot_fleet_request.foo", "launch_specification.4143232216.instance_type", "m3.large"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_spot_fleet_request.foo", "launch_specification.1590006269.spot_price", ""), //there will not be a value here since it's not overriding
|
||||
"aws_spot_fleet_request.foo", "launch_specification.335709043.spot_price", ""), //there will not be a value here since it's not overriding
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_spot_fleet_request.foo", "launch_specification.1590006269.instance_type", "m1.small"),
|
||||
"aws_spot_fleet_request.foo", "launch_specification.335709043.instance_type", "m1.small"),
|
||||
),
|
||||
},
|
||||
},
|
||||
|
@ -289,13 +289,13 @@ func TestAccAWSSpotFleetRequest_withWeightedCapacity(t *testing.T) {
|
|||
resource.TestCheckResourceAttr(
|
||||
"aws_spot_fleet_request.foo", "launch_specification.#", "2"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_spot_fleet_request.foo", "launch_specification.2325690000.weighted_capacity", "3"),
|
||||
"aws_spot_fleet_request.foo", "launch_specification.4120185872.weighted_capacity", "3"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_spot_fleet_request.foo", "launch_specification.2325690000.instance_type", "r3.large"),
|
||||
"aws_spot_fleet_request.foo", "launch_specification.4120185872.instance_type", "r3.large"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_spot_fleet_request.foo", "launch_specification.3079734941.weighted_capacity", "6"),
|
||||
"aws_spot_fleet_request.foo", "launch_specification.590403189.weighted_capacity", "6"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_spot_fleet_request.foo", "launch_specification.3079734941.instance_type", "m3.large"),
|
||||
"aws_spot_fleet_request.foo", "launch_specification.590403189.instance_type", "m3.large"),
|
||||
),
|
||||
},
|
||||
},
|
||||
|
|
|
@ -77,6 +77,25 @@ func resourceAwsVolumeAttachmentCreate(d *schema.ResourceData, meta interface{})
|
|||
|
||||
vols, err := conn.DescribeVolumes(request)
|
||||
if (err != nil) || (len(vols.Volumes) == 0) {
|
||||
// This handles the situation where the instance is created by
|
||||
// a spot request and whilst the request has been fulfilled the
|
||||
// instance is not running yet
|
||||
stateConf := &resource.StateChangeConf{
|
||||
Pending: []string{"pending"},
|
||||
Target: []string{"running"},
|
||||
Refresh: InstanceStateRefreshFunc(conn, iID),
|
||||
Timeout: 10 * time.Minute,
|
||||
Delay: 10 * time.Second,
|
||||
MinTimeout: 3 * time.Second,
|
||||
}
|
||||
|
||||
_, err = stateConf.WaitForState()
|
||||
if err != nil {
|
||||
return fmt.Errorf(
|
||||
"Error waiting for instance (%s) to become ready: %s",
|
||||
iID, err)
|
||||
}
|
||||
|
||||
// not attached
|
||||
opts := &ec2.AttachVolumeInput{
|
||||
Device: aws.String(name),
|
||||
|
|
|
@ -2,6 +2,8 @@ package aws
|
|||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
|
@ -24,3 +26,17 @@ func isBase64Encoded(data []byte) bool {
|
|||
func looksLikeJsonString(s interface{}) bool {
|
||||
return regexp.MustCompile(`^\s*{`).MatchString(s.(string))
|
||||
}
|
||||
|
||||
func jsonBytesEqual(b1, b2 []byte) bool {
|
||||
var o1 interface{}
|
||||
if err := json.Unmarshal(b1, &o1); err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
var o2 interface{}
|
||||
if err := json.Unmarshal(b2, &o2); err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return reflect.DeepEqual(o1, o2)
|
||||
}
|
||||
|
|
|
@ -32,3 +32,41 @@ func TestLooksLikeJsonString(t *testing.T) {
|
|||
t.Errorf("Expected looksLikeJson to return false for %s", doesNotLookLikeJson)
|
||||
}
|
||||
}
|
||||
|
||||
func TestJsonBytesEqualQuotedAndUnquoted(t *testing.T) {
|
||||
unquoted := `{"test": "test"}`
|
||||
quoted := "{\"test\": \"test\"}"
|
||||
|
||||
if !jsonBytesEqual([]byte(unquoted), []byte(quoted)) {
|
||||
t.Errorf("Expected jsonBytesEqual to return true for %s == %s", unquoted, quoted)
|
||||
}
|
||||
|
||||
unquotedDiff := `{"test": "test"}`
|
||||
quotedDiff := "{\"test\": \"tested\"}"
|
||||
|
||||
if jsonBytesEqual([]byte(unquotedDiff), []byte(quotedDiff)) {
|
||||
t.Errorf("Expected jsonBytesEqual to return false for %s == %s", unquotedDiff, quotedDiff)
|
||||
}
|
||||
}
|
||||
|
||||
func TestJsonBytesEqualWhitespaceAndNoWhitespace(t *testing.T) {
|
||||
noWhitespace := `{"test":"test"}`
|
||||
whitespace := `
|
||||
{
|
||||
"test": "test"
|
||||
}`
|
||||
|
||||
if !jsonBytesEqual([]byte(noWhitespace), []byte(whitespace)) {
|
||||
t.Errorf("Expected jsonBytesEqual to return true for %s == %s", noWhitespace, whitespace)
|
||||
}
|
||||
|
||||
noWhitespaceDiff := `{"test":"test"}`
|
||||
whitespaceDiff := `
|
||||
{
|
||||
"test": "tested"
|
||||
}`
|
||||
|
||||
if jsonBytesEqual([]byte(noWhitespaceDiff), []byte(whitespaceDiff)) {
|
||||
t.Errorf("Expected jsonBytesEqual to return false for %s == %s", noWhitespaceDiff, whitespaceDiff)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -324,7 +324,9 @@ func resourceDatadogMonitorUpdate(d *schema.ResourceData, meta interface{}) erro
|
|||
}
|
||||
|
||||
o := datadog.Options{
|
||||
NotifyNoData: datadog.Bool(d.Get("notify_no_data").(bool)),
|
||||
NotifyNoData: datadog.Bool(d.Get("notify_no_data").(bool)),
|
||||
RequireFullWindow: datadog.Bool(d.Get("require_full_window").(bool)),
|
||||
IncludeTags: datadog.Bool(d.Get("include_tags").(bool)),
|
||||
}
|
||||
if attr, ok := d.GetOk("thresholds"); ok {
|
||||
thresholds := attr.(map[string]interface{})
|
||||
|
@ -340,9 +342,6 @@ func resourceDatadogMonitorUpdate(d *schema.ResourceData, meta interface{}) erro
|
|||
}
|
||||
}
|
||||
|
||||
if attr, ok := d.GetOk("notify_no_data"); ok {
|
||||
o.SetNotifyNoData(attr.(bool))
|
||||
}
|
||||
if attr, ok := d.GetOk("new_host_delay"); ok {
|
||||
o.SetNewHostDelay(attr.(int))
|
||||
}
|
||||
|
@ -369,12 +368,6 @@ func resourceDatadogMonitorUpdate(d *schema.ResourceData, meta interface{}) erro
|
|||
}
|
||||
o.Silenced = s
|
||||
}
|
||||
if attr, ok := d.GetOk("include_tags"); ok {
|
||||
o.SetIncludeTags(attr.(bool))
|
||||
}
|
||||
if attr, ok := d.GetOk("require_full_window"); ok {
|
||||
o.SetRequireFullWindow(attr.(bool))
|
||||
}
|
||||
if attr, ok := d.GetOk("locked"); ok {
|
||||
o.SetLocked(attr.(bool))
|
||||
}
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
package google
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"google.golang.org/api/container/v1"
|
||||
)
|
||||
|
||||
type ContainerOperationWaiter struct {
|
||||
Service *container.Service
|
||||
Op *container.Operation
|
||||
Project string
|
||||
Zone string
|
||||
}
|
||||
|
||||
func (w *ContainerOperationWaiter) Conf() *resource.StateChangeConf {
|
||||
return &resource.StateChangeConf{
|
||||
Pending: []string{"PENDING", "RUNNING"},
|
||||
Target: []string{"DONE"},
|
||||
Refresh: w.RefreshFunc(),
|
||||
}
|
||||
}
|
||||
|
||||
func (w *ContainerOperationWaiter) RefreshFunc() resource.StateRefreshFunc {
|
||||
return func() (interface{}, string, error) {
|
||||
resp, err := w.Service.Projects.Zones.Operations.Get(
|
||||
w.Project, w.Zone, w.Op.Name).Do()
|
||||
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] Progress of operation %q: %q", w.Op.Name, resp.Status)
|
||||
|
||||
return resp, resp.Status, err
|
||||
}
|
||||
}
|
||||
|
||||
func containerOperationWait(config *Config, op *container.Operation, project, zone, activity string, timeoutMinutes, minTimeoutSeconds int) error {
|
||||
w := &ContainerOperationWaiter{
|
||||
Service: config.clientContainer,
|
||||
Op: op,
|
||||
Project: project,
|
||||
Zone: zone,
|
||||
}
|
||||
|
||||
state := w.Conf()
|
||||
state.Timeout = time.Duration(timeoutMinutes) * time.Minute
|
||||
state.MinTimeout = time.Duration(minTimeoutSeconds) * time.Second
|
||||
_, err := state.WaitForState()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error waiting for %s: %s", activity, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -91,6 +91,7 @@ func Provider() terraform.ResourceProvider {
|
|||
"google_compute_vpn_gateway": resourceComputeVpnGateway(),
|
||||
"google_compute_vpn_tunnel": resourceComputeVpnTunnel(),
|
||||
"google_container_cluster": resourceContainerCluster(),
|
||||
"google_container_node_pool": resourceContainerNodePool(),
|
||||
"google_dns_managed_zone": resourceDnsManagedZone(),
|
||||
"google_dns_record_set": resourceDnsRecordSet(),
|
||||
"google_sql_database": resourceSqlDatabase(),
|
||||
|
|
|
@ -5,9 +5,7 @@ import (
|
|||
"log"
|
||||
"net"
|
||||
"regexp"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"google.golang.org/api/container/v1"
|
||||
"google.golang.org/api/googleapi"
|
||||
|
@ -389,23 +387,11 @@ func resourceContainerClusterCreate(d *schema.ResourceData, meta interface{}) er
|
|||
}
|
||||
|
||||
// Wait until it's created
|
||||
wait := resource.StateChangeConf{
|
||||
Pending: []string{"PENDING", "RUNNING"},
|
||||
Target: []string{"DONE"},
|
||||
Timeout: 30 * time.Minute,
|
||||
MinTimeout: 3 * time.Second,
|
||||
Refresh: func() (interface{}, string, error) {
|
||||
resp, err := config.clientContainer.Projects.Zones.Operations.Get(
|
||||
project, zoneName, op.Name).Do()
|
||||
log.Printf("[DEBUG] Progress of creating GKE cluster %s: %s",
|
||||
clusterName, resp.Status)
|
||||
return resp, resp.Status, err
|
||||
},
|
||||
}
|
||||
|
||||
_, err = wait.WaitForState()
|
||||
if err != nil {
|
||||
return err
|
||||
waitErr := containerOperationWait(config, op, project, zoneName, "creating GKE cluster", 30, 3)
|
||||
if waitErr != nil {
|
||||
// The resource didn't actually create
|
||||
d.SetId("")
|
||||
return waitErr
|
||||
}
|
||||
|
||||
log.Printf("[INFO] GKE cluster %s has been created", clusterName)
|
||||
|
@ -503,24 +489,9 @@ func resourceContainerClusterUpdate(d *schema.ResourceData, meta interface{}) er
|
|||
}
|
||||
|
||||
// Wait until it's updated
|
||||
wait := resource.StateChangeConf{
|
||||
Pending: []string{"PENDING", "RUNNING"},
|
||||
Target: []string{"DONE"},
|
||||
Timeout: 10 * time.Minute,
|
||||
MinTimeout: 2 * time.Second,
|
||||
Refresh: func() (interface{}, string, error) {
|
||||
log.Printf("[DEBUG] Checking if GKE cluster %s is updated", clusterName)
|
||||
resp, err := config.clientContainer.Projects.Zones.Operations.Get(
|
||||
project, zoneName, op.Name).Do()
|
||||
log.Printf("[DEBUG] Progress of updating GKE cluster %s: %s",
|
||||
clusterName, resp.Status)
|
||||
return resp, resp.Status, err
|
||||
},
|
||||
}
|
||||
|
||||
_, err = wait.WaitForState()
|
||||
if err != nil {
|
||||
return err
|
||||
waitErr := containerOperationWait(config, op, project, zoneName, "updating GKE cluster", 10, 2)
|
||||
if waitErr != nil {
|
||||
return waitErr
|
||||
}
|
||||
|
||||
log.Printf("[INFO] GKE cluster %s has been updated to %s", d.Id(),
|
||||
|
@ -548,24 +519,9 @@ func resourceContainerClusterDelete(d *schema.ResourceData, meta interface{}) er
|
|||
}
|
||||
|
||||
// Wait until it's deleted
|
||||
wait := resource.StateChangeConf{
|
||||
Pending: []string{"PENDING", "RUNNING"},
|
||||
Target: []string{"DONE"},
|
||||
Timeout: 10 * time.Minute,
|
||||
MinTimeout: 3 * time.Second,
|
||||
Refresh: func() (interface{}, string, error) {
|
||||
log.Printf("[DEBUG] Checking if GKE cluster %s is deleted", clusterName)
|
||||
resp, err := config.clientContainer.Projects.Zones.Operations.Get(
|
||||
project, zoneName, op.Name).Do()
|
||||
log.Printf("[DEBUG] Progress of deleting GKE cluster %s: %s",
|
||||
clusterName, resp.Status)
|
||||
return resp, resp.Status, err
|
||||
},
|
||||
}
|
||||
|
||||
_, err = wait.WaitForState()
|
||||
if err != nil {
|
||||
return err
|
||||
waitErr := containerOperationWait(config, op, project, zoneName, "deleting GKE cluster", 10, 3)
|
||||
if waitErr != nil {
|
||||
return waitErr
|
||||
}
|
||||
|
||||
log.Printf("[INFO] GKE cluster %s has been deleted", d.Id())
|
||||
|
|
|
@ -0,0 +1,191 @@
|
|||
package google
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"google.golang.org/api/container/v1"
|
||||
"google.golang.org/api/googleapi"
|
||||
)
|
||||
|
||||
func resourceContainerNodePool() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceContainerNodePoolCreate,
|
||||
Read: resourceContainerNodePoolRead,
|
||||
Delete: resourceContainerNodePoolDelete,
|
||||
Exists: resourceContainerNodePoolExists,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"project": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ConflictsWith: []string{"name_prefix"},
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"name_prefix": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"zone": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"cluster": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"initial_node_count": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func resourceContainerNodePoolCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
config := meta.(*Config)
|
||||
|
||||
project, err := getProject(d, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
zone := d.Get("zone").(string)
|
||||
cluster := d.Get("cluster").(string)
|
||||
nodeCount := d.Get("initial_node_count").(int)
|
||||
|
||||
var name string
|
||||
if v, ok := d.GetOk("name"); ok {
|
||||
name = v.(string)
|
||||
} else if v, ok := d.GetOk("name_prefix"); ok {
|
||||
name = resource.PrefixedUniqueId(v.(string))
|
||||
} else {
|
||||
name = resource.UniqueId()
|
||||
}
|
||||
|
||||
nodePool := &container.NodePool{
|
||||
Name: name,
|
||||
InitialNodeCount: int64(nodeCount),
|
||||
}
|
||||
|
||||
req := &container.CreateNodePoolRequest{
|
||||
NodePool: nodePool,
|
||||
}
|
||||
|
||||
op, err := config.clientContainer.Projects.Zones.Clusters.NodePools.Create(project, zone, cluster, req).Do()
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating NodePool: %s", err)
|
||||
}
|
||||
|
||||
waitErr := containerOperationWait(config, op, project, zone, "creating GKE NodePool", 10, 3)
|
||||
if waitErr != nil {
|
||||
// The resource didn't actually create
|
||||
d.SetId("")
|
||||
return waitErr
|
||||
}
|
||||
|
||||
log.Printf("[INFO] GKE NodePool %s has been created", name)
|
||||
|
||||
d.SetId(name)
|
||||
|
||||
return resourceContainerNodePoolRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceContainerNodePoolRead(d *schema.ResourceData, meta interface{}) error {
|
||||
config := meta.(*Config)
|
||||
|
||||
project, err := getProject(d, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
zone := d.Get("zone").(string)
|
||||
name := d.Get("name").(string)
|
||||
cluster := d.Get("cluster").(string)
|
||||
|
||||
nodePool, err := config.clientContainer.Projects.Zones.Clusters.NodePools.Get(
|
||||
project, zone, cluster, name).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error reading NodePool: %s", err)
|
||||
}
|
||||
|
||||
d.Set("name", nodePool.Name)
|
||||
d.Set("initial_node_count", nodePool.InitialNodeCount)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceContainerNodePoolDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
config := meta.(*Config)
|
||||
|
||||
project, err := getProject(d, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
zone := d.Get("zone").(string)
|
||||
name := d.Get("name").(string)
|
||||
cluster := d.Get("cluster").(string)
|
||||
|
||||
op, err := config.clientContainer.Projects.Zones.Clusters.NodePools.Delete(
|
||||
project, zone, cluster, name).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error deleting NodePool: %s", err)
|
||||
}
|
||||
|
||||
// Wait until it's deleted
|
||||
waitErr := containerOperationWait(config, op, project, zone, "deleting GKE NodePool", 10, 2)
|
||||
if waitErr != nil {
|
||||
return waitErr
|
||||
}
|
||||
|
||||
log.Printf("[INFO] GKE NodePool %s has been deleted", d.Id())
|
||||
|
||||
d.SetId("")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceContainerNodePoolExists(d *schema.ResourceData, meta interface{}) (bool, error) {
|
||||
config := meta.(*Config)
|
||||
|
||||
project, err := getProject(d, config)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
zone := d.Get("zone").(string)
|
||||
name := d.Get("name").(string)
|
||||
cluster := d.Get("cluster").(string)
|
||||
|
||||
_, err = config.clientContainer.Projects.Zones.Clusters.NodePools.Get(
|
||||
project, zone, cluster, name).Do()
|
||||
if err != nil {
|
||||
if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 {
|
||||
log.Printf("[WARN] Removing Container NodePool %q because it's gone", name)
|
||||
// The resource doesn't exist anymore
|
||||
return false, err
|
||||
}
|
||||
// There was some other error in reading the resource
|
||||
return true, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
package google
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/acctest"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
func TestAccContainerNodePool_basic(t *testing.T) {
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckContainerNodePoolDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccContainerNodePool_basic,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckContainerNodePoolMatches("google_container_node_pool.np"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckContainerNodePoolDestroy(s *terraform.State) error {
|
||||
config := testAccProvider.Meta().(*Config)
|
||||
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "google_container_node_pool" {
|
||||
continue
|
||||
}
|
||||
|
||||
attributes := rs.Primary.Attributes
|
||||
_, err := config.clientContainer.Projects.Zones.Clusters.NodePools.Get(
|
||||
config.Project, attributes["zone"], attributes["cluster"], attributes["name"]).Do()
|
||||
if err == nil {
|
||||
return fmt.Errorf("NodePool still exists")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func testAccCheckContainerNodePoolMatches(n string) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
config := testAccProvider.Meta().(*Config)
|
||||
|
||||
rs, ok := s.RootModule().Resources[n]
|
||||
if !ok {
|
||||
return fmt.Errorf("Not found: %s", n)
|
||||
}
|
||||
|
||||
if rs.Primary.ID == "" {
|
||||
return fmt.Errorf("No ID is set")
|
||||
}
|
||||
|
||||
attributes := rs.Primary.Attributes
|
||||
found, err := config.clientContainer.Projects.Zones.Clusters.NodePools.Get(
|
||||
config.Project, attributes["zone"], attributes["cluster"], attributes["name"]).Do()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if found.Name != attributes["name"] {
|
||||
return fmt.Errorf("NodePool not found")
|
||||
}
|
||||
|
||||
inc, err := strconv.Atoi(attributes["initial_node_count"])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if found.InitialNodeCount != int64(inc) {
|
||||
return fmt.Errorf("Mismatched initialNodeCount. TF State: %s. GCP State: %d",
|
||||
attributes["initial_node_count"], found.InitialNodeCount)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
var testAccContainerNodePool_basic = fmt.Sprintf(`
|
||||
resource "google_container_cluster" "cluster" {
|
||||
name = "tf-cluster-nodepool-test-%s"
|
||||
zone = "us-central1-a"
|
||||
initial_node_count = 3
|
||||
|
||||
master_auth {
|
||||
username = "mr.yoda"
|
||||
password = "adoy.rm"
|
||||
}
|
||||
}
|
||||
|
||||
resource "google_container_node_pool" "np" {
|
||||
name = "tf-nodepool-test-%s"
|
||||
zone = "us-central1-a"
|
||||
cluster = "${google_container_cluster.cluster.name}"
|
||||
initial_node_count = 2
|
||||
}`, acctest.RandString(10), acctest.RandString(10))
|
|
@ -23,12 +23,13 @@ import (
|
|||
datadogprovider "github.com/hashicorp/terraform/builtin/providers/datadog"
|
||||
digitaloceanprovider "github.com/hashicorp/terraform/builtin/providers/digitalocean"
|
||||
dmeprovider "github.com/hashicorp/terraform/builtin/providers/dme"
|
||||
dnsprovider "github.com/hashicorp/terraform/builtin/providers/dns"
|
||||
dnsimpleprovider "github.com/hashicorp/terraform/builtin/providers/dnsimple"
|
||||
dnsprovider "github.com/hashicorp/terraform/builtin/providers/dns"
|
||||
dockerprovider "github.com/hashicorp/terraform/builtin/providers/docker"
|
||||
dynprovider "github.com/hashicorp/terraform/builtin/providers/dyn"
|
||||
externalprovider "github.com/hashicorp/terraform/builtin/providers/external"
|
||||
fastlyprovider "github.com/hashicorp/terraform/builtin/providers/fastly"
|
||||
fileprovisioner "github.com/hashicorp/terraform/builtin/provisioners/file"
|
||||
githubprovider "github.com/hashicorp/terraform/builtin/providers/github"
|
||||
googleprovider "github.com/hashicorp/terraform/builtin/providers/google"
|
||||
grafanaprovider "github.com/hashicorp/terraform/builtin/providers/grafana"
|
||||
|
@ -37,6 +38,7 @@ import (
|
|||
ignitionprovider "github.com/hashicorp/terraform/builtin/providers/ignition"
|
||||
influxdbprovider "github.com/hashicorp/terraform/builtin/providers/influxdb"
|
||||
libratoprovider "github.com/hashicorp/terraform/builtin/providers/librato"
|
||||
localexecprovisioner "github.com/hashicorp/terraform/builtin/provisioners/local-exec"
|
||||
logentriesprovider "github.com/hashicorp/terraform/builtin/providers/logentries"
|
||||
mailgunprovider "github.com/hashicorp/terraform/builtin/providers/mailgun"
|
||||
mysqlprovider "github.com/hashicorp/terraform/builtin/providers/mysql"
|
||||
|
@ -54,6 +56,7 @@ import (
|
|||
rabbitmqprovider "github.com/hashicorp/terraform/builtin/providers/rabbitmq"
|
||||
rancherprovider "github.com/hashicorp/terraform/builtin/providers/rancher"
|
||||
randomprovider "github.com/hashicorp/terraform/builtin/providers/random"
|
||||
remoteexecprovisioner "github.com/hashicorp/terraform/builtin/provisioners/remote-exec"
|
||||
rundeckprovider "github.com/hashicorp/terraform/builtin/providers/rundeck"
|
||||
scalewayprovider "github.com/hashicorp/terraform/builtin/providers/scaleway"
|
||||
softlayerprovider "github.com/hashicorp/terraform/builtin/providers/softlayer"
|
||||
|
@ -68,9 +71,6 @@ import (
|
|||
vaultprovider "github.com/hashicorp/terraform/builtin/providers/vault"
|
||||
vcdprovider "github.com/hashicorp/terraform/builtin/providers/vcd"
|
||||
vsphereprovider "github.com/hashicorp/terraform/builtin/providers/vsphere"
|
||||
fileprovisioner "github.com/hashicorp/terraform/builtin/provisioners/file"
|
||||
localexecprovisioner "github.com/hashicorp/terraform/builtin/provisioners/local-exec"
|
||||
remoteexecprovisioner "github.com/hashicorp/terraform/builtin/provisioners/remote-exec"
|
||||
|
||||
"github.com/hashicorp/terraform/plugin"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
|
@ -80,74 +80,76 @@ import (
|
|||
)
|
||||
|
||||
var InternalProviders = map[string]plugin.ProviderFunc{
|
||||
"alicloud": alicloudprovider.Provider,
|
||||
"archive": archiveprovider.Provider,
|
||||
"arukas": arukasprovider.Provider,
|
||||
"atlas": atlasprovider.Provider,
|
||||
"aws": awsprovider.Provider,
|
||||
"azure": azureprovider.Provider,
|
||||
"azurerm": azurermprovider.Provider,
|
||||
"bitbucket": bitbucketprovider.Provider,
|
||||
"chef": chefprovider.Provider,
|
||||
"clc": clcprovider.Provider,
|
||||
"alicloud": alicloudprovider.Provider,
|
||||
"archive": archiveprovider.Provider,
|
||||
"arukas": arukasprovider.Provider,
|
||||
"atlas": atlasprovider.Provider,
|
||||
"aws": awsprovider.Provider,
|
||||
"azure": azureprovider.Provider,
|
||||
"azurerm": azurermprovider.Provider,
|
||||
"bitbucket": bitbucketprovider.Provider,
|
||||
"chef": chefprovider.Provider,
|
||||
"clc": clcprovider.Provider,
|
||||
"cloudflare": cloudflareprovider.Provider,
|
||||
"cloudstack": cloudstackprovider.Provider,
|
||||
"cobbler": cobblerprovider.Provider,
|
||||
"consul": consulprovider.Provider,
|
||||
"datadog": datadogprovider.Provider,
|
||||
"digitalocean": digitaloceanprovider.Provider,
|
||||
"dme": dmeprovider.Provider,
|
||||
"dns": dnsprovider.Provider,
|
||||
"dnsimple": dnsimpleprovider.Provider,
|
||||
"docker": dockerprovider.Provider,
|
||||
"dyn": dynprovider.Provider,
|
||||
"external": externalprovider.Provider,
|
||||
"fastly": fastlyprovider.Provider,
|
||||
"github": githubprovider.Provider,
|
||||
"google": googleprovider.Provider,
|
||||
"grafana": grafanaprovider.Provider,
|
||||
"heroku": herokuprovider.Provider,
|
||||
"icinga2": icinga2provider.Provider,
|
||||
"ignition": ignitionprovider.Provider,
|
||||
"influxdb": influxdbprovider.Provider,
|
||||
"librato": libratoprovider.Provider,
|
||||
"cobbler": cobblerprovider.Provider,
|
||||
"consul": consulprovider.Provider,
|
||||
"datadog": datadogprovider.Provider,
|
||||
"digitalocean": digitaloceanprovider.Provider,
|
||||
"dme": dmeprovider.Provider,
|
||||
"dns": dnsprovider.Provider,
|
||||
"dnsimple": dnsimpleprovider.Provider,
|
||||
"docker": dockerprovider.Provider,
|
||||
"dyn": dynprovider.Provider,
|
||||
"external": externalprovider.Provider,
|
||||
"fastly": fastlyprovider.Provider,
|
||||
"github": githubprovider.Provider,
|
||||
"google": googleprovider.Provider,
|
||||
"grafana": grafanaprovider.Provider,
|
||||
"heroku": herokuprovider.Provider,
|
||||
"icinga2": icinga2provider.Provider,
|
||||
"ignition": ignitionprovider.Provider,
|
||||
"influxdb": influxdbprovider.Provider,
|
||||
"librato": libratoprovider.Provider,
|
||||
"logentries": logentriesprovider.Provider,
|
||||
"mailgun": mailgunprovider.Provider,
|
||||
"mysql": mysqlprovider.Provider,
|
||||
"newrelic": newrelicprovider.Provider,
|
||||
"nomad": nomadprovider.Provider,
|
||||
"ns1": ns1provider.Provider,
|
||||
"null": nullprovider.Provider,
|
||||
"openstack": openstackprovider.Provider,
|
||||
"opsgenie": opsgenieprovider.Provider,
|
||||
"packet": packetprovider.Provider,
|
||||
"pagerduty": pagerdutyprovider.Provider,
|
||||
"mailgun": mailgunprovider.Provider,
|
||||
"mysql": mysqlprovider.Provider,
|
||||
"newrelic": newrelicprovider.Provider,
|
||||
"nomad": nomadprovider.Provider,
|
||||
"ns1": ns1provider.Provider,
|
||||
"null": nullprovider.Provider,
|
||||
"openstack": openstackprovider.Provider,
|
||||
"opsgenie": opsgenieprovider.Provider,
|
||||
"packet": packetprovider.Provider,
|
||||
"pagerduty": pagerdutyprovider.Provider,
|
||||
"postgresql": postgresqlprovider.Provider,
|
||||
"powerdns": powerdnsprovider.Provider,
|
||||
"profitbricks": profitbricksprovider.Provider,
|
||||
"rabbitmq": rabbitmqprovider.Provider,
|
||||
"rancher": rancherprovider.Provider,
|
||||
"random": randomprovider.Provider,
|
||||
"rundeck": rundeckprovider.Provider,
|
||||
"scaleway": scalewayprovider.Provider,
|
||||
"softlayer": softlayerprovider.Provider,
|
||||
"spotinst": spotinstprovider.Provider,
|
||||
"powerdns": powerdnsprovider.Provider,
|
||||
"profitbricks": profitbricksprovider.Provider,
|
||||
"rabbitmq": rabbitmqprovider.Provider,
|
||||
"rancher": rancherprovider.Provider,
|
||||
"random": randomprovider.Provider,
|
||||
"rundeck": rundeckprovider.Provider,
|
||||
"scaleway": scalewayprovider.Provider,
|
||||
"softlayer": softlayerprovider.Provider,
|
||||
"spotinst": spotinstprovider.Provider,
|
||||
"statuscake": statuscakeprovider.Provider,
|
||||
"template": templateprovider.Provider,
|
||||
"terraform": terraformprovider.Provider,
|
||||
"test": testprovider.Provider,
|
||||
"tls": tlsprovider.Provider,
|
||||
"triton": tritonprovider.Provider,
|
||||
"ultradns": ultradnsprovider.Provider,
|
||||
"vault": vaultprovider.Provider,
|
||||
"vcd": vcdprovider.Provider,
|
||||
"vsphere": vsphereprovider.Provider,
|
||||
"template": templateprovider.Provider,
|
||||
"terraform": terraformprovider.Provider,
|
||||
"test": testprovider.Provider,
|
||||
"tls": tlsprovider.Provider,
|
||||
"triton": tritonprovider.Provider,
|
||||
"ultradns": ultradnsprovider.Provider,
|
||||
"vault": vaultprovider.Provider,
|
||||
"vcd": vcdprovider.Provider,
|
||||
"vsphere": vsphereprovider.Provider,
|
||||
|
||||
}
|
||||
|
||||
var InternalProvisioners = map[string]plugin.ProvisionerFunc{
|
||||
"file": fileprovisioner.Provisioner,
|
||||
"local-exec": localexecprovisioner.Provisioner,
|
||||
"remote-exec": remoteexecprovisioner.Provisioner,
|
||||
"file": fileprovisioner.Provisioner,
|
||||
"local-exec": localexecprovisioner.Provisioner,
|
||||
"remote-exec": remoteexecprovisioner.Provisioner,
|
||||
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
@ -155,3 +157,4 @@ func init() {
|
|||
// built-in provisioners.
|
||||
InternalProvisioners["chef"] = func() terraform.ResourceProvisioner { return new(chefprovisioner.ResourceProvisioner) }
|
||||
}
|
||||
|
||||
|
|
|
@ -54,6 +54,7 @@ The following attributes are exported:
|
|||
* `arn` - The Amazon Resource Name (ARN) specifying the role.
|
||||
* `create_date` - The creation date of the IAM role.
|
||||
* `unique_id` - The stable and unique string identifying the role.
|
||||
* `name` - The name of the role.
|
||||
|
||||
## Example of Using Data Source for Assume Role Policy
|
||||
|
||||
|
|
|
@ -102,7 +102,8 @@ The `root_block_device` mapping supports the following:
|
|||
* `volume_size` - (Optional) The size of the volume in gigabytes.
|
||||
* `iops` - (Optional) The amount of provisioned
|
||||
[IOPS](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ebs-io-characteristics.html).
|
||||
This must be set with a `volume_type` of `"io1"`.
|
||||
This is only valid for `volume_type` of `"io1"`, and must be specified if
|
||||
using that type
|
||||
* `delete_on_termination` - (Optional) Whether the volume should be destroyed
|
||||
on instance termination (Default: `true`).
|
||||
|
||||
|
|
|
@ -3,13 +3,13 @@ layout: "consul"
|
|||
page_title: "Consul: consul_catalog_entry"
|
||||
sidebar_current: "docs-consul-resource-catalog-entry"
|
||||
description: |-
|
||||
Provides access to Catalog data in Consul. This can be used to define a node or a service. Currently, defining health checks is not supported.
|
||||
Registers a node or service with the Consul Catalog. Currently, defining health checks is not supported.
|
||||
---
|
||||
|
||||
# consul\_catalog\_entry
|
||||
|
||||
Provides access to Catalog data in Consul. This can be used to define a
|
||||
node or a service. Currently, defining health checks is not supported.
|
||||
Registers a node or service with the [Consul Catalog](https://www.consul.io/docs/agent/http/catalog.html#catalog_register).
|
||||
Currently, defining health checks is not supported.
|
||||
|
||||
## Example Usage
|
||||
|
||||
|
@ -41,6 +41,11 @@ The following arguments are supported:
|
|||
* `service` - (Optional) A service to optionally associated with
|
||||
the node. Supported values are documented below.
|
||||
|
||||
* `datacenter` - (Optional) The datacenter to use. This overrides the
|
||||
datacenter in the provider setup and the agent's default datacenter.
|
||||
|
||||
* `token` - (Optional) ACL token.
|
||||
|
||||
The `service` block supports the following:
|
||||
|
||||
* `address` - (Optional) The address of the service. Defaults to the
|
||||
|
|
|
@ -129,13 +129,23 @@ The `client_auth` configuration block accepts the following arguments:
|
|||
```
|
||||
provider "vault" {
|
||||
# It is strongly recommended to configure this provider through the
|
||||
# environment variables described below, so that each user can have
|
||||
# environment variables described above, so that each user can have
|
||||
# separate credentials set in the environment.
|
||||
address = "https://vault.example.net:8200"
|
||||
#
|
||||
# This will default to using $VAULT_ADDR
|
||||
# But can be set explicitly
|
||||
# address = "https://vault.example.net:8200"
|
||||
}
|
||||
|
||||
data "vault_generic_secret" "example" {
|
||||
resource "vault_generic_secret" "example" {
|
||||
path = "secret/foo"
|
||||
|
||||
data_json = <<EOT
|
||||
{
|
||||
"foo": "bar",
|
||||
"pizza": "cheese"
|
||||
}
|
||||
EOT
|
||||
}
|
||||
```
|
||||
|
||||
|
|
Loading…
Reference in New Issue