Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 32 additions & 2 deletions cloudstack/resource_cloudstack_instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,19 @@ func resourceCloudStackInstanceCreate(d *schema.ResourceData, meta interface{})

if zone.Networktype == "Advanced" {
// Set the default network ID
p.SetNetworkids([]string{d.Get("network_id").(string)})
networkID := d.Get("network_id").(string)
p.SetNetworkids([]string{networkID})

// If no project is explicitly set, try to inherit it from the network
if _, ok := d.GetOk("project"); !ok && networkID != "" {
// Get the network to retrieve its project
// Use projectid=-1 to search across all projects
network, count, err := cs.Network.GetNetworkByID(networkID, cloudstack.WithProject("-1"))
if err == nil && count > 0 && network.Projectid != "" {
log.Printf("[DEBUG] Inheriting project %s from network %s", network.Projectid, networkID)
p.SetProjectid(network.Projectid)
}
}
}

// If there is a ipaddres supplied, add it to the parameter struct
Expand Down Expand Up @@ -414,6 +426,7 @@ func resourceCloudStackInstanceCreate(d *schema.ResourceData, meta interface{})
}

// If there is a project supplied, we retrieve and set the project id
// This will override the inherited project from network if explicitly set
if err := setProjectid(p, cs, d); err != nil {
return err
}
Expand Down Expand Up @@ -497,10 +510,22 @@ func resourceCloudStackInstanceRead(d *schema.ResourceData, meta interface{}) er
cs := meta.(*cloudstack.CloudStackClient)

// Get the virtual machine details
// First try with the project from state (if any)
project := d.Get("project").(string)
vm, count, err := cs.VirtualMachine.GetVirtualMachineByID(
d.Id(),
cloudstack.WithProject(d.Get("project").(string)),
cloudstack.WithProject(project),
)

// If not found and no explicit project was set, try with projectid=-1
// This handles the case where the project was inherited from network
if count == 0 && project == "" {
vm, count, err = cs.VirtualMachine.GetVirtualMachineByID(
d.Id(),
cloudstack.WithProject("-1"),
)
}

if err != nil {
if count == 0 {
log.Printf("[DEBUG] Instance %s does no longer exist", d.Get("name").(string))
Expand All @@ -516,6 +541,11 @@ func resourceCloudStackInstanceRead(d *schema.ResourceData, meta interface{}) er
d.Set("display_name", vm.Displayname)
d.Set("group", vm.Group)

// Set the project if the instance belongs to one
if vm.Project != "" {
d.Set("project", vm.Project)
}

// In some rare cases (when destroying a machine fails) it can happen that
// an instance does not have any attached NIC anymore.
if len(vm.Nic) > 0 {
Expand Down
56 changes: 56 additions & 0 deletions cloudstack/resource_cloudstack_instance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,29 @@ func TestAccCloudStackInstance_project(t *testing.T) {
})
}

func TestAccCloudStackInstance_networkProjectInheritance(t *testing.T) {
var instance cloudstack.VirtualMachine

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckCloudStackInstanceDestroy,
Steps: []resource.TestStep{
{
Config: testAccCloudStackInstance_networkProjectInheritance,
Check: resource.ComposeTestCheckFunc(
testAccCheckCloudStackInstanceExists(
"cloudstack_instance.foobar", &instance),
// Verify the project was inherited from the network
resource.TestCheckResourceAttr(
"cloudstack_instance.foobar", "project", "terraform"),
testAccCheckCloudStackInstanceProjectInherited(&instance),
),
},
},
})
}

func TestAccCloudStackInstance_import(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Expand Down Expand Up @@ -371,6 +394,18 @@ func testAccCheckCloudStackInstanceRenamedAndResized(
}
}

func testAccCheckCloudStackInstanceProjectInherited(
instance *cloudstack.VirtualMachine) resource.TestCheckFunc {
return func(s *terraform.State) error {

if instance.Project != "terraform" {
return fmt.Errorf("Expected project to be 'terraform' (inherited from network), got: %s", instance.Project)
}

return nil
}
}

