github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/builtin/providers/clc/resource_clc_public_ip.go (about)

     1  package clc
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"strconv"
     7  
     8  	clc "github.com/CenturyLinkCloud/clc-sdk"
     9  	"github.com/CenturyLinkCloud/clc-sdk/server"
    10  
    11  	"github.com/hashicorp/terraform/helper/schema"
    12  )
    13  
    14  func resourceCLCPublicIP() *schema.Resource {
    15  	return &schema.Resource{
    16  		Create: resourceCLCPublicIPCreate,
    17  		Read:   resourceCLCPublicIPRead,
    18  		Update: resourceCLCPublicIPUpdate,
    19  		Delete: resourceCLCPublicIPDelete,
    20  		Schema: map[string]*schema.Schema{
    21  			"server_id": &schema.Schema{
    22  				Type:     schema.TypeString,
    23  				Required: true,
    24  				ForceNew: true,
    25  			},
    26  			"internal_ip_address": &schema.Schema{
    27  				Type:     schema.TypeString,
    28  				Optional: true,
    29  				Computed: true,
    30  				Default:  nil,
    31  			},
    32  			"ports": &schema.Schema{
    33  				Type:     schema.TypeList,
    34  				Required: true,
    35  				Elem:     &schema.Schema{Type: schema.TypeMap},
    36  			},
    37  			"source_restrictions": &schema.Schema{
    38  				Type:     schema.TypeList,
    39  				Optional: true,
    40  				Elem:     &schema.Schema{Type: schema.TypeMap},
    41  			},
    42  		},
    43  	}
    44  }
    45  
    46  func resourceCLCPublicIPCreate(d *schema.ResourceData, meta interface{}) error {
    47  	client := meta.(*clc.Client)
    48  	sid := d.Get("server_id").(string)
    49  	priv := d.Get("internal_ip_address").(string)
    50  	ports, sources := parseIPSpec(d)
    51  	req := server.PublicIP{
    52  		Ports:              *ports,
    53  		SourceRestrictions: *sources,
    54  	}
    55  
    56  	// since the API doesn't tell us the public IP it allocated,
    57  	// track what was added after the call.
    58  	ips := make(map[string]string)
    59  	prev, err := client.Server.Get(sid)
    60  	if err != nil {
    61  		return fmt.Errorf("Failed finding server %v: %v", sid, err)
    62  	}
    63  	for _, i := range prev.Details.IPaddresses {
    64  		ips[i.Internal] = i.Public
    65  	}
    66  
    67  	if priv != "" {
    68  		// use existing private ip
    69  		if _, present := ips[priv]; !present {
    70  			return fmt.Errorf("Failed finding internal ip to use %v", priv)
    71  		}
    72  		req.InternalIP = priv
    73  	}
    74  	// execute the request
    75  	resp, err := client.Server.AddPublicIP(sid, req)
    76  	if err != nil {
    77  		return fmt.Errorf("Failed reserving public ip: %v", err)
    78  	}
    79  	err = waitStatus(client, resp.ID)
    80  	if err != nil {
    81  		return err
    82  	}
    83  
    84  	server, err := client.Server.Get(sid)
    85  	if err != nil {
    86  		return fmt.Errorf("Failed refreshing server for public ip: %v", err)
    87  	}
    88  	for _, i := range server.Details.IPaddresses {
    89  		if priv != "" && i.Internal == priv {
    90  			// bind
    91  			log.Printf("[DEBUG] Public IP bound on existing internal:%v - %v", i.Internal, i.Public)
    92  			d.SetId(i.Public)
    93  			break
    94  		} else if ips[i.Internal] == "" && i.Public != "" {
    95  			// allocate
    96  			log.Printf("[DEBUG] Public IP allocated on new internal:%v - %v", i.Internal, i.Public)
    97  			d.SetId(i.Public)
    98  			break
    99  		}
   100  	}
   101  	return resourceCLCPublicIPRead(d, meta)
   102  }
   103  
   104  func resourceCLCPublicIPRead(d *schema.ResourceData, meta interface{}) error {
   105  	client := meta.(*clc.Client)
   106  	pip := d.Id()
   107  	s := d.Get("server_id").(string)
   108  	resp, err := client.Server.GetPublicIP(s, pip)
   109  	if err != nil {
   110  		log.Printf("[INFO] Failed finding public ip: %v. Marking destroyed", d.Id())
   111  		d.SetId("")
   112  		return nil
   113  	}
   114  
   115  	d.Set("internal_ip_address", resp.InternalIP)
   116  	d.Set("ports", resp.Ports)
   117  	d.Set("source_restrictions", resp.SourceRestrictions)
   118  	return nil
   119  }
   120  
   121  func resourceCLCPublicIPUpdate(d *schema.ResourceData, meta interface{}) error {
   122  	client := meta.(*clc.Client)
   123  	ip := d.Id()
   124  	sid := d.Get("server_id").(string)
   125  	if d.HasChange("ports") || d.HasChange("source_restrictions") {
   126  		ports, sources := parseIPSpec(d)
   127  		req := server.PublicIP{
   128  			Ports:              *ports,
   129  			SourceRestrictions: *sources,
   130  		}
   131  		resp, err := client.Server.UpdatePublicIP(sid, ip, req)
   132  		if err != nil {
   133  			return fmt.Errorf("Failed updating public ip: %v", err)
   134  		}
   135  		err = waitStatus(client, resp.ID)
   136  		if err != nil {
   137  			return err
   138  		}
   139  		log.Printf("[INFO] Successfully updated %v with %v", ip, req)
   140  	}
   141  	return nil
   142  }
   143  
   144  func resourceCLCPublicIPDelete(d *schema.ResourceData, meta interface{}) error {
   145  	client := meta.(*clc.Client)
   146  	s := d.Get("server_id").(string)
   147  	ip := d.Id()
   148  	log.Printf("[INFO] Deleting public ip %v", ip)
   149  	resp, err := client.Server.DeletePublicIP(s, ip)
   150  	if err != nil {
   151  		return fmt.Errorf("Failed deleting public ip: %v", err)
   152  	}
   153  	err = waitStatus(client, resp.ID)
   154  	if err != nil {
   155  		return err
   156  	}
   157  	log.Printf("[INFO] Public IP sucessfully deleted: %v", ip)
   158  	return nil
   159  }
   160  
   161  func parseIPSpec(d *schema.ResourceData) (*[]server.Port, *[]server.SourceRestriction) {
   162  	var ports []server.Port
   163  	var sources []server.SourceRestriction
   164  	if v := d.Get("ports"); v != nil {
   165  		for _, v := range v.([]interface{}) {
   166  			m := v.(map[string]interface{})
   167  			p := server.Port{}
   168  			port, err := strconv.Atoi(m["port"].(string))
   169  			if err != nil {
   170  				log.Printf("[WARN] Failed parsing port '%v'. skipping", m["port"])
   171  				continue
   172  			}
   173  			p.Protocol = m["protocol"].(string)
   174  			p.Port = port
   175  			through := -1
   176  			if to := m["port_to"]; to != nil {
   177  				through, _ = strconv.Atoi(to.(string))
   178  				log.Printf("[DEBUG] port range: %v-%v", port, through)
   179  				p.PortTo = through
   180  			}
   181  			ports = append(ports, p)
   182  		}
   183  	}
   184  	if v := d.Get("source_restrictions"); v != nil {
   185  		for _, v := range v.([]interface{}) {
   186  			m := v.(map[string]interface{})
   187  			r := server.SourceRestriction{}
   188  			r.CIDR = m["cidr"].(string)
   189  			sources = append(sources, r)
   190  		}
   191  	}
   192  	return &ports, &sources
   193  }