github.com/jrasell/terraform@v0.6.17-0.20160523115548-2652f5232949/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 ForceNew: true, 90 ConflictsWith: []string{"aclid"}, 91 }, 92 93 "aclid": &schema.Schema{ 94 Type: schema.TypeString, 95 Optional: true, 96 ForceNew: true, 97 Deprecated: "Please use the `acl_id` field instead", 98 }, 99 100 "project": &schema.Schema{ 101 Type: schema.TypeString, 102 Optional: true, 103 ForceNew: true, 104 }, 105 106 "zone": &schema.Schema{ 107 Type: schema.TypeString, 108 Required: true, 109 ForceNew: true, 110 }, 111 112 "tags": tagsSchema(), 113 }, 114 } 115 } 116 117 func resourceCloudStackNetworkCreate(d *schema.ResourceData, meta interface{}) error { 118 cs := meta.(*cloudstack.CloudStackClient) 119 120 name := d.Get("name").(string) 121 122 // Retrieve the network_offering ID 123 networkofferingid, e := retrieveID(cs, "network_offering", d.Get("network_offering").(string)) 124 if e != nil { 125 return e.Error() 126 } 127 128 // Retrieve the zone ID 129 zoneid, e := retrieveID(cs, "zone", d.Get("zone").(string)) 130 if e != nil { 131 return e.Error() 132 } 133 134 // Compute/set the display text 135 displaytext, ok := d.GetOk("display_text") 136 if !ok { 137 displaytext = name 138 } 139 // Create a new parameter struct 140 p := cs.Network.NewCreateNetworkParams(displaytext.(string), name, networkofferingid, zoneid) 141 142 m, err := parseCIDR(d) 143 if err != nil { 144 return err 145 } 146 147 // Set the needed IP config 148 p.SetStartip(m["startip"]) 149 p.SetGateway(m["gateway"]) 150 p.SetEndip(m["endip"]) 151 p.SetNetmask(m["netmask"]) 152 153 if vlan, ok := d.GetOk("vlan"); ok { 154 p.SetVlan(strconv.Itoa(vlan.(int))) 155 } 156 157 // Check is this network needs to be created in a VPC 158 vpc, ok := d.GetOk("vpc_id") 159 if !ok { 160 vpc, ok = d.GetOk("vpc") 161 } 162 if ok { 163 // Retrieve the vpc ID 164 vpcid, e := retrieveID( 165 cs, 166 "vpc", 167 vpc.(string), 168 cloudstack.WithProject(d.Get("project").(string)), 169 ) 170 if e != nil { 171 return e.Error() 172 } 173 174 // Set the vpcid 175 p.SetVpcid(vpcid) 176 177 // Since we're in a VPC, check if we want to assiciate an ACL list 178 aclid, ok := d.GetOk("acl_id") 179 if !ok { 180 aclid, ok = d.GetOk("acl") 181 } 182 if ok { 183 // Set the acl ID 184 p.SetAclid(aclid.(string)) 185 } 186 } 187 188 // If there is a project supplied, we retrieve and set the project id 189 if err := setProjectid(p, cs, d); err != nil { 190 return err 191 } 192 193 // Create the new network 194 r, err := cs.Network.CreateNetwork(p) 195 if err != nil { 196 return fmt.Errorf("Error creating network %s: %s", name, err) 197 } 198 199 d.SetId(r.Id) 200 201 err = setTags(cs, d, "network") 202 if err != nil { 203 return fmt.Errorf("Error setting tags: %s", err) 204 } 205 206 return resourceCloudStackNetworkRead(d, meta) 207 } 208 209 func resourceCloudStackNetworkRead(d *schema.ResourceData, meta interface{}) error { 210 cs := meta.(*cloudstack.CloudStackClient) 211 212 // Get the virtual machine details 213 n, count, err := cs.Network.GetNetworkByID( 214 d.Id(), 215 cloudstack.WithProject(d.Get("project").(string)), 216 ) 217 if err != nil { 218 if count == 0 { 219 log.Printf( 220 "[DEBUG] Network %s does no longer exist", d.Get("name").(string)) 221 d.SetId("") 222 return nil 223 } 224 225 return err 226 } 227 228 d.Set("name", n.Name) 229 d.Set("display_text", n.Displaytext) 230 d.Set("cidr", n.Cidr) 231 d.Set("gateway", n.Gateway) 232 233 _, vpcID := d.GetOk("vpc_id") 234 _, vpc := d.GetOk("vpc") 235 if vpcID || vpc { 236 d.Set("vpc_id", n.Vpcid) 237 } 238 239 _, aclID := d.GetOk("acl_id") 240 _, acl := d.GetOk("aclid") 241 if aclID || acl { 242 d.Set("acl_id", n.Aclid) 243 } 244 245 // Read the tags and store them in a map 246 tags := make(map[string]interface{}) 247 for item := range n.Tags { 248 tags[n.Tags[item].Key] = n.Tags[item].Value 249 } 250 d.Set("tags", tags) 251 252 setValueOrID(d, "network_offering", n.Networkofferingname, n.Networkofferingid) 253 setValueOrID(d, "project", n.Project, n.Projectid) 254 setValueOrID(d, "zone", n.Zonename, n.Zoneid) 255 256 return nil 257 } 258 259 func resourceCloudStackNetworkUpdate(d *schema.ResourceData, meta interface{}) error { 260 cs := meta.(*cloudstack.CloudStackClient) 261 name := d.Get("name").(string) 262 263 // Create a new parameter struct 264 p := cs.Network.NewUpdateNetworkParams(d.Id()) 265 266 // Check if the name or display text is changed 267 if d.HasChange("name") || d.HasChange("display_text") { 268 p.SetName(name) 269 270 // Compute/set the display text 271 displaytext := d.Get("display_text").(string) 272 if displaytext == "" { 273 displaytext = name 274 } 275 p.SetDisplaytext(displaytext) 276 } 277 278 // Check if the cidr is changed 279 if d.HasChange("cidr") { 280 p.SetGuestvmcidr(d.Get("cidr").(string)) 281 } 282 283 // Check if the network offering is changed 284 if d.HasChange("network_offering") { 285 // Retrieve the network_offering ID 286 networkofferingid, e := retrieveID(cs, "network_offering", d.Get("network_offering").(string)) 287 if e != nil { 288 return e.Error() 289 } 290 // Set the new network offering 291 p.SetNetworkofferingid(networkofferingid) 292 } 293 294 // Update the network 295 _, err := cs.Network.UpdateNetwork(p) 296 if err != nil { 297 return fmt.Errorf( 298 "Error updating network %s: %s", name, err) 299 } 300 301 // Update tags if they have changed 302 if d.HasChange("tags") { 303 err = setTags(cs, d, "network") 304 if err != nil { 305 return fmt.Errorf("Error updating tags: %s", err) 306 } 307 } 308 309 return resourceCloudStackNetworkRead(d, meta) 310 } 311 312 func resourceCloudStackNetworkDelete(d *schema.ResourceData, meta interface{}) error { 313 cs := meta.(*cloudstack.CloudStackClient) 314 315 // Create a new parameter struct 316 p := cs.Network.NewDeleteNetworkParams(d.Id()) 317 318 // Delete the network 319 _, err := cs.Network.DeleteNetwork(p) 320 if err != nil { 321 // This is a very poor way to be told the ID does no longer exist :( 322 if strings.Contains(err.Error(), fmt.Sprintf( 323 "Invalid parameter id value=%s due to incorrect long value format, "+ 324 "or entity does not exist", d.Id())) { 325 return nil 326 } 327 328 return fmt.Errorf("Error deleting network %s: %s", d.Get("name").(string), err) 329 } 330 return nil 331 } 332 333 func parseCIDR(d *schema.ResourceData) (map[string]string, error) { 334 m := make(map[string]string, 4) 335 336 cidr := d.Get("cidr").(string) 337 ip, ipnet, err := net.ParseCIDR(cidr) 338 if err != nil { 339 return nil, fmt.Errorf("Unable to parse cidr %s: %s", cidr, err) 340 } 341 342 msk := ipnet.Mask 343 sub := ip.Mask(msk) 344 345 m["netmask"] = fmt.Sprintf("%d.%d.%d.%d", msk[0], msk[1], msk[2], msk[3]) 346 347 if gateway, ok := d.GetOk("gateway"); ok { 348 m["gateway"] = gateway.(string) 349 } else { 350 m["gateway"] = fmt.Sprintf("%d.%d.%d.%d", sub[0], sub[1], sub[2], sub[3]+1) 351 } 352 353 if startip, ok := d.GetOk("startip"); ok { 354 m["startip"] = startip.(string) 355 } else { 356 m["startip"] = fmt.Sprintf("%d.%d.%d.%d", sub[0], sub[1], sub[2], sub[3]+2) 357 } 358 359 if endip, ok := d.GetOk("endip"); ok { 360 m["endip"] = endip.(string) 361 } else { 362 m["endip"] = fmt.Sprintf("%d.%d.%d.%d", 363 sub[0]+(0xff-msk[0]), sub[1]+(0xff-msk[1]), sub[2]+(0xff-msk[2]), sub[3]+(0xff-msk[3]-1)) 364 } 365 366 return m, nil 367 }