func testAccCheckCloudStackInstanceDestroy(s *terraform.State) error {
cs := testAccProvider.Meta().(*cloudstack.CloudStackClient)

Expand Down Expand Up @@ -576,3 +611,24 @@ ${random_bytes.string.base64}
EOF
EOFTF
}`

const testAccCloudStackInstance_networkProjectInheritance = `
resource "cloudstack_network" "foo" {
name = "terraform-network"
display_text = "terraform-network"
cidr = "10.1.1.0/24"
network_offering = "DefaultIsolatedNetworkOfferingWithSourceNatService"
project = "terraform"
zone = "Sandbox-simulator"
}
resource "cloudstack_instance" "foobar" {
name = "terraform-test"
display_name = "terraform-test"
service_offering= "Small Instance"
network_id = cloudstack_network.foo.id
template = "CentOS 5.6 (64-bit) no GUI (Simulator)"
zone = cloudstack_network.foo.zone
expunge = true
# Note: project is NOT specified here - it should be inherited from the network
}`
24 changes: 24 additions & 0 deletions cloudstack/resource_cloudstack_ipaddress.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,33 @@ func resourceCloudStackIPAddressCreate(d *schema.ResourceData, meta interface{})
if vpcid, ok := d.GetOk("vpc_id"); ok && vpcid.(string) != "" {
return fmt.Errorf("set only network_id or vpc_id")
}

// If no project is explicitly set, try to inherit it from the network
if _, ok := d.GetOk("project"); !ok {
// Get the network to retrieve its project
// Use projectid=-1 to search across all projects
network, count, err := cs.Network.GetNetworkByID(networkid.(string), cloudstack.WithProject("-1"))
if err == nil && count > 0 && network.Projectid != "" {
log.Printf("[DEBUG] Inheriting project %s from network %s", network.Projectid, networkid.(string))
p.SetProjectid(network.Projectid)
}
}
}

if vpcid, ok := d.GetOk("vpc_id"); ok {
// Set the vpcid
p.SetVpcid(vpcid.(string))

// If no project is explicitly set, try to inherit it from the VPC
if _, ok := d.GetOk("project"); !ok {
// Get the VPC to retrieve its project
// Use projectid=-1 to search across all projects
vpc, count, err := cs.VPC.GetVPCByID(vpcid.(string), cloudstack.WithProject("-1"))
if err == nil && count > 0 && vpc.Projectid != "" {
log.Printf("[DEBUG] Inheriting project %s from VPC %s", vpc.Projectid, vpcid.(string))
p.SetProjectid(vpc.Projectid)
}
}
}

if zone, ok := d.GetOk("zone"); ok {
Expand All @@ -121,6 +143,7 @@ func resourceCloudStackIPAddressCreate(d *schema.ResourceData, meta interface{})
}

// If there is a project supplied, we retrieve and set the project id
// This will override the inherited project from VPC or network if explicitly set
if err := setProjectid(p, cs, d); err != nil {
return err
}
Expand Down Expand Up @@ -150,6 +173,7 @@ func resourceCloudStackIPAddressRead(d *schema.ResourceData, meta interface{}) e
d.Id(),
cloudstack.WithProject(d.Get("project").(string)),
)

if err != nil {
if count == 0 {
log.Printf(
Expand Down
89 changes: 89 additions & 0 deletions cloudstack/resource_cloudstack_ipaddress_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,52 @@ func TestAccCloudStackIPAddress_vpcid_with_network_id(t *testing.T) {
})
}

func TestAccCloudStackIPAddress_vpcProjectInheritance(t *testing.T) {
var ipaddr cloudstack.PublicIpAddress

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckCloudStackIPAddressDestroy,
Steps: []resource.TestStep{
{
Config: testAccCloudStackIPAddress_vpcProjectInheritance,
Check: resource.ComposeTestCheckFunc(
testAccCheckCloudStackIPAddressExists(
"cloudstack_ipaddress.foo", &ipaddr),
// Verify the project was inherited from the VPC
resource.TestCheckResourceAttr(
"cloudstack_ipaddress.foo", "project", "terraform"),
testAccCheckCloudStackIPAddressProjectInherited(&ipaddr),
),
},
},
})
}

func TestAccCloudStackIPAddress_networkProjectInheritance(t *testing.T) {
var ipaddr cloudstack.PublicIpAddress

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckCloudStackIPAddressDestroy,
Steps: []resource.TestStep{
{
Config: testAccCloudStackIPAddress_networkProjectInheritance,
Check: resource.ComposeTestCheckFunc(
testAccCheckCloudStackIPAddressExists(
"cloudstack_ipaddress.foo", &ipaddr),
// Verify the project was inherited from the network
resource.TestCheckResourceAttr(
"cloudstack_ipaddress.foo", "project", "terraform"),
testAccCheckCloudStackIPAddressProjectInherited(&ipaddr),
),
},
},
})
}

func testAccCheckCloudStackIPAddressExists(
n string, ipaddr *cloudstack.PublicIpAddress) resource.TestCheckFunc {
return func(s *terraform.State) error {
Expand Down Expand Up @@ -113,6 +159,18 @@ func testAccCheckCloudStackIPAddressExists(
}
}

func testAccCheckCloudStackIPAddressProjectInherited(
ipaddr *cloudstack.PublicIpAddress) resource.TestCheckFunc {
return func(s *terraform.State) error {

if ipaddr.Project != "terraform" {
return fmt.Errorf("Expected project to be 'terraform' (inherited from VPC or network), got: %s", ipaddr.Project)
}

return nil
}
}

func testAccCheckCloudStackIPAddressDestroy(s *terraform.State) error {
cs := testAccProvider.Meta().(*cloudstack.CloudStackClient)

Expand Down Expand Up @@ -186,3 +244,34 @@ resource "cloudstack_ipaddress" "foo" {
network_id = cloudstack_network.foo.id
zone = cloudstack_vpc.foo.zone
}`

