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  }