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