Merge branch 'master' of github.com:hashicorp/terraform
* 'master' of github.com:hashicorp/terraform: provider/aws: detach VPN gateway with proper ID update CHANGELOG provider/aws: Update ARN in instanceProfileReadResult provider/aws: remove placement_group from acctest core: module targeting Added support for more complexly images repos such as images on a private registry that are stored as namespace/name
This commit is contained in:
commit
4e717829f8
|
@ -120,6 +120,8 @@ BUG FIXES:
|
||||||
* provider/aws: ELB security groups can be updated in-place [GH-1662]
|
* provider/aws: ELB security groups can be updated in-place [GH-1662]
|
||||||
* provider/aws: `aws_main_route_table_association` can be deleted
|
* provider/aws: `aws_main_route_table_association` can be deleted
|
||||||
manually [GH-1806]
|
manually [GH-1806]
|
||||||
|
* provider/docker: image can reference more complex image addresses,
|
||||||
|
such as with private repos with ports [GH-1818]
|
||||||
* provider/openstack: region config is not required [GH-1441]
|
* provider/openstack: region config is not required [GH-1441]
|
||||||
* provider/openstack: `enable_dhcp` for networking subnet should be bool [GH-1741]
|
* provider/openstack: `enable_dhcp` for networking subnet should be bool [GH-1741]
|
||||||
* provisioner/remote-exec: add random number to uploaded script path so
|
* provisioner/remote-exec: add random number to uploaded script path so
|
||||||
|
|
|
@ -189,6 +189,9 @@ func instanceProfileReadResult(d *schema.ResourceData, result *iam.InstanceProfi
|
||||||
if err := d.Set("name", result.InstanceProfileName); err != nil {
|
if err := d.Set("name", result.InstanceProfileName); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if err := d.Set("arn", result.ARN); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
if err := d.Set("path", result.Path); err != nil {
|
if err := d.Set("path", result.Path); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,10 +21,6 @@ func TestAccAWSInstance_normal(t *testing.T) {
|
||||||
return fmt.Errorf("bad availability zone: %#v", *v.Placement.AvailabilityZone)
|
return fmt.Errorf("bad availability zone: %#v", *v.Placement.AvailabilityZone)
|
||||||
}
|
}
|
||||||
|
|
||||||
if *v.Placement.GroupName != "terraform-placement-group" {
|
|
||||||
return fmt.Errorf("bad placement group name: %#v", *v.Placement.GroupName)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(v.SecurityGroups) == 0 {
|
if len(v.SecurityGroups) == 0 {
|
||||||
return fmt.Errorf("no security groups: %#v", v.SecurityGroups)
|
return fmt.Errorf("no security groups: %#v", v.SecurityGroups)
|
||||||
}
|
}
|
||||||
|
@ -549,7 +545,6 @@ resource "aws_instance" "foo" {
|
||||||
# us-west-2
|
# us-west-2
|
||||||
ami = "ami-4fccb37f"
|
ami = "ami-4fccb37f"
|
||||||
availability_zone = "us-west-2a"
|
availability_zone = "us-west-2a"
|
||||||
placement_group = "terraform-placement-group"
|
|
||||||
|
|
||||||
instance_type = "m1.small"
|
instance_type = "m1.small"
|
||||||
security_groups = ["${aws_security_group.tf_test_foo.name}"]
|
security_groups = ["${aws_security_group.tf_test_foo.name}"]
|
||||||
|
|
|
@ -218,7 +218,7 @@ func resourceAwsVpnGatewayDetach(d *schema.ResourceData, meta interface{}) error
|
||||||
wait := true
|
wait := true
|
||||||
_, err := conn.DetachVPNGateway(&ec2.DetachVPNGatewayInput{
|
_, err := conn.DetachVPNGateway(&ec2.DetachVPNGatewayInput{
|
||||||
VPNGatewayID: aws.String(d.Id()),
|
VPNGatewayID: aws.String(d.Id()),
|
||||||
VPCID: aws.String(d.Get("vpc_id").(string)),
|
VPCID: aws.String(vpcID.(string)),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ec2err, ok := err.(aws.APIError)
|
ec2err, ok := err.(aws.APIError)
|
||||||
|
|
|
@ -192,10 +192,6 @@ resource "aws_vpn_gateway" "foo" {
|
||||||
`
|
`
|
||||||
|
|
||||||
const testAccVpnGatewayConfigChangeVPC = `
|
const testAccVpnGatewayConfigChangeVPC = `
|
||||||
resource "aws_vpc" "foo" {
|
|
||||||
cidr_block = "10.1.0.0/16"
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "aws_vpc" "bar" {
|
resource "aws_vpc" "bar" {
|
||||||
cidr_block = "10.2.0.0/16"
|
cidr_block = "10.2.0.0/16"
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package docker
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
"regexp"
|
||||||
|
|
||||||
dc "github.com/fsouza/go-dockerclient"
|
dc "github.com/fsouza/go-dockerclient"
|
||||||
"github.com/hashicorp/terraform/helper/schema"
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
|
@ -75,35 +76,28 @@ func pullImage(data *Data, client *dc.Client, image string) error {
|
||||||
|
|
||||||
pullOpts := dc.PullImageOptions{}
|
pullOpts := dc.PullImageOptions{}
|
||||||
|
|
||||||
splitImageName := strings.Split(image, ":")
|
//
|
||||||
switch {
|
// Breaks apart an image string into host:port, repo, and tag components
|
||||||
|
regex := "^(?:(?P<host>(?:[\\w-]+(?:\\.[\\w-]+)+)(?::[\\d]+)?)/)?(?P<repo>[\\w.-]+(?:/[\\w.-]*)*)*(?::(?P<tag>[\\w.-]*))?"
|
||||||
|
r, _ := regexp.Compile(regex)
|
||||||
|
|
||||||
// It's in registry:port/repo:tag format
|
// Result is in form [[image, host, repo, tag]], so we get the head of the
|
||||||
case len(splitImageName) == 3:
|
// outer list to pass the inner list to result
|
||||||
splitPortRepo := strings.Split(splitImageName[1], "/")
|
result := r.FindAllStringSubmatch(image, -1)[0]
|
||||||
pullOpts.Registry = splitImageName[0] + ":" + splitPortRepo[0]
|
|
||||||
pullOpts.Repository = splitPortRepo[1]
|
|
||||||
pullOpts.Tag = splitImageName[2]
|
|
||||||
|
|
||||||
// It's either registry:port/repo or repo:tag with default registry
|
// If the host is not an empty string, then the image is using a private registry
|
||||||
case len(splitImageName) == 2:
|
if (result[1] != "") {
|
||||||
splitPortRepo := strings.Split(splitImageName[1], "/")
|
pullOpts.Registry = result[1]
|
||||||
switch len(splitPortRepo) {
|
// The repository for a private registry should take the form of host/repo rather than just repo
|
||||||
|
pullOpts.Repository = result[1] + "/" + result[2]
|
||||||
// registry:port/repo
|
} else if (result[2] != "") {
|
||||||
case 2:
|
// Local registries, or the main docker registry will have an image named as just 'repo'
|
||||||
pullOpts.Registry = splitImageName[0] + ":" + splitPortRepo[0]
|
pullOpts.Repository = result[2]
|
||||||
pullOpts.Repository = splitPortRepo[1]
|
|
||||||
pullOpts.Tag = "latest"
|
|
||||||
|
|
||||||
// repo:tag
|
|
||||||
case 1:
|
|
||||||
pullOpts.Repository = splitImageName[0]
|
|
||||||
pullOpts.Tag = splitImageName[1]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
// If there was a tag specified, then set it
|
||||||
pullOpts.Repository = image
|
if (result[3] != "") {
|
||||||
|
pullOpts.Tag = result[3]
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := client.PullImage(pullOpts, dc.AuthConfiguration{}); err != nil {
|
if err := client.PullImage(pullOpts, dc.AuthConfiguration{}); err != nil {
|
||||||
|
|
|
@ -6128,6 +6128,87 @@ aws_instance.foo.1:
|
||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestContext2Apply_targetedModule(t *testing.T) {
|
||||||
|
m := testModule(t, "apply-targeted-module")
|
||||||
|
p := testProvider("aws")
|
||||||
|
p.ApplyFn = testApplyFn
|
||||||
|
p.DiffFn = testDiffFn
|
||||||
|
ctx := testContext2(t, &ContextOpts{
|
||||||
|
Module: m,
|
||||||
|
Providers: map[string]ResourceProviderFactory{
|
||||||
|
"aws": testProviderFuncFixed(p),
|
||||||
|
},
|
||||||
|
Targets: []string{"module.child"},
|
||||||
|
})
|
||||||
|
|
||||||
|
if _, err := ctx.Plan(); err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
state, err := ctx.Apply()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
mod := state.ModuleByPath([]string{"root", "child"})
|
||||||
|
if mod == nil {
|
||||||
|
t.Fatalf("no child module found in the state!\n\n%#v", state)
|
||||||
|
}
|
||||||
|
if len(mod.Resources) != 2 {
|
||||||
|
t.Fatalf("expected 2 resources, got: %#v", mod.Resources)
|
||||||
|
}
|
||||||
|
|
||||||
|
checkStateString(t, state, `
|
||||||
|
<no state>
|
||||||
|
module.child:
|
||||||
|
aws_instance.bar:
|
||||||
|
ID = foo
|
||||||
|
num = 2
|
||||||
|
type = aws_instance
|
||||||
|
aws_instance.foo:
|
||||||
|
ID = foo
|
||||||
|
num = 2
|
||||||
|
type = aws_instance
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestContext2Apply_targetedModuleResource(t *testing.T) {
|
||||||
|
m := testModule(t, "apply-targeted-module-resource")
|
||||||
|
p := testProvider("aws")
|
||||||
|
p.ApplyFn = testApplyFn
|
||||||
|
p.DiffFn = testDiffFn
|
||||||
|
ctx := testContext2(t, &ContextOpts{
|
||||||
|
Module: m,
|
||||||
|
Providers: map[string]ResourceProviderFactory{
|
||||||
|
"aws": testProviderFuncFixed(p),
|
||||||
|
},
|
||||||
|
Targets: []string{"module.child.aws_instance.foo"},
|
||||||
|
})
|
||||||
|
|
||||||
|
if _, err := ctx.Plan(); err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
state, err := ctx.Apply()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
mod := state.ModuleByPath([]string{"root", "child"})
|
||||||
|
if len(mod.Resources) != 1 {
|
||||||
|
t.Fatalf("expected 1 resource, got: %#v", mod.Resources)
|
||||||
|
}
|
||||||
|
|
||||||
|
checkStateString(t, state, `
|
||||||
|
<no state>
|
||||||
|
module.child:
|
||||||
|
aws_instance.foo:
|
||||||
|
ID = foo
|
||||||
|
num = 2
|
||||||
|
type = aws_instance
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
|
||||||
func TestContext2Apply_unknownAttribute(t *testing.T) {
|
func TestContext2Apply_unknownAttribute(t *testing.T) {
|
||||||
m := testModule(t, "apply-unknown")
|
m := testModule(t, "apply-unknown")
|
||||||
p := testProvider("aws")
|
p := testProvider("aws")
|
||||||
|
|
|
@ -19,6 +19,8 @@ type GraphNodeConfigResource struct {
|
||||||
|
|
||||||
// Used during DynamicExpand to target indexes
|
// Used during DynamicExpand to target indexes
|
||||||
Targets []ResourceAddress
|
Targets []ResourceAddress
|
||||||
|
|
||||||
|
Path []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *GraphNodeConfigResource) ConfigType() GraphNodeConfigType {
|
func (n *GraphNodeConfigResource) ConfigType() GraphNodeConfigType {
|
||||||
|
@ -174,7 +176,7 @@ func (n *GraphNodeConfigResource) DynamicExpand(ctx EvalContext) (*Graph, error)
|
||||||
// GraphNodeAddressable impl.
|
// GraphNodeAddressable impl.
|
||||||
func (n *GraphNodeConfigResource) ResourceAddress() *ResourceAddress {
|
func (n *GraphNodeConfigResource) ResourceAddress() *ResourceAddress {
|
||||||
return &ResourceAddress{
|
return &ResourceAddress{
|
||||||
// Indicates no specific index; will match on other three fields
|
Path: n.Path[1:],
|
||||||
Index: -1,
|
Index: -1,
|
||||||
InstanceType: TypePrimary,
|
InstanceType: TypePrimary,
|
||||||
Name: n.Resource.Name,
|
Name: n.Resource.Name,
|
||||||
|
|
|
@ -2,14 +2,22 @@ package terraform
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"reflect"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ResourceAddress is a way of identifying an individual resource (or,
|
// ResourceAddress is a way of identifying an individual resource (or,
|
||||||
// eventually, a subset of resources) within the state. It is used for Targets.
|
// eventually, a subset of resources) within the state. It is used for Targets.
|
||||||
type ResourceAddress struct {
|
type ResourceAddress struct {
|
||||||
|
// Addresses a resource falling somewhere in the module path
|
||||||
|
// When specified alone, addresses all resources within a module path
|
||||||
|
Path []string
|
||||||
|
|
||||||
|
// Addresses a specific resource that occurs in a list
|
||||||
Index int
|
Index int
|
||||||
|
|
||||||
InstanceType InstanceType
|
InstanceType InstanceType
|
||||||
Name string
|
Name string
|
||||||
Type string
|
Type string
|
||||||
|
@ -20,22 +28,18 @@ func ParseResourceAddress(s string) (*ResourceAddress, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
resourceIndex := -1
|
resourceIndex, err := ParseResourceIndex(matches["index"])
|
||||||
if matches["index"] != "" {
|
if err != nil {
|
||||||
var err error
|
|
||||||
if resourceIndex, err = strconv.Atoi(matches["index"]); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
instanceType, err := ParseInstanceType(matches["instance_type"])
|
||||||
instanceType := TypePrimary
|
if err != nil {
|
||||||
if matches["instance_type"] != "" {
|
|
||||||
var err error
|
|
||||||
if instanceType, err = ParseInstanceType(matches["instance_type"]); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
path := ParseResourcePath(matches["path"])
|
||||||
|
|
||||||
return &ResourceAddress{
|
return &ResourceAddress{
|
||||||
|
Path: path,
|
||||||
Index: resourceIndex,
|
Index: resourceIndex,
|
||||||
InstanceType: instanceType,
|
InstanceType: instanceType,
|
||||||
Name: matches["name"],
|
Name: matches["name"],
|
||||||
|
@ -49,19 +53,55 @@ func (addr *ResourceAddress) Equals(raw interface{}) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pathMatch := ((len(addr.Path) == 0 && len(other.Path) == 0) ||
|
||||||
|
reflect.DeepEqual(addr.Path, other.Path))
|
||||||
|
|
||||||
indexMatch := (addr.Index == -1 ||
|
indexMatch := (addr.Index == -1 ||
|
||||||
other.Index == -1 ||
|
other.Index == -1 ||
|
||||||
addr.Index == other.Index)
|
addr.Index == other.Index)
|
||||||
|
|
||||||
return (indexMatch &&
|
nameMatch := (addr.Name == "" ||
|
||||||
addr.InstanceType == other.InstanceType &&
|
other.Name == "" ||
|
||||||
addr.Name == other.Name &&
|
addr.Name == other.Name)
|
||||||
|
|
||||||
|
typeMatch := (addr.Type == "" ||
|
||||||
|
other.Type == "" ||
|
||||||
addr.Type == other.Type)
|
addr.Type == other.Type)
|
||||||
|
|
||||||
|
return (pathMatch &&
|
||||||
|
indexMatch &&
|
||||||
|
addr.InstanceType == other.InstanceType &&
|
||||||
|
nameMatch &&
|
||||||
|
typeMatch)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseResourceIndex(s string) (int, error) {
|
||||||
|
if s == "" {
|
||||||
|
return -1, nil
|
||||||
|
}
|
||||||
|
return strconv.Atoi(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseResourcePath(s string) []string {
|
||||||
|
if s == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
parts := strings.Split(s, ".")
|
||||||
|
path := make([]string, 0, len(parts))
|
||||||
|
for _, s := range parts {
|
||||||
|
// Due to the limitations of the regexp match below, the path match has
|
||||||
|
// some noise in it we have to filter out :|
|
||||||
|
if s == "" || s == "module" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
path = append(path, s)
|
||||||
|
}
|
||||||
|
return path
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseInstanceType(s string) (InstanceType, error) {
|
func ParseInstanceType(s string) (InstanceType, error) {
|
||||||
switch s {
|
switch s {
|
||||||
case "primary":
|
case "", "primary":
|
||||||
return TypePrimary, nil
|
return TypePrimary, nil
|
||||||
case "deposed":
|
case "deposed":
|
||||||
return TypeDeposed, nil
|
return TypeDeposed, nil
|
||||||
|
@ -76,10 +116,10 @@ func tokenizeResourceAddress(s string) (map[string]string, error) {
|
||||||
// Example of portions of the regexp below using the
|
// Example of portions of the regexp below using the
|
||||||
// string "aws_instance.web.tainted[1]"
|
// string "aws_instance.web.tainted[1]"
|
||||||
re := regexp.MustCompile(`\A` +
|
re := regexp.MustCompile(`\A` +
|
||||||
// "aws_instance"
|
// "module.foo.module.bar" (optional)
|
||||||
`(?P<type>[^.]+)\.` +
|
`(?P<path>(?:module\.[^.]+\.?)*)` +
|
||||||
// "web"
|
// "aws_instance.web" (optional when module path specified)
|
||||||
`(?P<name>[^.[]+)` +
|
`(?:(?P<type>[^.]+)\.(?P<name>[^.[]+))?` +
|
||||||
// "tainted" (optional, omission implies: "primary")
|
// "tainted" (optional, omission implies: "primary")
|
||||||
`(?:\.(?P<instance_type>\w+))?` +
|
`(?:\.(?P<instance_type>\w+))?` +
|
||||||
// "1" (optional, omission implies: "0")
|
// "1" (optional, omission implies: "0")
|
||||||
|
|
|
@ -64,6 +64,46 @@ func TestParseResourceAddress(t *testing.T) {
|
||||||
Index: -1,
|
Index: -1,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"in a module": {
|
||||||
|
Input: "module.child.aws_instance.foo",
|
||||||
|
Expected: &ResourceAddress{
|
||||||
|
Path: []string{"child"},
|
||||||
|
Type: "aws_instance",
|
||||||
|
Name: "foo",
|
||||||
|
InstanceType: TypePrimary,
|
||||||
|
Index: -1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"nested modules": {
|
||||||
|
Input: "module.a.module.b.module.forever.aws_instance.foo",
|
||||||
|
Expected: &ResourceAddress{
|
||||||
|
Path: []string{"a", "b", "forever"},
|
||||||
|
Type: "aws_instance",
|
||||||
|
Name: "foo",
|
||||||
|
InstanceType: TypePrimary,
|
||||||
|
Index: -1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"just a module": {
|
||||||
|
Input: "module.a",
|
||||||
|
Expected: &ResourceAddress{
|
||||||
|
Path: []string{"a"},
|
||||||
|
Type: "",
|
||||||
|
Name: "",
|
||||||
|
InstanceType: TypePrimary,
|
||||||
|
Index: -1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"just a nested module": {
|
||||||
|
Input: "module.a.module.b",
|
||||||
|
Expected: &ResourceAddress{
|
||||||
|
Path: []string{"a", "b"},
|
||||||
|
Type: "",
|
||||||
|
Name: "",
|
||||||
|
InstanceType: TypePrimary,
|
||||||
|
Index: -1,
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for tn, tc := range cases {
|
for tn, tc := range cases {
|
||||||
|
@ -204,6 +244,57 @@ func TestResourceAddressEquals(t *testing.T) {
|
||||||
},
|
},
|
||||||
Expect: false,
|
Expect: false,
|
||||||
},
|
},
|
||||||
|
"module address matches address of resource inside module": {
|
||||||
|
Address: &ResourceAddress{
|
||||||
|
Path: []string{"a", "b"},
|
||||||
|
Type: "",
|
||||||
|
Name: "",
|
||||||
|
InstanceType: TypePrimary,
|
||||||
|
Index: -1,
|
||||||
|
},
|
||||||
|
Other: &ResourceAddress{
|
||||||
|
Path: []string{"a", "b"},
|
||||||
|
Type: "aws_instance",
|
||||||
|
Name: "foo",
|
||||||
|
InstanceType: TypePrimary,
|
||||||
|
Index: 0,
|
||||||
|
},
|
||||||
|
Expect: true,
|
||||||
|
},
|
||||||
|
"module address doesn't match resource outside module": {
|
||||||
|
Address: &ResourceAddress{
|
||||||
|
Path: []string{"a", "b"},
|
||||||
|
Type: "",
|
||||||
|
Name: "",
|
||||||
|
InstanceType: TypePrimary,
|
||||||
|
Index: -1,
|
||||||
|
},
|
||||||
|
Other: &ResourceAddress{
|
||||||
|
Path: []string{"a"},
|
||||||
|
Type: "aws_instance",
|
||||||
|
Name: "foo",
|
||||||
|
InstanceType: TypePrimary,
|
||||||
|
Index: 0,
|
||||||
|
},
|
||||||
|
Expect: false,
|
||||||
|
},
|
||||||
|
"nil path vs empty path should match": {
|
||||||
|
Address: &ResourceAddress{
|
||||||
|
Path: []string{},
|
||||||
|
Type: "aws_instance",
|
||||||
|
Name: "foo",
|
||||||
|
InstanceType: TypePrimary,
|
||||||
|
Index: -1,
|
||||||
|
},
|
||||||
|
Other: &ResourceAddress{
|
||||||
|
Path: nil,
|
||||||
|
Type: "aws_instance",
|
||||||
|
Name: "foo",
|
||||||
|
InstanceType: TypePrimary,
|
||||||
|
Index: 0,
|
||||||
|
},
|
||||||
|
Expect: true,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for tn, tc := range cases {
|
for tn, tc := range cases {
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
resource "aws_instance" "foo" {
|
||||||
|
num = "2"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_instance" "bar" {
|
||||||
|
num = "2"
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
module "child" {
|
||||||
|
source = "./child"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_instance" "bar" {
|
||||||
|
foo = "bar"
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
resource "aws_instance" "foo" {
|
||||||
|
num = "2"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_instance" "bar" {
|
||||||
|
num = "2"
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
module "child" {
|
||||||
|
source = "./child"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_instance" "foo" {
|
||||||
|
foo = "bar"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_instance" "bar" {
|
||||||
|
foo = "bar"
|
||||||
|
}
|
|
@ -55,7 +55,10 @@ func (t *ConfigTransformer) Transform(g *Graph) error {
|
||||||
|
|
||||||
// Write all the resources out
|
// Write all the resources out
|
||||||
for _, r := range config.Resources {
|
for _, r := range config.Resources {
|
||||||
nodes = append(nodes, &GraphNodeConfigResource{Resource: r})
|
nodes = append(nodes, &GraphNodeConfigResource{
|
||||||
|
Resource: r,
|
||||||
|
Path: g.Path,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write all the modules out
|
// Write all the modules out
|
||||||
|
|
|
@ -44,6 +44,7 @@ func (t *ResourceCountTransformer) Transform(g *Graph) error {
|
||||||
var node dag.Vertex = &graphNodeExpandedResource{
|
var node dag.Vertex = &graphNodeExpandedResource{
|
||||||
Index: index,
|
Index: index,
|
||||||
Resource: t.Resource,
|
Resource: t.Resource,
|
||||||
|
Path: g.Path,
|
||||||
}
|
}
|
||||||
if t.Destroy {
|
if t.Destroy {
|
||||||
node = &graphNodeExpandedResourceDestroy{
|
node = &graphNodeExpandedResourceDestroy{
|
||||||
|
@ -93,6 +94,7 @@ func (t *ResourceCountTransformer) nodeIsTargeted(node dag.Vertex) bool {
|
||||||
type graphNodeExpandedResource struct {
|
type graphNodeExpandedResource struct {
|
||||||
Index int
|
Index int
|
||||||
Resource *config.Resource
|
Resource *config.Resource
|
||||||
|
Path []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *graphNodeExpandedResource) Name() string {
|
func (n *graphNodeExpandedResource) Name() string {
|
||||||
|
@ -112,8 +114,8 @@ func (n *graphNodeExpandedResource) ResourceAddress() *ResourceAddress {
|
||||||
index = 0
|
index = 0
|
||||||
}
|
}
|
||||||
return &ResourceAddress{
|
return &ResourceAddress{
|
||||||
|
Path: n.Path[1:],
|
||||||
Index: index,
|
Index: index,
|
||||||
// TODO: kjkjkj
|
|
||||||
InstanceType: TypePrimary,
|
InstanceType: TypePrimary,
|
||||||
Name: n.Resource.Name,
|
Name: n.Resource.Name,
|
||||||
Type: n.Resource.Type,
|
Type: n.Resource.Type,
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
package terraform
|
package terraform
|
||||||
|
|
||||||
import "github.com/hashicorp/terraform/dag"
|
import (
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/dag"
|
||||||
|
)
|
||||||
|
|
||||||
// TargetsTransformer is a GraphTransformer that, when the user specifies a
|
// TargetsTransformer is a GraphTransformer that, when the user specifies a
|
||||||
// list of resources to target, limits the graph to only those resources and
|
// list of resources to target, limits the graph to only those resources and
|
||||||
|
@ -30,6 +34,7 @@ func (t *TargetsTransformer) Transform(g *Graph) error {
|
||||||
for _, v := range g.Vertices() {
|
for _, v := range g.Vertices() {
|
||||||
if _, ok := v.(GraphNodeAddressable); ok {
|
if _, ok := v.(GraphNodeAddressable); ok {
|
||||||
if !targetedNodes.Include(v) {
|
if !targetedNodes.Include(v) {
|
||||||
|
log.Printf("[DEBUG] Removing %s, filtered by targeting.", v)
|
||||||
g.Remove(v)
|
g.Remove(v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,19 +10,34 @@ description: |-
|
||||||
# Resource Addressing
|
# Resource Addressing
|
||||||
|
|
||||||
A __Resource Address__ is a string that references a specific resource in a
|
A __Resource Address__ is a string that references a specific resource in a
|
||||||
larger infrastructure. The syntax of a resource address is:
|
larger infrastructure. An address is made up of two parts:
|
||||||
|
|
||||||
```
|
```
|
||||||
<resource_type>.<resource_name>[optional fields]
|
[module path][resource spec]
|
||||||
```
|
```
|
||||||
|
|
||||||
Required fields:
|
__Module path__:
|
||||||
|
|
||||||
|
A module path addresses a module within the tree of modules. It takes the form:
|
||||||
|
|
||||||
|
```
|
||||||
|
module.A.module.B.module.C...
|
||||||
|
```
|
||||||
|
|
||||||
|
Multiple modules in a path indicate nesting. If a module path is specified
|
||||||
|
without a resource spec, the address applies to every resource within the
|
||||||
|
module. If the module path is omitted, this addresses the root module.
|
||||||
|
|
||||||
|
__Resource spec__:
|
||||||
|
|
||||||
|
A resource spec addresses a specific resource in the config. It takes the form:
|
||||||
|
|
||||||
|
```
|
||||||
|
resource_type.resource_name[N]
|
||||||
|
```
|
||||||
|
|
||||||
* `resource_type` - Type of the resource being addressed.
|
* `resource_type` - Type of the resource being addressed.
|
||||||
* `resource_name` - User-defined name of the resource.
|
* `resource_name` - User-defined name of the resource.
|
||||||
|
|
||||||
Optional fields may include:
|
|
||||||
|
|
||||||
* `[N]` - where `N` is a `0`-based index into a resource with multiple
|
* `[N]` - where `N` is a `0`-based index into a resource with multiple
|
||||||
instances specified by the `count` meta-parameter. Omitting an index when
|
instances specified by the `count` meta-parameter. Omitting an index when
|
||||||
addressing a resource where `count > 1` means that the address references
|
addressing a resource where `count > 1` means that the address references
|
||||||
|
|
Loading…
Reference in New Issue