github.com/vtorhonen/terraform@v0.9.0-beta2.0.20170307220345-5d894e4ffda7/builtin/providers/openstack/resource_openstack_lb_monitor_v1.go (about)

     1  package openstack
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"strconv"
     7  	"time"
     8  
     9  	"github.com/hashicorp/terraform/helper/resource"
    10  	"github.com/hashicorp/terraform/helper/schema"
    11  
    12  	"github.com/gophercloud/gophercloud"
    13  	"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas/monitors"
    14  )
    15  
    16  func resourceLBMonitorV1() *schema.Resource {
    17  	return &schema.Resource{
    18  		Create: resourceLBMonitorV1Create,
    19  		Read:   resourceLBMonitorV1Read,
    20  		Update: resourceLBMonitorV1Update,
    21  		Delete: resourceLBMonitorV1Delete,
    22  		Importer: &schema.ResourceImporter{
    23  			State: schema.ImportStatePassthrough,
    24  		},
    25  
    26  		Schema: map[string]*schema.Schema{
    27  			"region": &schema.Schema{
    28  				Type:        schema.TypeString,
    29  				Required:    true,
    30  				ForceNew:    true,
    31  				DefaultFunc: schema.EnvDefaultFunc("OS_REGION_NAME", ""),
    32  			},
    33  			"tenant_id": &schema.Schema{
    34  				Type:     schema.TypeString,
    35  				Optional: true,
    36  				ForceNew: true,
    37  				Computed: true,
    38  			},
    39  			"type": &schema.Schema{
    40  				Type:     schema.TypeString,
    41  				Required: true,
    42  				ForceNew: true,
    43  			},
    44  			"delay": &schema.Schema{
    45  				Type:     schema.TypeInt,
    46  				Required: true,
    47  				ForceNew: false,
    48  			},
    49  			"timeout": &schema.Schema{
    50  				Type:     schema.TypeInt,
    51  				Required: true,
    52  				ForceNew: false,
    53  			},
    54  			"max_retries": &schema.Schema{
    55  				Type:     schema.TypeInt,
    56  				Required: true,
    57  				ForceNew: false,
    58  			},
    59  			"url_path": &schema.Schema{
    60  				Type:     schema.TypeString,
    61  				Optional: true,
    62  				ForceNew: false,
    63  			},
    64  			"http_method": &schema.Schema{
    65  				Type:     schema.TypeString,
    66  				Optional: true,
    67  				ForceNew: false,
    68  			},
    69  			"expected_codes": &schema.Schema{
    70  				Type:     schema.TypeString,
    71  				Optional: true,
    72  				ForceNew: false,
    73  			},
    74  			"admin_state_up": &schema.Schema{
    75  				Type:     schema.TypeString,
    76  				Optional: true,
    77  				ForceNew: false,
    78  				Computed: true,
    79  			},
    80  		},
    81  	}
    82  }
    83  
    84  func resourceLBMonitorV1Create(d *schema.ResourceData, meta interface{}) error {
    85  	config := meta.(*Config)
    86  	networkingClient, err := config.networkingV2Client(GetRegion(d))
    87  	if err != nil {
    88  		return fmt.Errorf("Error creating OpenStack networking client: %s", err)
    89  	}
    90  
    91  	createOpts := monitors.CreateOpts{
    92  		TenantID:      d.Get("tenant_id").(string),
    93  		Delay:         d.Get("delay").(int),
    94  		Timeout:       d.Get("timeout").(int),
    95  		MaxRetries:    d.Get("max_retries").(int),
    96  		URLPath:       d.Get("url_path").(string),
    97  		ExpectedCodes: d.Get("expected_codes").(string),
    98  		HTTPMethod:    d.Get("http_method").(string),
    99  	}
   100  
   101  	if v, ok := d.GetOk("type"); ok {
   102  		monitorType := resourceLBMonitorV1DetermineType(v.(string))
   103  		createOpts.Type = monitorType
   104  	}
   105  
   106  	asuRaw := d.Get("admin_state_up").(string)
   107  	if asuRaw != "" {
   108  		asu, err := strconv.ParseBool(asuRaw)
   109  		if err != nil {
   110  			return fmt.Errorf("admin_state_up, if provided, must be either 'true' or 'false'")
   111  		}
   112  		createOpts.AdminStateUp = &asu
   113  	}
   114  
   115  	log.Printf("[DEBUG] Create Options: %#v", createOpts)
   116  	m, err := monitors.Create(networkingClient, createOpts).Extract()
   117  	if err != nil {
   118  		return fmt.Errorf("Error creating OpenStack LB Monitor: %s", err)
   119  	}
   120  	log.Printf("[INFO] LB Monitor ID: %s", m.ID)
   121  
   122  	log.Printf("[DEBUG] Waiting for OpenStack LB Monitor (%s) to become available.", m.ID)
   123  
   124  	stateConf := &resource.StateChangeConf{
   125  		Pending:    []string{"PENDING_CREATE"},
   126  		Target:     []string{"ACTIVE"},
   127  		Refresh:    waitForLBMonitorActive(networkingClient, m.ID),
   128  		Timeout:    2 * time.Minute,
   129  		Delay:      5 * time.Second,
   130  		MinTimeout: 3 * time.Second,
   131  	}
   132  
   133  	_, err = stateConf.WaitForState()
   134  	if err != nil {
   135  		return err
   136  	}
   137  
   138  	d.SetId(m.ID)
   139  
   140  	return resourceLBMonitorV1Read(d, meta)
   141  }
   142  
   143  func resourceLBMonitorV1Read(d *schema.ResourceData, meta interface{}) error {
   144  	config := meta.(*Config)
   145  	networkingClient, err := config.networkingV2Client(GetRegion(d))
   146  	if err != nil {
   147  		return fmt.Errorf("Error creating OpenStack networking client: %s", err)
   148  	}
   149  
   150  	m, err := monitors.Get(networkingClient, d.Id()).Extract()
   151  	if err != nil {
   152  		return CheckDeleted(d, err, "LB monitor")
   153  	}
   154  
   155  	log.Printf("[DEBUG] Retrieved OpenStack LB Monitor %s: %+v", d.Id(), m)
   156  
   157  	d.Set("type", m.Type)
   158  	d.Set("delay", m.Delay)
   159  	d.Set("timeout", m.Timeout)
   160  	d.Set("max_retries", m.MaxRetries)
   161  	d.Set("tenant_id", m.TenantID)
   162  	d.Set("url_path", m.URLPath)
   163  	d.Set("http_method", m.HTTPMethod)
   164  	d.Set("expected_codes", m.ExpectedCodes)
   165  	d.Set("admin_state_up", strconv.FormatBool(m.AdminStateUp))
   166  	d.Set("region", GetRegion(d))
   167  
   168  	return nil
   169  }
   170  
   171  func resourceLBMonitorV1Update(d *schema.ResourceData, meta interface{}) error {
   172  	config := meta.(*Config)
   173  	networkingClient, err := config.networkingV2Client(GetRegion(d))
   174  	if err != nil {
   175  		return fmt.Errorf("Error creating OpenStack networking client: %s", err)
   176  	}
   177  
   178  	updateOpts := monitors.UpdateOpts{
   179  		Delay:         d.Get("delay").(int),
   180  		Timeout:       d.Get("timeout").(int),
   181  		MaxRetries:    d.Get("max_retries").(int),
   182  		URLPath:       d.Get("url_path").(string),
   183  		HTTPMethod:    d.Get("http_method").(string),
   184  		ExpectedCodes: d.Get("expected_codes").(string),
   185  	}
   186  
   187  	if d.HasChange("admin_state_up") {
   188  		asuRaw := d.Get("admin_state_up").(string)
   189  		if asuRaw != "" {
   190  			asu, err := strconv.ParseBool(asuRaw)
   191  			if err != nil {
   192  				return fmt.Errorf("admin_state_up, if provided, must be either 'true' or 'false'")
   193  			}
   194  			updateOpts.AdminStateUp = &asu
   195  		}
   196  	}
   197  
   198  	log.Printf("[DEBUG] Updating OpenStack LB Monitor %s with options: %+v", d.Id(), updateOpts)
   199  
   200  	_, err = monitors.Update(networkingClient, d.Id(), updateOpts).Extract()
   201  	if err != nil {
   202  		return fmt.Errorf("Error updating OpenStack LB Monitor: %s", err)
   203  	}
   204  
   205  	return resourceLBMonitorV1Read(d, meta)
   206  }
   207  
   208  func resourceLBMonitorV1Delete(d *schema.ResourceData, meta interface{}) error {
   209  	config := meta.(*Config)
   210  	networkingClient, err := config.networkingV2Client(GetRegion(d))
   211  	if err != nil {
   212  		return fmt.Errorf("Error creating OpenStack networking client: %s", err)
   213  	}
   214  
   215  	stateConf := &resource.StateChangeConf{
   216  		Pending:    []string{"ACTIVE", "PENDING_DELETE"},
   217  		Target:     []string{"DELETED"},
   218  		Refresh:    waitForLBMonitorDelete(networkingClient, d.Id()),
   219  		Timeout:    2 * time.Minute,
   220  		Delay:      5 * time.Second,
   221  		MinTimeout: 3 * time.Second,
   222  	}
   223  
   224  	_, err = stateConf.WaitForState()
   225  	if err != nil {
   226  		return fmt.Errorf("Error deleting OpenStack LB Monitor: %s", err)
   227  	}
   228  
   229  	d.SetId("")
   230  	return nil
   231  }
   232  
   233  func resourceLBMonitorV1DetermineType(t string) monitors.MonitorType {
   234  	var monitorType monitors.MonitorType
   235  	switch t {
   236  	case "PING":
   237  		monitorType = monitors.TypePING
   238  	case "TCP":
   239  		monitorType = monitors.TypeTCP
   240  	case "HTTP":
   241  		monitorType = monitors.TypeHTTP
   242  	case "HTTPS":
   243  		monitorType = monitors.TypeHTTPS
   244  	}
   245  
   246  	return monitorType
   247  }
   248  
   249  func waitForLBMonitorActive(networkingClient *gophercloud.ServiceClient, monitorId string) resource.StateRefreshFunc {
   250  	return func() (interface{}, string, error) {
   251  		m, err := monitors.Get(networkingClient, monitorId).Extract()
   252  		if err != nil {
   253  			return nil, "", err
   254  		}
   255  
   256  		// The monitor resource has no Status attribute, so a successful Get is the best we can do
   257  		log.Printf("[DEBUG] OpenStack LB Monitor: %+v", m)
   258  		return m, "ACTIVE", nil
   259  	}
   260  }
   261  
   262  func waitForLBMonitorDelete(networkingClient *gophercloud.ServiceClient, monitorId string) resource.StateRefreshFunc {
   263  	return func() (interface{}, string, error) {
   264  		log.Printf("[DEBUG] Attempting to delete OpenStack LB Monitor %s", monitorId)
   265  
   266  		m, err := monitors.Get(networkingClient, monitorId).Extract()
   267  		if err != nil {
   268  			if _, ok := err.(gophercloud.ErrDefault404); ok {
   269  				log.Printf("[DEBUG] Successfully deleted OpenStack LB Monitor %s", monitorId)
   270  				return m, "DELETED", nil
   271  			}
   272  
   273  			if errCode, ok := err.(gophercloud.ErrUnexpectedResponseCode); ok {
   274  				if errCode.Actual == 409 {
   275  					log.Printf("[DEBUG] OpenStack LB Monitor (%s) is waiting for Pool to delete.", monitorId)
   276  					return m, "PENDING", nil
   277  				}
   278  			}
   279  
   280  			return m, "ACTIVE", err
   281  		}
   282  
   283  		log.Printf("[DEBUG] OpenStack LB Monitor: %+v", m)
   284  		err = monitors.Delete(networkingClient, monitorId).ExtractErr()
   285  		if err != nil {
   286  			if _, ok := err.(gophercloud.ErrDefault404); ok {
   287  				log.Printf("[DEBUG] Successfully deleted OpenStack LB Monitor %s", monitorId)
   288  				return m, "DELETED", nil
   289  			}
   290  
   291  			if errCode, ok := err.(gophercloud.ErrUnexpectedResponseCode); ok {
   292  				if errCode.Actual == 409 {
   293  					log.Printf("[DEBUG] OpenStack LB Monitor (%s) is waiting for Pool to delete.", monitorId)
   294  					return m, "PENDING", nil
   295  				}
   296  			}
   297  
   298  			return m, "ACTIVE", err
   299  		}
   300  
   301  		log.Printf("[DEBUG] OpenStack LB Monitor %s still active.", monitorId)
   302  		return m, "ACTIVE", nil
   303  	}
   304  
   305  }