From 1efd5ff8143223d43e893a733799e3fbb9acedb2 Mon Sep 17 00:00:00 2001 From: John Engelman Date: Sun, 5 Feb 2017 04:35:48 -0600 Subject: [PATCH] [Rancher] - allow for importing resources using environment ID to target (#11688) --- builtin/providers/rancher/config.go | 21 ++++--- builtin/providers/rancher/provider.go | 2 +- .../rancher/resource_rancher_environment.go | 24 +++++-- .../resource_rancher_environment_test.go | 15 ++++- .../resource_rancher_registration_token.go | 19 ++++-- ...esource_rancher_registration_token_test.go | 11 +++- .../rancher/resource_rancher_registry.go | 19 ++++-- .../resource_rancher_registry_credential.go | 19 ++++-- ...source_rancher_registry_credential_test.go | 12 +++- .../rancher/resource_rancher_registry_test.go | 12 +++- .../rancher/resource_rancher_stack.go | 28 ++++++--- .../rancher/resource_rancher_stack_test.go | 12 +++- builtin/providers/rancher/util.go | 21 +++++-- builtin/providers/rancher/util_test.go | 62 +++++++++++++++++++ .../r/registration_token.html.markdown | 10 ++- .../rancher/r/registry.html.markdown | 10 ++- .../r/registry_credential.html.markdown | 10 ++- .../providers/rancher/r/stack.html.markdown | 10 ++- 18 files changed, 256 insertions(+), 61 deletions(-) create mode 100644 builtin/providers/rancher/util_test.go diff --git a/builtin/providers/rancher/config.go b/builtin/providers/rancher/config.go index a17a91ab68..55b1a1b850 100644 --- a/builtin/providers/rancher/config.go +++ b/builtin/providers/rancher/config.go @@ -7,31 +7,30 @@ import ( "github.com/raphink/go-rancher/catalog" ) +// Config is the configuration parameters for a Rancher API type Config struct { - *rancherClient.RancherClient APIURL string AccessKey string SecretKey string } -// Create creates a generic Rancher client -func (c *Config) CreateClient() error { +// GlobalClient creates a Rancher client scoped to the global API +func (c *Config) GlobalClient() (*rancherClient.RancherClient, error) { client, err := rancherClient.NewRancherClient(&rancherClient.ClientOpts{ Url: c.APIURL, AccessKey: c.AccessKey, SecretKey: c.SecretKey, }) if err != nil { - return err + return nil, err } log.Printf("[INFO] Rancher Client configured for url: %s", c.APIURL) - c.RancherClient = client - - return nil + return client, nil } +// EnvironmentClient creates a Rancher client scoped to an Environment's API func (c *Config) EnvironmentClient(env string) (*rancherClient.RancherClient, error) { url := c.APIURL + "/projects/" + env + "/schemas" @@ -49,8 +48,13 @@ func (c *Config) EnvironmentClient(env string) (*rancherClient.RancherClient, er return client, nil } +// RegistryClient creates a Rancher client scoped to a Registry's API func (c *Config) RegistryClient(id string) (*rancherClient.RancherClient, error) { - reg, err := c.Registry.ById(id) + client, err := c.GlobalClient() + if err != nil { + return nil, err + } + reg, err := client.Registry.ById(id) if err != nil { return nil, err } @@ -58,6 +62,7 @@ func (c *Config) RegistryClient(id string) (*rancherClient.RancherClient, error) return c.EnvironmentClient(reg.AccountId) } +// CatalogClient creates a Rancher client scoped to a Catalog's API func (c *Config) CatalogClient() (*catalog.RancherClient, error) { url := c.APIURL + "-catalog/schemas" diff --git a/builtin/providers/rancher/provider.go b/builtin/providers/rancher/provider.go index e553b649ef..e13052bfa8 100644 --- a/builtin/providers/rancher/provider.go +++ b/builtin/providers/rancher/provider.go @@ -60,7 +60,7 @@ func providerConfigure(d *schema.ResourceData) (interface{}, error) { SecretKey: d.Get("secret_key").(string), } - err := config.CreateClient() + _, err := config.GlobalClient() return config, err } diff --git a/builtin/providers/rancher/resource_rancher_environment.go b/builtin/providers/rancher/resource_rancher_environment.go index 33ae2913e8..99c79c61b4 100644 --- a/builtin/providers/rancher/resource_rancher_environment.go +++ b/builtin/providers/rancher/resource_rancher_environment.go @@ -47,7 +47,10 @@ func resourceRancherEnvironment() *schema.Resource { func resourceRancherEnvironmentCreate(d *schema.ResourceData, meta interface{}) error { log.Printf("[INFO] Creating Environment: %s", d.Id()) - client := meta.(*Config) + client, err := meta.(*Config).GlobalClient() + if err != nil { + return err + } name := d.Get("name").(string) description := d.Get("description").(string) @@ -87,7 +90,10 @@ func resourceRancherEnvironmentCreate(d *schema.ResourceData, meta interface{}) func resourceRancherEnvironmentRead(d *schema.ResourceData, meta interface{}) error { log.Printf("[INFO] Refreshing Environment: %s", d.Id()) - client := meta.(*Config) + client, err := meta.(*Config).GlobalClient() + if err != nil { + return err + } env, err := client.Project.ById(d.Id()) if err != nil { @@ -110,13 +116,16 @@ func resourceRancherEnvironmentRead(d *schema.ResourceData, meta interface{}) er d.Set("description", env.Description) d.Set("name", env.Name) - d.Set("orchestration", GetActiveOrchestration(env)) + d.Set("orchestration", getActiveOrchestration(env)) return nil } func resourceRancherEnvironmentUpdate(d *schema.ResourceData, meta interface{}) error { - client := meta.(*Config) + client, err := meta.(*Config).GlobalClient() + if err != nil { + return err + } name := d.Get("name").(string) description := d.Get("description").(string) @@ -145,7 +154,10 @@ func resourceRancherEnvironmentUpdate(d *schema.ResourceData, meta interface{}) func resourceRancherEnvironmentDelete(d *schema.ResourceData, meta interface{}) error { log.Printf("[INFO] Deleting Environment: %s", d.Id()) id := d.Id() - client := meta.(*Config) + client, err := meta.(*Config).GlobalClient() + if err != nil { + return err + } env, err := client.Project.ById(id) if err != nil { @@ -193,7 +205,7 @@ func setOrchestrationFields(orchestration string, data map[string]interface{}) { // EnvironmentStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch // a Rancher Environment. -func EnvironmentStateRefreshFunc(client *Config, environmentID string) resource.StateRefreshFunc { +func EnvironmentStateRefreshFunc(client *rancherClient.RancherClient, environmentID string) resource.StateRefreshFunc { return func() (interface{}, string, error) { env, err := client.Project.ById(environmentID) diff --git a/builtin/providers/rancher/resource_rancher_environment_test.go b/builtin/providers/rancher/resource_rancher_environment_test.go index 23a49a6ff4..ec8a81d7c7 100644 --- a/builtin/providers/rancher/resource_rancher_environment_test.go +++ b/builtin/providers/rancher/resource_rancher_environment_test.go @@ -62,7 +62,10 @@ func TestAccRancherEnvironment_disappears(t *testing.T) { func testAccRancherEnvironmentDisappears(env *rancherClient.Project) resource.TestCheckFunc { return func(s *terraform.State) error { - client := testAccProvider.Meta().(*Config) + client, err := testAccProvider.Meta().(*Config).GlobalClient() + if err != nil { + return err + } if err := client.Project.Delete(env); err != nil { return fmt.Errorf("Error deleting Environment: %s", err) } @@ -96,7 +99,10 @@ func testAccCheckRancherEnvironmentExists(n string, env *rancherClient.Project) return fmt.Errorf("No App Name is set") } - client := testAccProvider.Meta().(*Config) + client, err := testAccProvider.Meta().(*Config).GlobalClient() + if err != nil { + return err + } foundEnv, err := client.Project.ById(rs.Primary.ID) if err != nil { @@ -114,7 +120,10 @@ func testAccCheckRancherEnvironmentExists(n string, env *rancherClient.Project) } func testAccCheckRancherEnvironmentDestroy(s *terraform.State) error { - client := testAccProvider.Meta().(*Config) + client, err := testAccProvider.Meta().(*Config).GlobalClient() + if err != nil { + return err + } for _, rs := range s.RootModule().Resources { if rs.Type != "rancher_environment" { diff --git a/builtin/providers/rancher/resource_rancher_registration_token.go b/builtin/providers/rancher/resource_rancher_registration_token.go index 1890303081..39403d20cc 100644 --- a/builtin/providers/rancher/resource_rancher_registration_token.go +++ b/builtin/providers/rancher/resource_rancher_registration_token.go @@ -205,12 +205,21 @@ func resourceRancherRegistrationTokenDelete(d *schema.ResourceData, meta interfa } func resourceRancherRegistrationTokenImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { - client := meta.(*Config) - regT, err := client.RegistrationToken.ById(d.Id()) - if err != nil { - return []*schema.ResourceData{}, err + envID, resourceID := splitID(d.Id()) + d.SetId(resourceID) + if envID != "" { + d.Set("environment_id", envID) + } else { + client, err := meta.(*Config).GlobalClient() + if err != nil { + return []*schema.ResourceData{}, err + } + token, err := client.RegistrationToken.ById(d.Id()) + if err != nil { + return []*schema.ResourceData{}, err + } + d.Set("environment_id", token.AccountId) } - d.Set("environment_id", regT.AccountId) return []*schema.ResourceData{d}, nil } diff --git a/builtin/providers/rancher/resource_rancher_registration_token_test.go b/builtin/providers/rancher/resource_rancher_registration_token_test.go index ea1cbe96d1..881192cbf4 100644 --- a/builtin/providers/rancher/resource_rancher_registration_token_test.go +++ b/builtin/providers/rancher/resource_rancher_registration_token_test.go @@ -136,7 +136,10 @@ func testAccCheckRancherRegistrationTokenExists(n string, regT *rancherClient.Re return fmt.Errorf("No App Name is set") } - client, _ := testAccProvider.Meta().(*Config).EnvironmentClient(rs.Primary.Attributes["environment_id"]) + client, err := testAccProvider.Meta().(*Config).EnvironmentClient(rs.Primary.Attributes["environment_id"]) + if err != nil { + return err + } foundRegT, err := client.RegistrationToken.ById(rs.Primary.ID) if err != nil { @@ -154,12 +157,16 @@ func testAccCheckRancherRegistrationTokenExists(n string, regT *rancherClient.Re } func testAccCheckRancherRegistrationTokenDestroy(s *terraform.State) error { - client := testAccProvider.Meta().(*Config) for _, rs := range s.RootModule().Resources { if rs.Type != "rancher_registration_token" { continue } + client, err := testAccProvider.Meta().(*Config).GlobalClient() + if err != nil { + return err + } + regT, err := client.RegistrationToken.ById(rs.Primary.ID) if err == nil { diff --git a/builtin/providers/rancher/resource_rancher_registry.go b/builtin/providers/rancher/resource_rancher_registry.go index 5bf5a619b1..13192988c2 100644 --- a/builtin/providers/rancher/resource_rancher_registry.go +++ b/builtin/providers/rancher/resource_rancher_registry.go @@ -211,12 +211,21 @@ func resourceRancherRegistryDelete(d *schema.ResourceData, meta interface{}) err } func resourceRancherRegistryImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { - client := meta.(*Config) - reg, err := client.Registry.ById(d.Id()) - if err != nil { - return []*schema.ResourceData{}, err + envID, resourceID := splitID(d.Id()) + d.SetId(resourceID) + if envID != "" { + d.Set("environment_id", envID) + } else { + client, err := meta.(*Config).GlobalClient() + if err != nil { + return []*schema.ResourceData{}, err + } + registry, err := client.Registry.ById(d.Id()) + if err != nil { + return []*schema.ResourceData{}, err + } + d.Set("environment_id", registry.AccountId) } - d.Set("environment_id", reg.AccountId) return []*schema.ResourceData{d}, nil } diff --git a/builtin/providers/rancher/resource_rancher_registry_credential.go b/builtin/providers/rancher/resource_rancher_registry_credential.go index 45b21dc783..bf051e40ac 100644 --- a/builtin/providers/rancher/resource_rancher_registry_credential.go +++ b/builtin/providers/rancher/resource_rancher_registry_credential.go @@ -233,12 +233,21 @@ func resourceRancherRegistryCredentialDelete(d *schema.ResourceData, meta interf } func resourceRancherRegistryCredentialImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { - client := meta.(*Config) - regC, err := client.RegistryCredential.ById(d.Id()) - if err != nil { - return []*schema.ResourceData{}, err + regID, resourceID := splitID(d.Id()) + d.SetId(resourceID) + if regID != "" { + d.Set("registry_id", regID) + } else { + client, err := meta.(*Config).GlobalClient() + if err != nil { + return []*schema.ResourceData{}, err + } + cred, err := client.RegistryCredential.ById(d.Id()) + if err != nil { + return []*schema.ResourceData{}, err + } + d.Set("registry_id", cred.RegistryId) } - d.Set("environment_id", regC.AccountId) return []*schema.ResourceData{d}, nil } diff --git a/builtin/providers/rancher/resource_rancher_registry_credential_test.go b/builtin/providers/rancher/resource_rancher_registry_credential_test.go index fd6a42be4b..4ff52ffaa5 100644 --- a/builtin/providers/rancher/resource_rancher_registry_credential_test.go +++ b/builtin/providers/rancher/resource_rancher_registry_credential_test.go @@ -129,7 +129,10 @@ func testAccCheckRancherRegistryCredentialExists(n string, reg *rancherClient.Re return fmt.Errorf("No App Name is set") } - client, _ := testAccProvider.Meta().(*Config).RegistryClient(rs.Primary.Attributes["registry_id"]) + client, err := testAccProvider.Meta().(*Config).RegistryClient(rs.Primary.Attributes["registry_id"]) + if err != nil { + return err + } foundReg, err := client.RegistryCredential.ById(rs.Primary.ID) if err != nil { @@ -147,12 +150,15 @@ func testAccCheckRancherRegistryCredentialExists(n string, reg *rancherClient.Re } func testAccCheckRancherRegistryCredentialDestroy(s *terraform.State) error { - client := testAccProvider.Meta().(*Config) - for _, rs := range s.RootModule().Resources { if rs.Type != "rancher_registry_credential" { continue } + client, err := testAccProvider.Meta().(*Config).GlobalClient() + if err != nil { + return err + } + reg, err := client.RegistryCredential.ById(rs.Primary.ID) if err == nil { diff --git a/builtin/providers/rancher/resource_rancher_registry_test.go b/builtin/providers/rancher/resource_rancher_registry_test.go index 5550284fb8..d999d925e5 100644 --- a/builtin/providers/rancher/resource_rancher_registry_test.go +++ b/builtin/providers/rancher/resource_rancher_registry_test.go @@ -138,7 +138,10 @@ func testAccCheckRancherRegistryExists(n string, reg *rancherClient.Registry) re return fmt.Errorf("No App Name is set") } - client, _ := testAccProvider.Meta().(*Config).EnvironmentClient(rs.Primary.Attributes["environment_id"]) + client, err := testAccProvider.Meta().(*Config).EnvironmentClient(rs.Primary.Attributes["environment_id"]) + if err != nil { + return err + } foundReg, err := client.Registry.ById(rs.Primary.ID) if err != nil { @@ -156,12 +159,15 @@ func testAccCheckRancherRegistryExists(n string, reg *rancherClient.Registry) re } func testAccCheckRancherRegistryDestroy(s *terraform.State) error { - client := testAccProvider.Meta().(*Config) - for _, rs := range s.RootModule().Resources { if rs.Type != "rancher_registry" { continue } + client, err := testAccProvider.Meta().(*Config).GlobalClient() + if err != nil { + return err + } + reg, err := client.Registry.ById(rs.Primary.ID) if err == nil { diff --git a/builtin/providers/rancher/resource_rancher_stack.go b/builtin/providers/rancher/resource_rancher_stack.go index ea0a08fd3c..4e53df457e 100644 --- a/builtin/providers/rancher/resource_rancher_stack.go +++ b/builtin/providers/rancher/resource_rancher_stack.go @@ -156,10 +156,13 @@ func resourceRancherStackRead(d *schema.ResourceData, meta interface{}) error { dockerCompose := strings.Replace(config.DockerComposeConfig, "\r", "", -1) rancherCompose := strings.Replace(config.RancherComposeConfig, "\r", "", -1) - catalogId := d.Get("catalog_id") - if catalogId == "" { + catalogID := d.Get("catalog_id") + if catalogID == "" { d.Set("docker_compose", dockerCompose) d.Set("rancher_compose", rancherCompose) + } else { + d.Set("docker_compose", "") + d.Set("rancher_compose", "") } d.Set("rendered_docker_compose", dockerCompose) d.Set("rendered_rancher_compose", rancherCompose) @@ -203,7 +206,7 @@ func resourceRancherStackUpdate(d *schema.ResourceData, meta interface{}) error } var newStack rancherClient.Environment - if err := client.Update("environment", &stack.Resource, data, &newStack); err != nil { + if err = client.Update("environment", &stack.Resource, data, &newStack); err != nil { return err } @@ -334,12 +337,21 @@ func resourceRancherStackDelete(d *schema.ResourceData, meta interface{}) error } func resourceRancherStackImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { - client := meta.(*Config) - stack, err := client.Environment.ById(d.Id()) - if err != nil { - return []*schema.ResourceData{}, err + envID, resourceID := splitID(d.Id()) + d.SetId(resourceID) + if envID != "" { + d.Set("environment_id", envID) + } else { + client, err := meta.(*Config).GlobalClient() + if err != nil { + return []*schema.ResourceData{}, err + } + stack, err := client.Environment.ById(d.Id()) + if err != nil { + return []*schema.ResourceData{}, err + } + d.Set("environment_id", stack.AccountId) } - d.Set("environment_id", stack.AccountId) return []*schema.ResourceData{d}, nil } diff --git a/builtin/providers/rancher/resource_rancher_stack_test.go b/builtin/providers/rancher/resource_rancher_stack_test.go index 189d48395e..fd7e22af4c 100644 --- a/builtin/providers/rancher/resource_rancher_stack_test.go +++ b/builtin/providers/rancher/resource_rancher_stack_test.go @@ -177,7 +177,10 @@ func testAccCheckRancherStackExists(n string, stack *rancherClient.Environment) return fmt.Errorf("No App Name is set") } - client, _ := testAccProvider.Meta().(*Config).EnvironmentClient(rs.Primary.Attributes["environment_id"]) + client, err := testAccProvider.Meta().(*Config).EnvironmentClient(rs.Primary.Attributes["environment_id"]) + if err != nil { + return err + } foundStack, err := client.Environment.ById(rs.Primary.ID) if err != nil { @@ -216,12 +219,15 @@ func testAccCheckRancherStackAttributes(stack *rancherClient.Environment, enviro } func testAccCheckRancherStackDestroy(s *terraform.State) error { - client := testAccProvider.Meta().(*Config) - for _, rs := range s.RootModule().Resources { if rs.Type != "rancher_stack" { continue } + client, err := testAccProvider.Meta().(*Config).GlobalClient() + if err != nil { + return err + } + stack, err := client.Environment.ById(rs.Primary.ID) if err == nil { diff --git a/builtin/providers/rancher/util.go b/builtin/providers/rancher/util.go index 1b7a50c853..60317bf578 100644 --- a/builtin/providers/rancher/util.go +++ b/builtin/providers/rancher/util.go @@ -1,14 +1,18 @@ package rancher -import "github.com/rancher/go-rancher/client" +import ( + "strings" + + "github.com/rancher/go-rancher/client" +) const ( - REMOVED = "removed" - PURGED = "purged" + stateRemoved = "removed" + statePurged = "purged" ) // GetActiveOrchestration get the name of the active orchestration for a environment -func GetActiveOrchestration(project *client.Project) string { +func getActiveOrchestration(project *client.Project) string { orch := "cattle" switch { @@ -24,5 +28,12 @@ func GetActiveOrchestration(project *client.Project) string { } func removed(state string) bool { - return state == REMOVED || state == PURGED + return state == stateRemoved || state == statePurged +} + +func splitID(id string) (envID, resourceID string) { + if strings.Contains(id, "/") { + return id[0:strings.Index(id, "/")], id[strings.Index(id, "/")+1:] + } + return "", id } diff --git a/builtin/providers/rancher/util_test.go b/builtin/providers/rancher/util_test.go new file mode 100644 index 0000000000..2592f8519f --- /dev/null +++ b/builtin/providers/rancher/util_test.go @@ -0,0 +1,62 @@ +package rancher + +import ( + "testing" + + "github.com/rancher/go-rancher/client" +) + +var idTests = []struct { + id string + envID string + resourceID string +}{ + {"1a05", "", "1a05"}, + {"1a05/1s234", "1a05", "1s234"}, +} + +func TestSplitId(t *testing.T) { + for _, tt := range idTests { + envID, resourceID := splitID(tt.id) + if envID != tt.envID || resourceID != tt.resourceID { + t.Errorf("splitId(%s) => [%s, %s]) want [%s, %s]", tt.id, envID, resourceID, tt.envID, tt.resourceID) + } + } +} + +var stateTests = []struct { + state string + removed bool +}{ + {"removed", true}, + {"purged", true}, + {"active", false}, +} + +func TestRemovedState(t *testing.T) { + for _, tt := range stateTests { + removed := removed(tt.state) + if removed != tt.removed { + t.Errorf("removed(%s) => %t, wants %t", tt.state, removed, tt.removed) + } + } +} + +var orchestrationTests = []struct { + project *client.Project + orchestration string +}{ + {&client.Project{}, "cattle"}, + {&client.Project{Swarm: true}, "swarm"}, + {&client.Project{Mesos: true}, "mesos"}, + {&client.Project{Kubernetes: true}, "kubernetes"}, +} + +func TestActiveOrchestration(t *testing.T) { + for _, tt := range orchestrationTests { + orchestration := getActiveOrchestration(tt.project) + if orchestration != tt.orchestration { + t.Errorf("getActiveOrchestration(%+v) => %s, wants %s", tt.project, orchestration, tt.orchestration) + } + } +} diff --git a/website/source/docs/providers/rancher/r/registration_token.html.markdown b/website/source/docs/providers/rancher/r/registration_token.html.markdown index b94d207f78..e377b16f10 100644 --- a/website/source/docs/providers/rancher/r/registration_token.html.markdown +++ b/website/source/docs/providers/rancher/r/registration_token.html.markdown @@ -39,7 +39,15 @@ The following attributes are exported: ## Import -Registration tokens can be imported using their Rancher API ID, e.g. +Registration tokens can be imported using the Environment and Registration token +IDs in the form `/`. + +``` +$ terraform import rancher_registration_token.dev_token 1a5/1c11 +``` + +If the credentials for the Rancher provider have access to the global API, then +then `environment_id` can be omitted e.g. ``` $ terraform import rancher_registration_token.dev_token 1c11 diff --git a/website/source/docs/providers/rancher/r/registry.html.markdown b/website/source/docs/providers/rancher/r/registry.html.markdown index 9183ae975c..a036308a09 100644 --- a/website/source/docs/providers/rancher/r/registry.html.markdown +++ b/website/source/docs/providers/rancher/r/registry.html.markdown @@ -37,7 +37,15 @@ No further attributes are exported. ## Import -Registries can be imported using their Rancher API ID, e.g. +Registries can be imported using the Environment and Registry IDs in the form +`/` + +``` +$ terraform import rancher_registry.private_registry 1a5/1sp31 +``` + +If the credentials for the Rancher provider have access to the global API, then +then `environment_id` can be omitted e.g. ``` $ terraform import rancher_registry.private_registry 1sp31 diff --git a/website/source/docs/providers/rancher/r/registry_credential.html.markdown b/website/source/docs/providers/rancher/r/registry_credential.html.markdown index 533d4f4fe1..d38806cebf 100644 --- a/website/source/docs/providers/rancher/r/registry_credential.html.markdown +++ b/website/source/docs/providers/rancher/r/registry_credential.html.markdown @@ -41,7 +41,15 @@ No further attributes are exported. ## Import -Registry credentials can be imported using their Rancher API ID, e.g. +Registry credentials can be imported using the Registry and credentials +IDs in the format `/` + +``` +$ terraform import rancher_registry_credential.private_registry 1sp31/1c605 +``` + +If the credentials for the Rancher provider have access to the global API, then +then `registry_id` can be omitted e.g. ``` $ terraform import rancher_registry_credential.private_registry 1c605 diff --git a/website/source/docs/providers/rancher/r/stack.html.markdown b/website/source/docs/providers/rancher/r/stack.html.markdown index ee5cd20f35..a567450adc 100644 --- a/website/source/docs/providers/rancher/r/stack.html.markdown +++ b/website/source/docs/providers/rancher/r/stack.html.markdown @@ -57,7 +57,15 @@ The following attributes are exported: ## Import -Stacks can be imported using their Rancher API ID, e.g. +Stacks can be imported using the Environment and Stack ID in the form +`/` + +``` +$ terraform import rancher_stack.foo 1a5/1e149 +``` + +If the credentials for the Rancher provider have access to the global API, then +then `environment_id` can be omitted e.g. ``` $ terraform import rancher_stack.foo 1e149