github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/builtin/providers/cloudstack/resource_cloudstack_loadbalancer_rule.go (about) 1 package cloudstack 2 3 import ( 4 "fmt" 5 "log" 6 "strings" 7 8 "github.com/hashicorp/terraform/helper/schema" 9 "github.com/xanzy/go-cloudstack/cloudstack" 10 ) 11 12 func resourceCloudStackLoadBalancerRule() *schema.Resource { 13 return &schema.Resource{ 14 Create: resourceCloudStackLoadBalancerRuleCreate, 15 Read: resourceCloudStackLoadBalancerRuleRead, 16 Update: resourceCloudStackLoadBalancerRuleUpdate, 17 Delete: resourceCloudStackLoadBalancerRuleDelete, 18 19 Schema: map[string]*schema.Schema{ 20 "name": &schema.Schema{ 21 Type: schema.TypeString, 22 Required: true, 23 }, 24 25 "description": &schema.Schema{ 26 Type: schema.TypeString, 27 Optional: true, 28 Computed: true, 29 }, 30 31 "ip_address_id": &schema.Schema{ 32 Type: schema.TypeString, 33 Required: true, 34 ForceNew: true, 35 }, 36 37 "network_id": &schema.Schema{ 38 Type: schema.TypeString, 39 Optional: true, 40 ForceNew: true, 41 }, 42 43 "algorithm": &schema.Schema{ 44 Type: schema.TypeString, 45 Required: true, 46 }, 47 48 "private_port": &schema.Schema{ 49 Type: schema.TypeInt, 50 Required: true, 51 ForceNew: true, 52 }, 53 54 "public_port": &schema.Schema{ 55 Type: schema.TypeInt, 56 Required: true, 57 ForceNew: true, 58 }, 59 60 "member_ids": &schema.Schema{ 61 Type: schema.TypeSet, 62 Required: true, 63 ForceNew: false, 64 Elem: &schema.Schema{Type: schema.TypeString}, 65 Set: schema.HashString, 66 }, 67 68 "project": &schema.Schema{ 69 Type: schema.TypeString, 70 Optional: true, 71 Computed: true, 72 ForceNew: true, 73 }, 74 }, 75 } 76 } 77 78 func resourceCloudStackLoadBalancerRuleCreate(d *schema.ResourceData, meta interface{}) error { 79 cs := meta.(*cloudstack.CloudStackClient) 80 d.Partial(true) 81 82 // Create a new parameter struct 83 p := cs.LoadBalancer.NewCreateLoadBalancerRuleParams( 84 d.Get("algorithm").(string), 85 d.Get("name").(string), 86 d.Get("private_port").(int), 87 d.Get("public_port").(int), 88 ) 89 90 // Don't autocreate a firewall rule, use a resource if needed 91 p.SetOpenfirewall(false) 92 93 // Set the description 94 if description, ok := d.GetOk("description"); ok { 95 p.SetDescription(description.(string)) 96 } else { 97 p.SetDescription(d.Get("name").(string)) 98 } 99 100 if networkid, ok := d.GetOk("network_id"); ok { 101 // Set the network id 102 p.SetNetworkid(networkid.(string)) 103 } 104 105 // Set the ipaddress id 106 p.SetPublicipid(d.Get("ip_address_id").(string)) 107 108 // Create the load balancer rule 109 r, err := cs.LoadBalancer.CreateLoadBalancerRule(p) 110 if err != nil { 111 return err 112 } 113 114 // Set the load balancer rule ID and set partials 115 d.SetId(r.Id) 116 d.SetPartial("name") 117 d.SetPartial("description") 118 d.SetPartial("ip_address_id") 119 d.SetPartial("network_id") 120 d.SetPartial("algorithm") 121 d.SetPartial("private_port") 122 d.SetPartial("public_port") 123 124 // Create a new parameter struct 125 ap := cs.LoadBalancer.NewAssignToLoadBalancerRuleParams(r.Id) 126 127 var mbs []string 128 for _, id := range d.Get("member_ids").(*schema.Set).List() { 129 mbs = append(mbs, id.(string)) 130 } 131 132 ap.SetVirtualmachineids(mbs) 133 134 _, err = cs.LoadBalancer.AssignToLoadBalancerRule(ap) 135 if err != nil { 136 return err 137 } 138 139 d.SetPartial("member_ids") 140 d.Partial(false) 141 142 return resourceCloudStackLoadBalancerRuleRead(d, meta) 143 } 144 145 func resourceCloudStackLoadBalancerRuleRead(d *schema.ResourceData, meta interface{}) error { 146 cs := meta.(*cloudstack.CloudStackClient) 147 148 // Get the load balancer details 149 lb, count, err := cs.LoadBalancer.GetLoadBalancerRuleByID( 150 d.Id(), 151 cloudstack.WithProject(d.Get("project").(string)), 152 ) 153 if err != nil { 154 if count == 0 { 155 log.Printf("[DEBUG] Load balancer rule %s does no longer exist", d.Get("name").(string)) 156 d.SetId("") 157 return nil 158 } 159 160 return err 161 } 162 163 d.Set("algorithm", lb.Algorithm) 164 d.Set("public_port", lb.Publicport) 165 d.Set("private_port", lb.Privateport) 166 d.Set("ip_address_id", lb.Publicipid) 167 168 // Only set network if user specified it to avoid spurious diffs 169 if _, ok := d.GetOk("network_id"); ok { 170 d.Set("network_id", lb.Networkid) 171 } 172 173 setValueOrID(d, "project", lb.Project, lb.Projectid) 174 175 p := cs.LoadBalancer.NewListLoadBalancerRuleInstancesParams(d.Id()) 176 l, err := cs.LoadBalancer.ListLoadBalancerRuleInstances(p) 177 if err != nil { 178 return err 179 } 180 181 var mbs []string 182 for _, i := range l.LoadBalancerRuleInstances { 183 mbs = append(mbs, i.Id) 184 } 185 d.Set("member_ids", mbs) 186 187 return nil 188 } 189 190 func resourceCloudStackLoadBalancerRuleUpdate(d *schema.ResourceData, meta interface{}) error { 191 cs := meta.(*cloudstack.CloudStackClient) 192 193 if d.HasChange("name") || d.HasChange("description") || d.HasChange("algorithm") { 194 name := d.Get("name").(string) 195 196 // Create new parameter struct 197 p := cs.LoadBalancer.NewUpdateLoadBalancerRuleParams(d.Id()) 198 199 if d.HasChange("name") { 200 log.Printf("[DEBUG] Name has changed for load balancer rule %s, starting update", name) 201 202 p.SetName(name) 203 } 204 205 if d.HasChange("description") { 206 log.Printf( 207 "[DEBUG] Description has changed for load balancer rule %s, starting update", name) 208 209 p.SetDescription(d.Get("description").(string)) 210 } 211 212 if d.HasChange("algorithm") { 213 algorithm := d.Get("algorithm").(string) 214 215 log.Printf( 216 "[DEBUG] Algorithm has changed to %s for load balancer rule %s, starting update", 217 algorithm, 218 name, 219 ) 220 221 // Set the new Algorithm 222 p.SetAlgorithm(algorithm) 223 } 224 225 _, err := cs.LoadBalancer.UpdateLoadBalancerRule(p) 226 if err != nil { 227 return fmt.Errorf( 228 "Error updating load balancer rule %s", name) 229 } 230 } 231 232 if d.HasChange("member_ids") { 233 o, n := d.GetChange("member_ids") 234 ombs, nmbs := o.(*schema.Set), n.(*schema.Set) 235 236 setToStringList := func(s *schema.Set) []string { 237 l := make([]string, s.Len()) 238 for i, v := range s.List() { 239 l[i] = v.(string) 240 } 241 return l 242 } 243 244 membersToAdd := setToStringList(nmbs.Difference(ombs)) 245 membersToRemove := setToStringList(ombs.Difference(nmbs)) 246 247 log.Printf("[DEBUG] Members to add: %v, remove: %v", membersToAdd, membersToRemove) 248 249 if len(membersToAdd) > 0 { 250 p := cs.LoadBalancer.NewAssignToLoadBalancerRuleParams(d.Id()) 251 p.SetVirtualmachineids(membersToAdd) 252 if _, err := cs.LoadBalancer.AssignToLoadBalancerRule(p); err != nil { 253 return err 254 } 255 } 256 257 if len(membersToRemove) > 0 { 258 p := cs.LoadBalancer.NewRemoveFromLoadBalancerRuleParams(d.Id()) 259 p.SetVirtualmachineids(membersToRemove) 260 if _, err := cs.LoadBalancer.RemoveFromLoadBalancerRule(p); err != nil { 261 return err 262 } 263 } 264 } 265 266 return resourceCloudStackLoadBalancerRuleRead(d, meta) 267 } 268 269 func resourceCloudStackLoadBalancerRuleDelete(d *schema.ResourceData, meta interface{}) error { 270 cs := meta.(*cloudstack.CloudStackClient) 271 272 // Create a new parameter struct 273 p := cs.LoadBalancer.NewDeleteLoadBalancerRuleParams(d.Id()) 274 275 log.Printf("[INFO] Deleting load balancer rule: %s", d.Get("name").(string)) 276 if _, err := cs.LoadBalancer.DeleteLoadBalancerRule(p); err != nil { 277 // This is a very poor way to be told the ID does no longer exist :( 278 if !strings.Contains(err.Error(), fmt.Sprintf( 279 "Invalid parameter id value=%s due to incorrect long value format, "+ 280 "or entity does not exist", d.Id())) { 281 return err 282 } 283 } 284 285 return nil 286 }