[Rancher] - allow for importing resources using environment ID to target (#11688)

This commit is contained in:
John Engelman 2017-02-05 04:35:48 -06:00 committed by Paul Stack
parent 64e2381cb2
commit 1efd5ff814
18 changed files with 256 additions and 61 deletions

View File

@ -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"

View File

@ -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
}

View File

@ -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)

View File

@ -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" {

View File

@ -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
}

View File

@ -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 {

View File

@ -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
}

View File

@ -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
}

View File

@ -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 {

View File

@ -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 {

View File

@ -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
}

View File

@ -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 {

View File

@ -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
}

View File

@ -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)
}
}
}

View File

@ -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 `<environment_id>/<registration_token_id>`.
```
$ 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

View File

@ -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
`<environment_id>/<registry_id>`
```
$ 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

View File

@ -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 `<registry_id>/<credential_id>`
```
$ 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

View File

@ -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
`<environment_id>/<stack_id>`
```
$ 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