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