github.com/koding/terraform@v0.6.4-0.20170608090606-5d7e0339779d/builtin/providers/rancher/resource_rancher_environment.go (about) 1 package rancher 2 3 import ( 4 "fmt" 5 "log" 6 "strings" 7 "time" 8 9 "github.com/hashicorp/terraform/helper/resource" 10 "github.com/hashicorp/terraform/helper/schema" 11 "github.com/hashicorp/terraform/helper/validation" 12 rancherClient "github.com/rancher/go-rancher/client" 13 ) 14 15 func resourceRancherEnvironment() *schema.Resource { 16 return &schema.Resource{ 17 Create: resourceRancherEnvironmentCreate, 18 Read: resourceRancherEnvironmentRead, 19 Update: resourceRancherEnvironmentUpdate, 20 Delete: resourceRancherEnvironmentDelete, 21 Importer: &schema.ResourceImporter{ 22 State: schema.ImportStatePassthrough, 23 }, 24 25 Schema: map[string]*schema.Schema{ 26 "id": &schema.Schema{ 27 Type: schema.TypeString, 28 Computed: true, 29 }, 30 "name": &schema.Schema{ 31 Type: schema.TypeString, 32 Required: true, 33 }, 34 "orchestration": &schema.Schema{ 35 Type: schema.TypeString, 36 Default: "cattle", 37 Optional: true, 38 ValidateFunc: validation.StringInSlice([]string{"cattle", "kubernetes", "mesos", "swarm"}, true), 39 }, 40 "description": &schema.Schema{ 41 Type: schema.TypeString, 42 Optional: true, 43 }, 44 "member": &schema.Schema{ 45 Type: schema.TypeSet, 46 Optional: true, 47 Computed: true, 48 Elem: &schema.Resource{ 49 Schema: map[string]*schema.Schema{ 50 "external_id_type": { 51 Type: schema.TypeString, 52 Required: true, 53 }, 54 "external_id": { 55 Type: schema.TypeString, 56 Required: true, 57 }, 58 "role": { 59 Type: schema.TypeString, 60 Required: true, 61 }, 62 }, 63 }, 64 }, 65 }, 66 } 67 } 68 69 func resourceRancherEnvironmentCreate(d *schema.ResourceData, meta interface{}) error { 70 log.Printf("[INFO] Creating Environment: %s", d.Id()) 71 client, err := meta.(*Config).GlobalClient() 72 if err != nil { 73 return err 74 } 75 76 name := d.Get("name").(string) 77 description := d.Get("description").(string) 78 orchestration := d.Get("orchestration").(string) 79 80 data := map[string]interface{}{ 81 "name": &name, 82 "description": &description, 83 } 84 85 setOrchestrationFields(orchestration, data) 86 87 var newEnv rancherClient.Project 88 if err := client.Create("project", data, &newEnv); err != nil { 89 return err 90 } 91 92 stateConf := &resource.StateChangeConf{ 93 Pending: []string{"active", "removed", "removing"}, 94 Target: []string{"active"}, 95 Refresh: EnvironmentStateRefreshFunc(client, newEnv.Id), 96 Timeout: 10 * time.Minute, 97 Delay: 1 * time.Second, 98 MinTimeout: 3 * time.Second, 99 } 100 _, waitErr := stateConf.WaitForState() 101 if waitErr != nil { 102 return fmt.Errorf( 103 "Error waiting for environment (%s) to be created: %s", newEnv.Id, waitErr) 104 } 105 106 d.SetId(newEnv.Id) 107 log.Printf("[INFO] Environment ID: %s", d.Id()) 108 109 // Add members 110 if v, ok := d.GetOk("member"); ok { 111 envClient, err := meta.(*Config).EnvironmentClient(d.Id()) 112 if err != nil { 113 return err 114 } 115 members := v.([]interface{}) 116 _, err = envClient.Project.ActionSetmembers(&newEnv, &rancherClient.SetProjectMembersInput{ 117 Members: members, 118 }) 119 if err != nil { 120 return err 121 } 122 } 123 124 return resourceRancherEnvironmentRead(d, meta) 125 } 126 127 func resourceRancherEnvironmentRead(d *schema.ResourceData, meta interface{}) error { 128 log.Printf("[INFO] Refreshing Environment: %s", d.Id()) 129 client, err := meta.(*Config).GlobalClient() 130 if err != nil { 131 return err 132 } 133 134 env, err := client.Project.ById(d.Id()) 135 if err != nil { 136 return err 137 } 138 139 if env == nil { 140 log.Printf("[INFO] Environment %s not found", d.Id()) 141 d.SetId("") 142 return nil 143 } 144 145 if removed(env.State) { 146 log.Printf("[INFO] Environment %s was removed on %v", d.Id(), env.Removed) 147 d.SetId("") 148 return nil 149 } 150 151 log.Printf("[INFO] Environment Name: %s", env.Name) 152 153 d.Set("description", env.Description) 154 d.Set("name", env.Name) 155 d.Set("orchestration", getActiveOrchestration(env)) 156 157 envClient, err := meta.(*Config).EnvironmentClient(d.Id()) 158 if err != nil { 159 return err 160 } 161 162 members, _ := envClient.ProjectMember.List(NewListOpts()) 163 164 d.Set("member", normalizeMembers(members.Data)) 165 return nil 166 } 167 168 func resourceRancherEnvironmentUpdate(d *schema.ResourceData, meta interface{}) error { 169 client, err := meta.(*Config).GlobalClient() 170 if err != nil { 171 return err 172 } 173 174 name := d.Get("name").(string) 175 description := d.Get("description").(string) 176 orchestration := d.Get("orchestration").(string) 177 178 data := map[string]interface{}{ 179 "name": &name, 180 "description": &description, 181 } 182 183 setOrchestrationFields(orchestration, data) 184 185 var newEnv rancherClient.Project 186 env, err := client.Project.ById(d.Id()) 187 if err != nil { 188 return err 189 } 190 191 if err := client.Update("project", &env.Resource, data, &newEnv); err != nil { 192 return err 193 } 194 195 // Update members 196 envClient, err := meta.(*Config).EnvironmentClient(d.Id()) 197 if err != nil { 198 return err 199 } 200 members := d.Get("member").(*schema.Set).List() 201 _, err = envClient.Project.ActionSetmembers(&newEnv, &rancherClient.SetProjectMembersInput{ 202 Members: makeProjectMembers(members), 203 }) 204 if err != nil { 205 return err 206 } 207 208 return resourceRancherEnvironmentRead(d, meta) 209 } 210 211 func resourceRancherEnvironmentDelete(d *schema.ResourceData, meta interface{}) error { 212 log.Printf("[INFO] Deleting Environment: %s", d.Id()) 213 id := d.Id() 214 client, err := meta.(*Config).GlobalClient() 215 if err != nil { 216 return err 217 } 218 219 env, err := client.Project.ById(id) 220 if err != nil { 221 return err 222 } 223 224 if err := client.Project.Delete(env); err != nil { 225 return fmt.Errorf("Error deleting Environment: %s", err) 226 } 227 228 log.Printf("[DEBUG] Waiting for environment (%s) to be removed", id) 229 230 stateConf := &resource.StateChangeConf{ 231 Pending: []string{"active", "removed", "removing"}, 232 Target: []string{"removed"}, 233 Refresh: EnvironmentStateRefreshFunc(client, id), 234 Timeout: 10 * time.Minute, 235 Delay: 1 * time.Second, 236 MinTimeout: 3 * time.Second, 237 } 238 239 _, waitErr := stateConf.WaitForState() 240 if waitErr != nil { 241 return fmt.Errorf( 242 "Error waiting for environment (%s) to be removed: %s", id, waitErr) 243 } 244 245 d.SetId("") 246 return nil 247 } 248 249 func setOrchestrationFields(orchestration string, data map[string]interface{}) { 250 orch := strings.ToLower(orchestration) 251 252 data["swarm"] = false 253 data["kubernetes"] = false 254 data["mesos"] = false 255 256 if orch == "k8s" { 257 orch = "kubernetes" 258 } 259 260 data[orch] = true 261 } 262 263 func normalizeMembers(in []rancherClient.ProjectMember) (out []interface{}) { 264 for _, m := range in { 265 mm := map[string]string{ 266 "external_id_type": m.ExternalIdType, 267 "external_id": m.ExternalId, 268 "role": m.Role, 269 } 270 out = append(out, mm) 271 } 272 return 273 } 274 275 func makeProjectMembers(in []interface{}) (out []interface{}) { 276 for _, m := range in { 277 mMap := m.(map[string]interface{}) 278 mm := rancherClient.ProjectMember{ 279 ExternalIdType: mMap["external_id_type"].(string), 280 ExternalId: mMap["external_id"].(string), 281 Role: mMap["role"].(string), 282 } 283 out = append(out, mm) 284 } 285 return 286 } 287 288 // EnvironmentStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch 289 // a Rancher Environment. 290 func EnvironmentStateRefreshFunc(client *rancherClient.RancherClient, environmentID string) resource.StateRefreshFunc { 291 return func() (interface{}, string, error) { 292 env, err := client.Project.ById(environmentID) 293 294 if err != nil { 295 return nil, "", err 296 } 297 298 return env, env.State, nil 299 } 300 }