blob: b4d60c89ac4c55704f43208ae5a86076e70a7b17 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
package cloudstack
import (
"fmt"
"strings"
"testing"
"github.com/apache/cloudstack-go/v2/cloudstack"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/terraform"
)
func TestAccCloudStackProject_basic(t *testing.T) {
var project cloudstack.Project
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckCloudStackProjectDestroy,
Steps: []resource.TestStep{
{
Config: testAccCloudStackProject_basic,
Check: resource.ComposeTestCheckFunc(
testAccCheckCloudStackProjectExists(
"cloudstack_project.foo", &project),
resource.TestCheckResourceAttr(
"cloudstack_project.foo", "name", "terraform-test-project"),
resource.TestCheckResourceAttr(
"cloudstack_project.foo", "displaytext", "Terraform Test Project"),
),
},
},
})
}
func TestAccCloudStackProject_update(t *testing.T) {
var project cloudstack.Project
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckCloudStackProjectDestroy,
Steps: []resource.TestStep{
{
Config: testAccCloudStackProject_basic,
Check: resource.ComposeTestCheckFunc(
testAccCheckCloudStackProjectExists(
"cloudstack_project.foo", &project),
resource.TestCheckResourceAttr(
"cloudstack_project.foo", "name", "terraform-test-project"),
resource.TestCheckResourceAttr(
"cloudstack_project.foo", "displaytext", "Terraform Test Project"),
),
},
{
Config: testAccCloudStackProject_update,
Check: resource.ComposeTestCheckFunc(
testAccCheckCloudStackProjectExists(
"cloudstack_project.foo", &project),
resource.TestCheckResourceAttr(
"cloudstack_project.foo", "name", "terraform-test-project-updated"),
resource.TestCheckResourceAttr(
"cloudstack_project.foo", "displaytext", "Terraform Test Project Updated"),
),
},
},
})
}
func TestAccCloudStackProject_import(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckCloudStackProjectDestroy,
Steps: []resource.TestStep{
{
Config: testAccCloudStackProject_basic,
},
{
ResourceName: "cloudstack_project.foo",
ImportState: true,
ImportStateVerify: true,
},
},
})
}
func TestAccCloudStackProject_account(t *testing.T) {
var project cloudstack.Project
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckCloudStackProjectDestroy,
Steps: []resource.TestStep{
{
Config: testAccCloudStackProject_account,
Check: resource.ComposeTestCheckFunc(
testAccCheckCloudStackProjectExists(
"cloudstack_project.bar", &project),
resource.TestCheckResourceAttr(
"cloudstack_project.bar", "name", "terraform-test-project-account"),
resource.TestCheckResourceAttr(
"cloudstack_project.bar", "displaytext", "Terraform Test Project with Account"),
resource.TestCheckResourceAttr(
"cloudstack_project.bar", "account", "admin"),
),
},
},
})
}
func TestAccCloudStackProject_updateAccount(t *testing.T) {
var project cloudstack.Project
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckCloudStackProjectDestroy,
Steps: []resource.TestStep{
{
Config: testAccCloudStackProject_account,
Check: resource.ComposeTestCheckFunc(
testAccCheckCloudStackProjectExists(
"cloudstack_project.bar", &project),
resource.TestCheckResourceAttr(
"cloudstack_project.bar", "name", "terraform-test-project-account"),
resource.TestCheckResourceAttr(
"cloudstack_project.bar", "displaytext", "Terraform Test Project with Account"),
resource.TestCheckResourceAttr(
"cloudstack_project.bar", "account", "admin"),
),
},
{
Config: testAccCloudStackProject_updateAccount,
Check: resource.ComposeTestCheckFunc(
testAccCheckCloudStackProjectExists(
"cloudstack_project.bar", &project),
resource.TestCheckResourceAttr(
"cloudstack_project.bar", "name", "terraform-test-project-account"),
resource.TestCheckResourceAttr(
"cloudstack_project.bar", "displaytext", "Terraform Test Project with Account"),
resource.TestCheckResourceAttr(
"cloudstack_project.bar", "account", "admin"),
),
},
},
})
}
func TestAccCloudStackProject_emptyDisplayText(t *testing.T) {
var project cloudstack.Project
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckCloudStackProjectDestroy,
Steps: []resource.TestStep{
{
Config: testAccCloudStackProject_emptyDisplayText,
Check: resource.ComposeTestCheckFunc(
testAccCheckCloudStackProjectExists(
"cloudstack_project.empty", &project),
resource.TestCheckResourceAttr(
"cloudstack_project.empty", "name", "terraform-test-project-empty-display"),
resource.TestCheckResourceAttr(
"cloudstack_project.empty", "displaytext", "terraform-test-project-empty-display"),
),
},
},
})
}
func TestAccCloudStackProject_updateUserid(t *testing.T) {
var project cloudstack.Project
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckCloudStackProjectDestroy,
Steps: []resource.TestStep{
{
Config: testAccCloudStackProject_userid,
Check: resource.ComposeTestCheckFunc(
testAccCheckCloudStackProjectExists(
"cloudstack_project.baz", &project),
resource.TestCheckResourceAttr(
"cloudstack_project.baz", "name", "terraform-test-project-userid"),
resource.TestCheckResourceAttr(
"cloudstack_project.baz", "displaytext", "Terraform Test Project with Userid"),
),
},
{
Config: testAccCloudStackProject_updateUserid,
Check: resource.ComposeTestCheckFunc(
testAccCheckCloudStackProjectExists(
"cloudstack_project.baz", &project),
resource.TestCheckResourceAttr(
"cloudstack_project.baz", "name", "terraform-test-project-userid-updated"),
resource.TestCheckResourceAttr(
"cloudstack_project.baz", "displaytext", "Terraform Test Project with Userid Updated"),
),
},
},
})
}
func testAccCheckCloudStackProjectExists(
n string, project *cloudstack.Project) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
if !ok {
return fmt.Errorf("Not found: %s", n)
}
if rs.Primary.ID == "" {
return fmt.Errorf("No project ID is set")
}
cs := testAccProvider.Meta().(*cloudstack.CloudStackClient)
// Get domain if available
var domain string
if domainAttr, ok := rs.Primary.Attributes["domain"]; ok && domainAttr != "" {
domain = domainAttr
}
// First try to find the project by ID with domain if available
p := cs.Project.NewListProjectsParams()
p.SetId(rs.Primary.ID)
// Add domain if available
if domain != "" {
domainID, err := retrieveID(cs, "domain", domain)
if err == nil {
p.SetDomainid(domainID)
}
}
list, err := cs.Project.ListProjects(p)
if err == nil && list.Count > 0 && list.Projects[0].Id == rs.Primary.ID {
// Found by ID, set the project and return
*project = *list.Projects[0]
return nil
}
// If not found by ID or there was an error, try by name
if err != nil || list.Count == 0 || list.Projects[0].Id != rs.Primary.ID {
name := rs.Primary.Attributes["name"]
if name == "" {
return fmt.Errorf("Project not found by ID and name attribute is empty")
}
// Try to find by name
p := cs.Project.NewListProjectsParams()
p.SetName(name)
// Add domain if available
if domain, ok := rs.Primary.Attributes["domain"]; ok && domain != "" {
domainID, err := retrieveID(cs, "domain", domain)
if err != nil {
return fmt.Errorf("Error retrieving domain ID: %v", err)
}
p.SetDomainid(domainID)
}
list, err := cs.Project.ListProjects(p)
if err != nil {
return fmt.Errorf("Error retrieving project by name: %s", err)
}
if list.Count == 0 {
return fmt.Errorf("Project with name %s not found", name)
}
// Find the project with the matching ID if possible
found := false
for _, proj := range list.Projects {
if proj.Id == rs.Primary.ID {
*project = *proj
found = true
break
}
}
// If we didn't find a project with matching ID, use the first one
if !found {
*project = *list.Projects[0]
// Update the resource ID to match the found project
rs.Primary.ID = list.Projects[0].Id
}
return nil
}
return fmt.Errorf("Project not found by ID or name")
}
}
func testAccCheckCloudStackProjectDestroy(s *terraform.State) error {
cs := testAccProvider.Meta().(*cloudstack.CloudStackClient)
for _, rs := range s.RootModule().Resources {
if rs.Type != "cloudstack_project" {
continue
}
if rs.Primary.ID == "" {
return fmt.Errorf("No project ID is set")
}
// Get domain if available
var domain string
if domainAttr, ok := rs.Primary.Attributes["domain"]; ok && domainAttr != "" {
domain = domainAttr
}
// Try to find the project by ID
p := cs.Project.NewListProjectsParams()
p.SetId(rs.Primary.ID)
// Add domain if available
if domain != "" {
domainID, err := retrieveID(cs, "domain", domain)
if err == nil {
p.SetDomainid(domainID)
}
}
list, err := cs.Project.ListProjects(p)
// If we get an error, check if it's a "not found" error
if err != nil {
if strings.Contains(err.Error(), "not found") ||
strings.Contains(err.Error(), "does not exist") ||
strings.Contains(err.Error(), "could not be found") ||
strings.Contains(err.Error(), fmt.Sprintf(
"Invalid parameter id value=%s due to incorrect long value format, "+
"or entity does not exist", rs.Primary.ID)) {
// Project doesn't exist, which is what we want
continue
}
// For other errors, return them
return fmt.Errorf("error checking if project %s exists: %s", rs.Primary.ID, err)
}
// If we found the project, it still exists
if list.Count != 0 {
return fmt.Errorf("project %s still exists (found by ID)", rs.Primary.ID)
}
// Also check by name to be thorough
name := rs.Primary.Attributes["name"]
if name != "" {
// Try to find the project by name
p := cs.Project.NewListProjectsParams()
p.SetName(name)
// Add domain if available
if domain, ok := rs.Primary.Attributes["domain"]; ok && domain != "" {
domainID, err := retrieveID(cs, "domain", domain)
if err == nil {
p.SetDomainid(domainID)
}
}
list, err := cs.Project.ListProjects(p)
if err != nil {
// Ignore errors for name lookup
continue
}
// Check if any of the returned projects match our ID
for _, proj := range list.Projects {
if proj.Id == rs.Primary.ID {
return fmt.Errorf("project %s still exists (found by name %s)", rs.Primary.ID, name)
}
}
}
}
return nil
}
const testAccCloudStackProject_basic = `
resource "cloudstack_project" "foo" {
name = "terraform-test-project"
displaytext = "Terraform Test Project"
}`
const testAccCloudStackProject_update = `
resource "cloudstack_project" "foo" {
name = "terraform-test-project-updated"
displaytext = "Terraform Test Project Updated"
}`
const testAccCloudStackProject_account = `
resource "cloudstack_project" "bar" {
name = "terraform-test-project-account"
displaytext = "Terraform Test Project with Account"
account = "admin"
domain = "ROOT"
}`
const testAccCloudStackProject_updateAccount = `
resource "cloudstack_project" "bar" {
name = "terraform-test-project-account"
displaytext = "Terraform Test Project with Account"
account = "admin"
domain = "ROOT"
}`
const testAccCloudStackProject_userid = `
resource "cloudstack_project" "baz" {
name = "terraform-test-project-userid"
displaytext = "Terraform Test Project with Userid"
domain = "ROOT"
}`
const testAccCloudStackProject_updateUserid = `
resource "cloudstack_project" "baz" {
name = "terraform-test-project-userid-updated"
displaytext = "Terraform Test Project with Userid Updated"
domain = "ROOT"
}`
const testAccCloudStackProject_emptyDisplayText = `
resource "cloudstack_project" "empty" {
name = "terraform-test-project-empty-display"
displaytext = "terraform-test-project-empty-display"
}`
func TestAccCloudStackProject_updateAccountid(t *testing.T) {
var project cloudstack.Project
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckCloudStackProjectDestroy,
Steps: []resource.TestStep{
{
Config: testAccCloudStackProject_accountid,
Check: resource.ComposeTestCheckFunc(
testAccCheckCloudStackProjectExists(
"cloudstack_project.accountid_test", &project),
resource.TestCheckResourceAttr(
"cloudstack_project.accountid_test", "name", "terraform-test-project-accountid"),
resource.TestCheckResourceAttr(
"cloudstack_project.accountid_test", "displaytext", "Terraform Test Project with Accountid"),
resource.TestCheckResourceAttrSet(
"cloudstack_project.accountid_test", "accountid"),
),
},
{
Config: testAccCloudStackProject_updateAccountid,
Check: resource.ComposeTestCheckFunc(
testAccCheckCloudStackProjectExists(
"cloudstack_project.accountid_test", &project),
resource.TestCheckResourceAttr(
"cloudstack_project.accountid_test", "name", "terraform-test-project-accountid"),
resource.TestCheckResourceAttr(
"cloudstack_project.accountid_test", "displaytext", "Terraform Test Project with Accountid"),
resource.TestCheckResourceAttrSet(
"cloudstack_project.accountid_test", "accountid"),
),
},
},
})
}
func TestAccCloudStackProject_list(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckCloudStackProjectDestroy,
Steps: []resource.TestStep{
{
Config: testAccCloudStackProject_list,
Check: resource.ComposeTestCheckFunc(
testAccCheckCloudStackProjectsExist("cloudstack_project.project1", "cloudstack_project.project2"),
),
},
},
})
}
func testAccCheckCloudStackProjectsExist(projectNames ...string) resource.TestCheckFunc {
return func(s *terraform.State) error {
// Get CloudStack client
cs := testAccProvider.Meta().(*cloudstack.CloudStackClient)
// Create a map to track which projects we've found
foundProjects := make(map[string]bool)
for _, name := range projectNames {
// Get the project resource from state
rs, ok := s.RootModule().Resources[name]
if !ok {
return fmt.Errorf("Not found: %s", name)
}
if rs.Primary.ID == "" {
return fmt.Errorf("No project ID is set for %s", name)
}
// Add the project ID to our tracking map
foundProjects[rs.Primary.ID] = false
}
// List all projects
p := cs.Project.NewListProjectsParams()
list, err := cs.Project.ListProjects(p)
if err != nil {
return err
}
// Check if all our projects are in the list
for _, project := range list.Projects {
if _, exists := foundProjects[project.Id]; exists {
foundProjects[project.Id] = true
}
}
// Verify all projects were found
for id, found := range foundProjects {
if !found {
return fmt.Errorf("Project with ID %s was not found in the list", id)
}
}
return nil
}
}
const testAccCloudStackProject_accountid = `
resource "cloudstack_project" "accountid_test" {
name = "terraform-test-project-accountid"
displaytext = "Terraform Test Project with Accountid"
accountid = "1"
domain = "ROOT"
}`
const testAccCloudStackProject_updateAccountid = `
resource "cloudstack_project" "accountid_test" {
name = "terraform-test-project-accountid"
displaytext = "Terraform Test Project with Accountid"
accountid = "2"
domain = "ROOT"
}`
const testAccCloudStackProject_list = `
resource "cloudstack_project" "project1" {
name = "terraform-test-project-list-1"
displaytext = "Terraform Test Project List 1"
}
resource "cloudstack_project" "project2" {
name = "terraform-test-project-list-2"
displaytext = "Terraform Test Project List 2"
}`