github.com/serbaut/terraform@v0.6.12-0.20160607213102-ac2d195cc560/builtin/providers/cloudstack/resource_cloudstack_network.go (about) 1 package cloudstack 2 3 import ( 4 "fmt" 5 "log" 6 "net" 7 "strconv" 8 "strings" 9 10 "github.com/hashicorp/terraform/helper/schema" 11 "github.com/xanzy/go-cloudstack/cloudstack" 12 ) 13 14 func resourceCloudStackNetwork() *schema.Resource { 15 return &schema.Resource{ 16 Create: resourceCloudStackNetworkCreate, 17 Read: resourceCloudStackNetworkRead, 18 Update: resourceCloudStackNetworkUpdate, 19 Delete: resourceCloudStackNetworkDelete, 20 21 Schema: map[string]*schema.Schema{ 22 "name": &schema.Schema{ 23 Type: schema.TypeString, 24 Required: true, 25 }, 26 27 "display_text": &schema.Schema{ 28 Type: schema.TypeString, 29 Optional: true, 30 Computed: true, 31 }, 32 33 "cidr": &schema.Schema{ 34 Type: schema.TypeString, 35 Required: true, 36 ForceNew: true, 37 }, 38 39 "gateway": &schema.Schema{ 40 Type: schema.TypeString, 41 Optional: true, 42 Computed: true, 43 ForceNew: true, 44 }, 45 46 "startip": &schema.Schema{ 47 Type: schema.TypeString, 48 Optional: true, 49 Computed: true, 50 ForceNew: true, 51 }, 52 53 "endip": &schema.Schema{ 54 Type: schema.TypeString, 55 Optional: true, 56 Computed: true, 57 ForceNew: true, 58 }, 59 60 "network_offering": &schema.Schema{ 61 Type: schema.TypeString, 62 Required: true, 63 }, 64 65 "vlan": &schema.Schema{ 66 Type: schema.TypeInt, 67 Optional: true, 68 ForceNew: true, 69 }, 70 71 "vpc_id": &schema.Schema{ 72 Type: schema.TypeString, 73 Optional: true, 74 Computed: true, 75 ForceNew: true, 76 }, 77 78 "vpc": &schema.Schema{ 79 Type: schema.TypeString, 80 Optional: true, 81 ForceNew: true, 82 Deprecated: "Please use the `vpc_id` field instead", 83 }, 84 85 "acl_id": &schema.Schema{ 86 Type: schema.TypeString, 87 Optional: true, 88 Computed: true, 89 ConflictsWith: []string{"aclid"}, 90 }, 91 92 "aclid": &schema.Schema{ 93 Type: schema.TypeString, 94 Optional: true, 95 Deprecated: "Please use the `acl_id` field instead", 96 }, 97 98 "project": &schema.Schema{ 99 Type: schema.TypeString, 100 Optional: true, 101 ForceNew: true, 102 }, 103 104 "zone": &schema.Schema{ 105 Type: schema.TypeString, 106 Required: true, 107 ForceNew: true, 108 }, 109 110 "tags": tagsSchema(), 111 }, 112 } 113 } 114 115 func resourceCloudStackNetworkCreate(d *schema.ResourceData, meta interface{}) error { 116 cs := meta.(*cloudstack.CloudStackClient) 117 118 name := d.Get("name").(string) 119 120 // Retrieve the network_offering ID 121 networkofferingid, e := retrieveID(cs, "network_offering", d.Get("network_offering").(string)) 122 if e != nil { 123 return e.Error() 124 } 125 126 // Retrieve the zone ID 127 zoneid, e := retrieveID(cs, "zone", d.Get("zone").(string)) 128 if e != nil { 129 return e.Error() 130 } 131 132 // Compute/set the display text 133 displaytext, ok := d.GetOk("display_text") 134 if !ok { 135 displaytext = name 136 } 137 // Create a new parameter struct 138 p := cs.Network.NewCreateNetworkParams(displaytext.(string), name, networkofferingid, zoneid) 139 140 m, err := parseCIDR(d) 141 if err != nil { 142 return err 143 } 144 145 // Set the needed IP config 146 p.SetStartip(m["startip"]) 147 p.SetGateway(m["gateway"]) 148 p.SetEndip(m["endip"]) 149 p.SetNetmask(m["netmask"]) 150 151 if vlan, ok := d.GetOk("vlan"); ok { 152 p.SetVlan(strconv.Itoa(vlan.(int))) 153 } 154 155 // Check is this network needs to be created in a VPC 156 vpc, ok := d.GetOk("vpc_id") 157 if !ok { 158 vpc, ok = d.GetOk("vpc") 159 } 160 if ok { 161 // Retrieve the vpc ID 162 vpcid, e := retrieveID( 163 cs, 164 "vpc", 165 vpc.(string), 166 cloudstack.WithProject(d.Get("project").(string)), 167 ) 168 if e != nil { 169 return e.Error() 170 } 171 172 // Set the vpcid 173 p.SetVpcid(vpcid) 174 175 // Since we're in a VPC, check if we want to assiciate an ACL list 176 aclid, ok := d.GetOk("acl_id") 177 if !ok { 178 aclid, ok = d.GetOk("acl") 179 } 180 if ok { 181 // Set the acl ID 182 p.SetAclid(aclid.(string)) 183 } 184 } 185 186 // If there is a project supplied, we retrieve and set the project id 187 if err := setProjectid(p, cs, d); err != nil { 188 return err 189 } 190 191 // Create the new network 192 r, err := cs.Network.CreateNetwork(p) 193 if err != nil { 194 return fmt.Errorf("Error creating network %s: %s", name, err) 195 } 196 197 d.SetId(r.Id) 198 199 err = setTags(cs, d, "network") 200 if err != nil { 201 return fmt.Errorf("Error setting tags: %s", err) 202 } 203 204 return resourceCloudStackNetworkRead(d, meta) 205 } 206 207 func resourceCloudStackNetworkRead(d *schema.ResourceData, meta interface{}) error { 208 cs := meta.(*cloudstack.CloudStackClient) 209 210 // Get the virtual machine details 211 n, count, err := cs.Network.GetNetworkByID( 212 d.Id(), 213 cloudstack.WithProject(d.Get("project").(string)), 214 ) 215 if err != nil { 216 if count == 0 { 217 log.Printf( 218 "[DEBUG] Network %s does no longer exist", d.Get("name").(string)) 219 d.SetId("") 220 return nil 221 } 222 223 return err 224 } 225 226 d.Set("name", n.Name) 227 d.Set("display_text", n.Displaytext) 228 d.Set("cidr", n.Cidr) 229 d.Set("gateway", n.Gateway) 230 231 _, vpcID := d.GetOk("vpc_id") 232 _, vpc := d.GetOk("vpc") 233 if vpcID || vpc { 234 d.Set("vpc_id", n.Vpcid) 235 } 236 237 _, aclID := d.GetOk("acl_id") 238 _, acl := d.GetOk("aclid") 239 if aclID || acl { 240 d.Set("acl_id", n.Aclid) 241 } 242 243 // Read the tags and store them in a map 244 tags := make(map[string]interface{}) 245 for item := range n.Tags { 246 tags[n.Tags[item].Key] = n.Tags[item].Value 247 } 248 d.Set("tags", tags) 249 250 setValueOrID(d, "network_offering", n.Networkofferingname, n.Networkofferingid) 251 setValueOrID(d, "project", n.Project, n.Projectid) 252 setValueOrID(d, "zone", n.Zonename, n.Zoneid) 253 254 return nil 255 } 256 257 func resourceCloudStackNetworkUpdate(d *schema.ResourceData, meta interface{}) error { 258 cs := meta.(*cloudstack.CloudStackClient) 259 name := d.Get("name").(string) 260 261 // Create a new parameter struct 262 p := cs.Network.NewUpdateNetworkParams(d.Id()) 263 264 // Check if the name or display text is changed 265 if d.HasChange("name") || d.HasChange("display_text") { 266 p.SetName(name) 267 268 // Compute/set the display text 269 displaytext := d.Get("display_text").(string) 270 if displaytext == "" { 271 displaytext = name 272 } 273 p.SetDisplaytext(displaytext) 274 } 275 276 // Check if the cidr is changed 277 if d.HasChange("cidr") { 278 p.SetGuestvmcidr(d.Get("cidr").(string)) 279 } 280 281 // Check if the network offering is changed 282 if d.HasChange("network_offering") { 283 // Retrieve the network_offering ID 284 networkofferingid, e := retrieveID(cs, "network_offering", d.Get("network_offering").(string)) 285 if e != nil { 286 return e.Error() 287 } 288 // Set the new network offering 289 p.SetNetworkofferingid(networkofferingid) 290 } 291 292 // Update the network 293 _, err := cs.Network.UpdateNetwork(p) 294 if err != nil { 295 return fmt.Errorf( 296 "Error updating network %s: %s", name, err) 297 } 298 299 // Replace the ACL if the ID has changed 300 if d.HasChange("acl_id") || d.HasChange("acl") { 301 aclid, ok := d.GetOk("acl_id") 302 if !ok { 303 aclid, ok = d.GetOk("acl") 304 } 305 if !ok { 306 return fmt.Errorf("Replacing the ACL requires a valid ACL ID") 307 } 308 309 p := cs.NetworkACL.NewReplaceNetworkACLListParams(aclid.(string)) 310 p.SetNetworkid(d.Id()) 311 312 _, err := cs.NetworkACL.ReplaceNetworkACLList(p) 313 if err != nil { 314 return fmt.Errorf("Error replacing ACL: %s", err) 315 } 316 } 317 318 // Update tags if they have changed 319 if d.HasChange("tags") { 320 err = setTags(cs, d, "network") 321 if err != nil { 322 return fmt.Errorf("Error updating tags: %s", err) 323 } 324 } 325 326 return resourceCloudStackNetworkRead(d, meta) 327 } 328 329 func resourceCloudStackNetworkDelete(d *schema.ResourceData, meta interface{}) error { 330 cs := meta.(*cloudstack.CloudStackClient) 331 332 // Create a new parameter struct 333 p := cs.Network.NewDeleteNetworkParams(d.Id()) 334 335 // Delete the network 336 _, err := cs.Network.DeleteNetwork(p) 337 if err != nil { 338 // This is a very poor way to be told the ID does no longer exist :( 339 if strings.Contains(err.Error(), fmt.Sprintf( 340 "Invalid parameter id value=%s due to incorrect long value format, "+ 341 "or entity does not exist", d.Id())) { 342 return nil 343 } 344 345 return fmt.Errorf("Error deleting network %s: %s", d.Get("name").(string), err) 346 } 347 return nil 348 } 349 350 func parseCIDR(d *schema.ResourceData) (map[string]string, error) { 351 m := make(map[string]string, 4) 352 353 cidr := d.Get("cidr").(string) 354 ip, ipnet, err := net.ParseCIDR(cidr) 355 if err != nil { 356 return nil, fmt.Errorf("Unable to parse cidr %s: %s", cidr, err) 357 } 358 359 msk := ipnet.Mask 360 sub := ip.Mask(msk) 361 362 m["netmask"] = fmt.Sprintf("%d.%d.%d.%d", msk[0], msk[1], msk[2], msk[3]) 363 364 if gateway, ok := d.GetOk("gateway"); ok { 365 m["gateway"] = gateway.(string) 366 } else { 367 m["gateway"] = fmt.Sprintf("%d.%d.%d.%d", sub[0], sub[1], sub[2], sub[3]+1) 368 } 369 370 if startip, ok := d.GetOk("startip"); ok { 371 m["startip"] = startip.(string) 372 } else { 373 m["startip"] = fmt.Sprintf("%d.%d.%d.%d", sub[0], sub[1], sub[2], sub[3]+2) 374 } 375 376 if endip, ok := d.GetOk("endip"); ok { 377 m["endip"] = endip.(string) 378 } else { 379 m["endip"] = fmt.Sprintf("%d.%d.%d.%d", 380 sub[0]+(0xff-msk[0]), sub[1]+(0xff-msk[1]), sub[2]+(0xff-msk[2]), sub[3]+(0xff-msk[3]-1)) 381 } 382 383 return m, nil 384 }