github.com/vtorhonen/terraform@v0.9.0-beta2.0.20170307220345-5d894e4ffda7/builtin/providers/clc/provider.go (about) 1 package clc 2 3 import ( 4 "fmt" 5 "log" 6 "strconv" 7 8 clc "github.com/CenturyLinkCloud/clc-sdk" 9 "github.com/CenturyLinkCloud/clc-sdk/api" 10 "github.com/CenturyLinkCloud/clc-sdk/group" 11 "github.com/CenturyLinkCloud/clc-sdk/server" 12 "github.com/CenturyLinkCloud/clc-sdk/status" 13 "github.com/hashicorp/terraform/helper/schema" 14 "github.com/hashicorp/terraform/terraform" 15 ) 16 17 // Provider implements ResourceProvider for CLC 18 func Provider() terraform.ResourceProvider { 19 return &schema.Provider{ 20 Schema: map[string]*schema.Schema{ 21 "username": &schema.Schema{ 22 Type: schema.TypeString, 23 Required: true, 24 DefaultFunc: schema.EnvDefaultFunc("CLC_USERNAME", nil), 25 Description: "Your CLC username", 26 }, 27 "password": &schema.Schema{ 28 Type: schema.TypeString, 29 Required: true, 30 DefaultFunc: schema.EnvDefaultFunc("CLC_PASSWORD", nil), 31 Description: "Your CLC password", 32 }, 33 "account": &schema.Schema{ 34 Type: schema.TypeString, 35 Optional: true, 36 DefaultFunc: schema.EnvDefaultFunc("CLC_ACCOUNT", ""), 37 Description: "Account alias override", 38 }, 39 }, 40 41 ResourcesMap: map[string]*schema.Resource{ 42 "clc_server": resourceCLCServer(), 43 "clc_group": resourceCLCGroup(), 44 "clc_public_ip": resourceCLCPublicIP(), 45 "clc_load_balancer": resourceCLCLoadBalancer(), 46 "clc_load_balancer_pool": resourceCLCLoadBalancerPool(), 47 }, 48 49 ConfigureFunc: providerConfigure, 50 } 51 } 52 53 func providerConfigure(d *schema.ResourceData) (interface{}, error) { 54 un := d.Get("username").(string) 55 pw := d.Get("password").(string) 56 57 config, err := api.NewConfig(un, pw) 58 if err != nil { 59 return nil, fmt.Errorf("Failed to create CLC config with provided details: %v", err) 60 } 61 config.UserAgent = fmt.Sprintf("terraform-clc terraform/%s", terraform.Version) 62 // user requested alias override or sub-account 63 if al := d.Get("account").(string); al != "" { 64 config.Alias = al 65 } 66 67 client := clc.New(config) 68 if err := client.Authenticate(); err != nil { 69 return nil, fmt.Errorf("Failed authenticated with provided credentials: %v", err) 70 } 71 72 alerts, err := client.Alert.GetAll() 73 if err != nil { 74 return nil, fmt.Errorf("Failed to connect to the CLC api because %s", err) 75 } 76 for _, a := range alerts.Items { 77 log.Printf("[WARN] Received alert: %v", a) 78 } 79 return client, nil 80 } 81 82 // package utility functions 83 84 func waitStatus(client *clc.Client, id string) error { 85 // block until queue is processed and server is up 86 poll := make(chan *status.Response, 1) 87 err := client.Status.Poll(id, poll) 88 if err != nil { 89 return nil 90 } 91 status := <-poll 92 log.Printf("[DEBUG] status %v", status) 93 if status.Failed() { 94 return fmt.Errorf("unsuccessful job %v failed with status: %v", id, status.Status) 95 } 96 return nil 97 } 98 99 func dcGroups(dcname string, client *clc.Client) (map[string]string, error) { 100 dc, _ := client.DC.Get(dcname) 101 _, id := dc.Links.GetID("group") 102 m := map[string]string{} 103 resp, _ := client.Group.Get(id) 104 m[resp.Name] = resp.ID // top 105 m[resp.ID] = resp.ID 106 for _, x := range resp.Groups { 107 deepGroups(x, &m) 108 } 109 return m, nil 110 } 111 112 func deepGroups(g group.Groups, m *map[string]string) { 113 (*m)[g.Name] = g.ID 114 (*m)[g.ID] = g.ID 115 for _, sg := range g.Groups { 116 deepGroups(sg, m) 117 } 118 } 119 120 // resolveGroupByNameOrId takes a reference to a group (either name or guid) 121 // and returns the guid of the group 122 func resolveGroupByNameOrId(ref, dc string, client *clc.Client) (string, error) { 123 m, err := dcGroups(dc, client) 124 if err != nil { 125 return "", fmt.Errorf("Failed pulling groups in location %v - %v", dc, err) 126 } 127 if id, ok := m[ref]; ok { 128 return id, nil 129 } 130 return "", fmt.Errorf("Failed resolving group '%v' in location %v", ref, dc) 131 } 132 133 func stateFromString(st string) server.PowerState { 134 switch st { 135 case "on", "started": 136 return server.On 137 case "off", "stopped": 138 return server.Off 139 case "pause", "paused": 140 return server.Pause 141 case "reboot": 142 return server.Reboot 143 case "reset": 144 return server.Reset 145 case "shutdown": 146 return server.ShutDown 147 case "start_maintenance": 148 return server.StartMaintenance 149 case "stop_maintenance": 150 return server.StopMaintenance 151 } 152 return -1 153 } 154 155 func parseCustomFields(d *schema.ResourceData) ([]api.Customfields, error) { 156 var fields []api.Customfields 157 if v := d.Get("custom_fields"); v != nil { 158 for _, v := range v.([]interface{}) { 159 m := v.(map[string]interface{}) 160 f := api.Customfields{ 161 ID: m["id"].(string), 162 Value: m["value"].(string), 163 } 164 fields = append(fields, f) 165 } 166 } 167 return fields, nil 168 } 169 170 func parseAdditionalDisks(d *schema.ResourceData) ([]server.Disk, error) { 171 // some complexity here: create has a different format than update 172 // on-create: { path, sizeGB, type } 173 // on-update: { diskId, sizeGB, (path), (type=partitioned) } 174 var disks []server.Disk 175 if v := d.Get("additional_disks"); v != nil { 176 for _, v := range v.([]interface{}) { 177 m := v.(map[string]interface{}) 178 ty := m["type"].(string) 179 var pa string 180 if nil != m["path"] { 181 pa = m["path"].(string) 182 } 183 sz, err := strconv.Atoi(m["size_gb"].(string)) 184 if err != nil { 185 log.Printf("[WARN] Failed parsing size '%v'. skipping", m["size_gb"]) 186 return nil, fmt.Errorf("Unable to parse %v as int", m["size_gb"]) 187 } 188 if ty != "raw" && ty != "partitioned" { 189 return nil, fmt.Errorf("Expected type of { raw | partitioned }. received %v", ty) 190 } 191 if ty == "raw" && pa != "" { 192 return nil, fmt.Errorf("Path can not be specified for raw disks") 193 } 194 disk := server.Disk{ 195 SizeGB: sz, 196 Type: ty, 197 } 198 if pa != "" { 199 disk.Path = pa 200 } 201 disks = append(disks, disk) 202 } 203 } 204 return disks, nil 205 } 206 207 func parsePackages(d *schema.ResourceData) ([]server.Package, error) { 208 var pkgs []server.Package 209 if e := d.Get("packages"); e != nil { 210 for _, e := range e.([]interface{}) { 211 m := e.(map[string]interface{}) 212 id := m["id"].(string) 213 delete(m, "id") 214 ms := make(map[string]string) 215 for k, v := range m { 216 if s, ok := v.(string); ok { 217 ms[k] = s 218 } 219 } 220 p := server.Package{ 221 ID: id, 222 Params: ms, 223 } 224 pkgs = append(pkgs, p) 225 } 226 } 227 return pkgs, nil 228 }