github.com/turtlemonvh/terraform@v0.6.9-0.20151204001754-8e40b6b855e8/builtin/providers/cloudstack/resource_cloudstack_network.go (about)

     1  package cloudstack
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"net"
     7  	"strings"
     8  
     9  	"github.com/hashicorp/terraform/helper/schema"
    10  	"github.com/xanzy/go-cloudstack/cloudstack"
    11  )
    12  
    13  func resourceCloudStackNetwork() *schema.Resource {
    14  	return &schema.Resource{
    15  		Create: resourceCloudStackNetworkCreate,
    16  		Read:   resourceCloudStackNetworkRead,
    17  		Update: resourceCloudStackNetworkUpdate,
    18  		Delete: resourceCloudStackNetworkDelete,
    19  
    20  		Schema: map[string]*schema.Schema{
    21  			"name": &schema.Schema{
    22  				Type:     schema.TypeString,
    23  				Required: true,
    24  			},
    25  
    26  			"display_text": &schema.Schema{
    27  				Type:     schema.TypeString,
    28  				Optional: true,
    29  				Computed: true,
    30  			},
    31  
    32  			"cidr": &schema.Schema{
    33  				Type:     schema.TypeString,
    34  				Required: true,
    35  				ForceNew: true,
    36  			},
    37  
    38  			"network_offering": &schema.Schema{
    39  				Type:     schema.TypeString,
    40  				Required: true,
    41  			},
    42  
    43  			"vpc": &schema.Schema{
    44  				Type:     schema.TypeString,
    45  				Optional: true,
    46  				ForceNew: true,
    47  			},
    48  
    49  			"aclid": &schema.Schema{
    50  				Type:     schema.TypeString,
    51  				Optional: true,
    52  				ForceNew: true,
    53  			},
    54  
    55  			"project": &schema.Schema{
    56  				Type:     schema.TypeString,
    57  				Optional: true,
    58  				ForceNew: true,
    59  			},
    60  
    61  			"zone": &schema.Schema{
    62  				Type:     schema.TypeString,
    63  				Required: true,
    64  				ForceNew: true,
    65  			},
    66  		},
    67  	}
    68  }
    69  
    70  func resourceCloudStackNetworkCreate(d *schema.ResourceData, meta interface{}) error {
    71  	cs := meta.(*cloudstack.CloudStackClient)
    72  
    73  	name := d.Get("name").(string)
    74  
    75  	// Retrieve the network_offering ID
    76  	networkofferingid, e := retrieveID(cs, "network_offering", d.Get("network_offering").(string))
    77  	if e != nil {
    78  		return e.Error()
    79  	}
    80  
    81  	// Retrieve the zone ID
    82  	zoneid, e := retrieveID(cs, "zone", d.Get("zone").(string))
    83  	if e != nil {
    84  		return e.Error()
    85  	}
    86  
    87  	// Compute/set the display text
    88  	displaytext, ok := d.GetOk("display_text")
    89  	if !ok {
    90  		displaytext = name
    91  	}
    92  
    93  	// Create a new parameter struct
    94  	p := cs.Network.NewCreateNetworkParams(displaytext.(string), name, networkofferingid, zoneid)
    95  
    96  	// Get the network details from the CIDR
    97  	m, err := parseCIDR(d.Get("cidr").(string))
    98  	if err != nil {
    99  		return err
   100  	}
   101  
   102  	// Set the needed IP config
   103  	p.SetStartip(m["start"])
   104  	p.SetGateway(m["gateway"])
   105  	p.SetEndip(m["end"])
   106  	p.SetNetmask(m["netmask"])
   107  
   108  	// Check is this network needs to be created in a VPC
   109  	vpc := d.Get("vpc").(string)
   110  	if vpc != "" {
   111  		// Retrieve the vpc ID
   112  		vpcid, e := retrieveID(cs, "vpc", vpc)
   113  		if e != nil {
   114  			return e.Error()
   115  		}
   116  
   117  		// Set the vpc ID
   118  		p.SetVpcid(vpcid)
   119  
   120  		// Since we're in a VPC, check if we want to assiciate an ACL list
   121  		aclid := d.Get("aclid").(string)
   122  		if aclid != "" {
   123  			// Set the acl ID
   124  			p.SetAclid(aclid)
   125  		}
   126  	}
   127  
   128  	// If there is a project supplied, we retrieve and set the project id
   129  	if project, ok := d.GetOk("project"); ok {
   130  		// Retrieve the project ID
   131  		projectid, e := retrieveID(cs, "project", project.(string))
   132  		if e != nil {
   133  			return e.Error()
   134  		}
   135  		// Set the default project ID
   136  		p.SetProjectid(projectid)
   137  	}
   138  
   139  	// Create the new network
   140  	r, err := cs.Network.CreateNetwork(p)
   141  	if err != nil {
   142  		return fmt.Errorf("Error creating network %s: %s", name, err)
   143  	}
   144  
   145  	d.SetId(r.Id)
   146  
   147  	return resourceCloudStackNetworkRead(d, meta)
   148  }
   149  
   150  func resourceCloudStackNetworkRead(d *schema.ResourceData, meta interface{}) error {
   151  	cs := meta.(*cloudstack.CloudStackClient)
   152  
   153  	// Get the virtual machine details
   154  	n, count, err := cs.Network.GetNetworkByID(d.Id())
   155  	if err != nil {
   156  		if count == 0 {
   157  			log.Printf(
   158  				"[DEBUG] Network %s does no longer exist", d.Get("name").(string))
   159  			d.SetId("")
   160  			return nil
   161  		}
   162  
   163  		return err
   164  	}
   165  
   166  	d.Set("name", n.Name)
   167  	d.Set("display_text", n.Displaytext)
   168  	d.Set("cidr", n.Cidr)
   169  
   170  	setValueOrID(d, "network_offering", n.Networkofferingname, n.Networkofferingid)
   171  	setValueOrID(d, "project", n.Project, n.Projectid)
   172  	setValueOrID(d, "zone", n.Zonename, n.Zoneid)
   173  
   174  	return nil
   175  }
   176  
   177  func resourceCloudStackNetworkUpdate(d *schema.ResourceData, meta interface{}) error {
   178  	cs := meta.(*cloudstack.CloudStackClient)
   179  	name := d.Get("name").(string)
   180  
   181  	// Create a new parameter struct
   182  	p := cs.Network.NewUpdateNetworkParams(d.Id())
   183  
   184  	// Check if the name or display text is changed
   185  	if d.HasChange("name") || d.HasChange("display_text") {
   186  		p.SetName(name)
   187  
   188  		// Compute/set the display text
   189  		displaytext := d.Get("display_text").(string)
   190  		if displaytext == "" {
   191  			displaytext = name
   192  		}
   193  		p.SetDisplaytext(displaytext)
   194  	}
   195  
   196  	// Check if the cidr is changed
   197  	if d.HasChange("cidr") {
   198  		p.SetGuestvmcidr(d.Get("cidr").(string))
   199  	}
   200  
   201  	// Check if the network offering is changed
   202  	if d.HasChange("network_offering") {
   203  		// Retrieve the network_offering ID
   204  		networkofferingid, e := retrieveID(cs, "network_offering", d.Get("network_offering").(string))
   205  		if e != nil {
   206  			return e.Error()
   207  		}
   208  		// Set the new network offering
   209  		p.SetNetworkofferingid(networkofferingid)
   210  	}
   211  
   212  	// Update the network
   213  	_, err := cs.Network.UpdateNetwork(p)
   214  	if err != nil {
   215  		return fmt.Errorf(
   216  			"Error updating network %s: %s", name, err)
   217  	}
   218  
   219  	return resourceCloudStackNetworkRead(d, meta)
   220  }
   221  
   222  func resourceCloudStackNetworkDelete(d *schema.ResourceData, meta interface{}) error {
   223  	cs := meta.(*cloudstack.CloudStackClient)
   224  
   225  	// Create a new parameter struct
   226  	p := cs.Network.NewDeleteNetworkParams(d.Id())
   227  
   228  	// Delete the network
   229  	_, err := cs.Network.DeleteNetwork(p)
   230  	if err != nil {
   231  		// This is a very poor way to be told the ID does no longer exist :(
   232  		if strings.Contains(err.Error(), fmt.Sprintf(
   233  			"Invalid parameter id value=%s due to incorrect long value format, "+
   234  				"or entity does not exist", d.Id())) {
   235  			return nil
   236  		}
   237  
   238  		return fmt.Errorf("Error deleting network %s: %s", d.Get("name").(string), err)
   239  	}
   240  	return nil
   241  }
   242  
   243  func parseCIDR(cidr string) (map[string]string, error) {
   244  	m := make(map[string]string, 4)
   245  
   246  	ip, ipnet, err := net.ParseCIDR(cidr)
   247  	if err != nil {
   248  		return nil, fmt.Errorf("Unable to parse cidr %s: %s", cidr, err)
   249  	}
   250  
   251  	msk := ipnet.Mask
   252  	sub := ip.Mask(msk)
   253  
   254  	m["netmask"] = fmt.Sprintf("%d.%d.%d.%d", msk[0], msk[1], msk[2], msk[3])
   255  	m["gateway"] = fmt.Sprintf("%d.%d.%d.%d", sub[0], sub[1], sub[2], sub[3]+1)
   256  	m["start"] = fmt.Sprintf("%d.%d.%d.%d", sub[0], sub[1], sub[2], sub[3]+2)
   257  	m["end"] = fmt.Sprintf("%d.%d.%d.%d",
   258  		sub[0]+(0xff-msk[0]), sub[1]+(0xff-msk[1]), sub[2]+(0xff-msk[2]), sub[3]+(0xff-msk[3]-1))
   259  
   260  	return m, nil
   261  }