const testAccCloudStackIPAddress_vpcProjectInheritance = `
resource "cloudstack_vpc" "foo" {
name = "terraform-vpc"
cidr = "10.0.0.0/8"
vpc_offering = "Default VPC offering"
project = "terraform"
zone = "Sandbox-simulator"
}
resource "cloudstack_ipaddress" "foo" {
vpc_id = cloudstack_vpc.foo.id
zone = cloudstack_vpc.foo.zone
# Note: project is NOT specified here - it should be inherited from the VPC
}`

const testAccCloudStackIPAddress_networkProjectInheritance = `
resource "cloudstack_network" "foo" {
name = "terraform-network"
display_text = "terraform-network"
cidr = "10.1.1.0/24"
network_offering = "DefaultIsolatedNetworkOfferingWithSourceNatService"
project = "terraform"
source_nat_ip = true
zone = "Sandbox-simulator"
}
resource "cloudstack_ipaddress" "foo" {
network_id = cloudstack_network.foo.id
# Note: project is NOT specified here - it should be inherited from the network
}`
31 changes: 29 additions & 2 deletions cloudstack/resource_cloudstack_network.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,9 +228,24 @@ func resourceCloudStackNetworkCreate(d *schema.ResourceData, meta interface{}) e
// Set the acl ID
p.SetAclid(aclid.(string))
}

// If no project is explicitly set, try to inherit it from the VPC
if _, ok := d.GetOk("project"); !ok {
// Get the VPC to retrieve its project
// Use listall to search across all projects
vpcParams := cs.VPC.NewListVPCsParams()
vpcParams.SetId(vpcid.(string))
vpcParams.SetListall(true)
vpcList, err := cs.VPC.ListVPCs(vpcParams)
if err == nil && vpcList.Count > 0 && vpcList.VPCs[0].Projectid != "" {
log.Printf("[DEBUG] Inheriting project %s from VPC %s", vpcList.VPCs[0].Projectid, vpcid.(string))
p.SetProjectid(vpcList.VPCs[0].Projectid)
}
}
}

// If there is a project supplied, we retrieve and set the project id
// This will override the inherited project from VPC if explicitly set
if err := setProjectid(p, cs, d); err != nil {
return err
}
Expand Down Expand Up @@ -283,11 +298,23 @@ func resourceCloudStackNetworkCreate(d *schema.ResourceData, meta interface{}) e
func resourceCloudStackNetworkRead(d *schema.ResourceData, meta interface{}) error {
cs := meta.(*cloudstack.CloudStackClient)

// Get the virtual machine details
// Get the network details
// First try with the project from state (if any)
project := d.Get("project").(string)
n, count, err := cs.Network.GetNetworkByID(
d.Id(),
cloudstack.WithProject(d.Get("project").(string)),
cloudstack.WithProject(project),
)

// If not found and no explicit project was set, try with projectid=-1
// This handles the case where the project was inherited from VPC
if count == 0 && project == "" {
n, count, err = cs.Network.GetNetworkByID(
d.Id(),
cloudstack.WithProject("-1"),
)
}

if err != nil {
if count == 0 {
log.Printf(
Expand Down
Loading