github.com/andresvia/terraform@v0.6.15-0.20160412045437-d51c75946785/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": &schema.Schema{ 72 Type: schema.TypeString, 73 Optional: true, 74 ForceNew: true, 75 }, 76 77 "aclid": &schema.Schema{ 78 Type: schema.TypeString, 79 Optional: true, 80 ForceNew: true, 81 }, 82 83 "project": &schema.Schema{ 84 Type: schema.TypeString, 85 Optional: true, 86 ForceNew: true, 87 }, 88 89 "zone": &schema.Schema{ 90 Type: schema.TypeString, 91 Required: true, 92 ForceNew: true, 93 }, 94 95 "tags": tagsSchema(), 96 }, 97 } 98 } 99 100 func resourceCloudStackNetworkCreate(d *schema.ResourceData, meta interface{}) error { 101 cs := meta.(*cloudstack.CloudStackClient) 102 103 name := d.Get("name").(string) 104 105 // Retrieve the network_offering ID 106 networkofferingid, e := retrieveID(cs, "network_offering", d.Get("network_offering").(string)) 107 if e != nil { 108 return e.Error() 109 } 110 111 // Retrieve the zone ID 112 zoneid, e := retrieveID(cs, "zone", d.Get("zone").(string)) 113 if e != nil { 114 return e.Error() 115 } 116 117 // Compute/set the display text 118 displaytext, ok := d.GetOk("display_text") 119 if !ok { 120 displaytext = name 121 } 122 // Create a new parameter struct 123 p := cs.Network.NewCreateNetworkParams(displaytext.(string), name, networkofferingid, zoneid) 124 125 m, err := parseCIDR(d) 126 if err != nil { 127 return err 128 } 129 130 // Set the needed IP config 131 p.SetStartip(m["startip"]) 132 p.SetGateway(m["gateway"]) 133 p.SetEndip(m["endip"]) 134 p.SetNetmask(m["netmask"]) 135 136 if vlan, ok := d.GetOk("vlan"); ok { 137 p.SetVlan(strconv.Itoa(vlan.(int))) 138 } 139 140 // Check is this network needs to be created in a VPC 141 vpc := d.Get("vpc").(string) 142 if vpc != "" { 143 // Retrieve the vpc ID 144 vpcid, e := retrieveID(cs, "vpc", vpc) 145 if e != nil { 146 return e.Error() 147 } 148 149 // Set the vpc ID 150 p.SetVpcid(vpcid) 151 152 // Since we're in a VPC, check if we want to assiciate an ACL list 153 aclid := d.Get("aclid").(string) 154 if aclid != "" { 155 // Set the acl ID 156 p.SetAclid(aclid) 157 } 158 } 159 160 // If there is a project supplied, we retrieve and set the project id 161 if project, ok := d.GetOk("project"); ok { 162 // Retrieve the project ID 163 projectid, e := retrieveID(cs, "project", project.(string)) 164 if e != nil { 165 return e.Error() 166 } 167 // Set the default project ID 168 p.SetProjectid(projectid) 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(d.Id()) 192 if err != nil { 193 if count == 0 { 194 log.Printf( 195 "[DEBUG] Network %s does no longer exist", d.Get("name").(string)) 196 d.SetId("") 197 return nil 198 } 199 200 return err 201 } 202 203 d.Set("name", n.Name) 204 d.Set("display_text", n.Displaytext) 205 d.Set("cidr", n.Cidr) 206 d.Set("gateway", n.Gateway) 207 208 // Read the tags and store them in a map 209 tags := make(map[string]interface{}) 210 for item := range n.Tags { 211 tags[n.Tags[item].Key] = n.Tags[item].Value 212 } 213 d.Set("tags", tags) 214 215 setValueOrID(d, "network_offering", n.Networkofferingname, n.Networkofferingid) 216 setValueOrID(d, "project", n.Project, n.Projectid) 217 setValueOrID(d, "zone", n.Zonename, n.Zoneid) 218 219 return nil 220 } 221 222 func resourceCloudStackNetworkUpdate(d *schema.ResourceData, meta interface{}) error { 223 cs := meta.(*cloudstack.CloudStackClient) 224 name := d.Get("name").(string) 225 226 // Create a new parameter struct 227 p := cs.Network.NewUpdateNetworkParams(d.Id()) 228 229 // Check if the name or display text is changed 230 if d.HasChange("name") || d.HasChange("display_text") { 231 p.SetName(name) 232 233 // Compute/set the display text 234 displaytext := d.Get("display_text").(string) 235 if displaytext == "" { 236 displaytext = name 237 } 238 p.SetDisplaytext(displaytext) 239 } 240 241 // Check if the cidr is changed 242 if d.HasChange("cidr") { 243 p.SetGuestvmcidr(d.Get("cidr").(string)) 244 } 245 246 // Check if the network offering is changed 247 if d.HasChange("network_offering") { 248 // Retrieve the network_offering ID 249 networkofferingid, e := retrieveID(cs, "network_offering", d.Get("network_offering").(string)) 250 if e != nil { 251 return e.Error() 252 } 253 // Set the new network offering 254 p.SetNetworkofferingid(networkofferingid) 255 } 256 257 // Update the network 258 _, err := cs.Network.UpdateNetwork(p) 259 if err != nil { 260 return fmt.Errorf( 261 "Error updating network %s: %s", name, err) 262 } 263 264 // Update tags if they have changed 265 if d.HasChange("tags") { 266 err = setTags(cs, d, "network") 267 if err != nil { 268 return fmt.Errorf("Error updating tags: %s", err) 269 } 270 } 271 272 return resourceCloudStackNetworkRead(d, meta) 273 } 274 275 func resourceCloudStackNetworkDelete(d *schema.ResourceData, meta interface{}) error { 276 cs := meta.(*cloudstack.CloudStackClient) 277 278 // Create a new parameter struct 279 p := cs.Network.NewDeleteNetworkParams(d.Id()) 280 281 // Delete the network 282 _, err := cs.Network.DeleteNetwork(p) 283 if err != nil { 284 // This is a very poor way to be told the ID does no longer exist :( 285 if strings.Contains(err.Error(), fmt.Sprintf( 286 "Invalid parameter id value=%s due to incorrect long value format, "+ 287 "or entity does not exist", d.Id())) { 288 return nil 289 } 290 291 return fmt.Errorf("Error deleting network %s: %s", d.Get("name").(string), err) 292 } 293 return nil 294 } 295 296 func parseCIDR(d *schema.ResourceData) (map[string]string, error) { 297 m := make(map[string]string, 4) 298 299 cidr := d.Get("cidr").(string) 300 ip, ipnet, err := net.ParseCIDR(cidr) 301 if err != nil { 302 return nil, fmt.Errorf("Unable to parse cidr %s: %s", cidr, err) 303 } 304 305 msk := ipnet.Mask 306 sub := ip.Mask(msk) 307 308 m["netmask"] = fmt.Sprintf("%d.%d.%d.%d", msk[0], msk[1], msk[2], msk[3]) 309 310 if gateway, ok := d.GetOk("gateway"); ok { 311 m["gateway"] = gateway.(string) 312 } else { 313 m["gateway"] = fmt.Sprintf("%d.%d.%d.%d", sub[0], sub[1], sub[2], sub[3]+1) 314 } 315 316 if startip, ok := d.GetOk("startip"); ok { 317 m["startip"] = startip.(string) 318 } else { 319 m["startip"] = fmt.Sprintf("%d.%d.%d.%d", sub[0], sub[1], sub[2], sub[3]+2) 320 } 321 322 if endip, ok := d.GetOk("endip"); ok { 323 m["endip"] = endip.(string) 324 } else { 325 m["endip"] = fmt.Sprintf("%d.%d.%d.%d", 326 sub[0]+(0xff-msk[0]), sub[1]+(0xff-msk[1]), sub[2]+(0xff-msk[2]), sub[3]+(0xff-msk[3]-1)) 327 } 328 329 return m, nil 330 }