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

     1  package alicloud
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"strings"
     7  
     8  	"errors"
     9  	"github.com/denverdino/aliyungo/common"
    10  	"github.com/denverdino/aliyungo/slb"
    11  	"github.com/hashicorp/terraform/helper/hashcode"
    12  	"github.com/hashicorp/terraform/helper/resource"
    13  	"github.com/hashicorp/terraform/helper/schema"
    14  	"time"
    15  )
    16  
    17  func resourceAliyunSlb() *schema.Resource {
    18  	return &schema.Resource{
    19  		Create: resourceAliyunSlbCreate,
    20  		Read:   resourceAliyunSlbRead,
    21  		Update: resourceAliyunSlbUpdate,
    22  		Delete: resourceAliyunSlbDelete,
    23  
    24  		Schema: map[string]*schema.Schema{
    25  			"name": &schema.Schema{
    26  				Type:         schema.TypeString,
    27  				Optional:     true,
    28  				ValidateFunc: validateSlbName,
    29  				Computed:     true,
    30  			},
    31  
    32  			"internet": &schema.Schema{
    33  				Type:     schema.TypeBool,
    34  				Optional: true,
    35  				ForceNew: true,
    36  			},
    37  
    38  			"vswitch_id": &schema.Schema{
    39  				Type:     schema.TypeString,
    40  				Optional: true,
    41  				ForceNew: true,
    42  			},
    43  
    44  			"internet_charge_type": &schema.Schema{
    45  				Type:         schema.TypeString,
    46  				Optional:     true,
    47  				ForceNew:     true,
    48  				Default:      "paybytraffic",
    49  				ValidateFunc: validateSlbInternetChargeType,
    50  			},
    51  
    52  			"bandwidth": &schema.Schema{
    53  				Type:         schema.TypeInt,
    54  				Optional:     true,
    55  				ValidateFunc: validateSlbBandwidth,
    56  				Computed:     true,
    57  			},
    58  
    59  			"listener": &schema.Schema{
    60  				Type:     schema.TypeSet,
    61  				Optional: true,
    62  				Elem: &schema.Resource{
    63  					Schema: map[string]*schema.Schema{
    64  						"instance_port": &schema.Schema{
    65  							Type:         schema.TypeInt,
    66  							ValidateFunc: validateInstancePort,
    67  							Required:     true,
    68  						},
    69  
    70  						"lb_port": &schema.Schema{
    71  							Type:         schema.TypeInt,
    72  							ValidateFunc: validateInstancePort,
    73  							Required:     true,
    74  						},
    75  
    76  						"lb_protocol": &schema.Schema{
    77  							Type:         schema.TypeString,
    78  							ValidateFunc: validateInstanceProtocol,
    79  							Required:     true,
    80  						},
    81  
    82  						"bandwidth": &schema.Schema{
    83  							Type:         schema.TypeInt,
    84  							ValidateFunc: validateSlbListenerBandwidth,
    85  							Required:     true,
    86  						},
    87  						"scheduler": &schema.Schema{
    88  							Type:         schema.TypeString,
    89  							ValidateFunc: validateSlbListenerScheduler,
    90  							Optional:     true,
    91  							Default:      slb.WRRScheduler,
    92  						},
    93  						//http & https
    94  						"sticky_session": &schema.Schema{
    95  							Type: schema.TypeString,
    96  							ValidateFunc: validateAllowedStringValue([]string{
    97  								string(slb.OnFlag),
    98  								string(slb.OffFlag)}),
    99  							Optional: true,
   100  							Default:  slb.OffFlag,
   101  						},
   102  						//http & https
   103  						"sticky_session_type": &schema.Schema{
   104  							Type: schema.TypeString,
   105  							ValidateFunc: validateAllowedStringValue([]string{
   106  								string(slb.InsertStickySessionType),
   107  								string(slb.ServerStickySessionType)}),
   108  							Optional: true,
   109  						},
   110  						//http & https
   111  						"cookie_timeout": &schema.Schema{
   112  							Type:         schema.TypeInt,
   113  							ValidateFunc: validateSlbListenerCookieTimeout,
   114  							Optional:     true,
   115  						},
   116  						//http & https
   117  						"cookie": &schema.Schema{
   118  							Type:         schema.TypeString,
   119  							ValidateFunc: validateSlbListenerCookie,
   120  							Optional:     true,
   121  						},
   122  						//tcp & udp
   123  						"persistence_timeout": &schema.Schema{
   124  							Type:         schema.TypeInt,
   125  							ValidateFunc: validateSlbListenerPersistenceTimeout,
   126  							Optional:     true,
   127  							Default:      0,
   128  						},
   129  						//http & https
   130  						"health_check": &schema.Schema{
   131  							Type: schema.TypeString,
   132  							ValidateFunc: validateAllowedStringValue([]string{
   133  								string(slb.OnFlag),
   134  								string(slb.OffFlag)}),
   135  							Optional: true,
   136  							Default:  slb.OffFlag,
   137  						},
   138  						//tcp
   139  						"health_check_type": &schema.Schema{
   140  							Type: schema.TypeString,
   141  							ValidateFunc: validateAllowedStringValue([]string{
   142  								string(slb.TCPHealthCheckType),
   143  								string(slb.HTTPHealthCheckType)}),
   144  							Optional: true,
   145  							Default:  slb.TCPHealthCheckType,
   146  						},
   147  						//http & https & tcp
   148  						"health_check_domain": &schema.Schema{
   149  							Type:         schema.TypeString,
   150  							ValidateFunc: validateSlbListenerHealthCheckDomain,
   151  							Optional:     true,
   152  						},
   153  						//http & https & tcp
   154  						"health_check_uri": &schema.Schema{
   155  							Type:         schema.TypeString,
   156  							ValidateFunc: validateSlbListenerHealthCheckUri,
   157  							Optional:     true,
   158  						},
   159  						"health_check_connect_port": &schema.Schema{
   160  							Type:         schema.TypeInt,
   161  							ValidateFunc: validateSlbListenerHealthCheckConnectPort,
   162  							Optional:     true,
   163  						},
   164  						"healthy_threshold": &schema.Schema{
   165  							Type:         schema.TypeInt,
   166  							ValidateFunc: validateIntegerInRange(1, 10),
   167  							Optional:     true,
   168  						},
   169  						"unhealthy_threshold": &schema.Schema{
   170  							Type:         schema.TypeInt,
   171  							ValidateFunc: validateIntegerInRange(1, 10),
   172  							Optional:     true,
   173  						},
   174  
   175  						"health_check_timeout": &schema.Schema{
   176  							Type:         schema.TypeInt,
   177  							ValidateFunc: validateIntegerInRange(1, 50),
   178  							Optional:     true,
   179  						},
   180  						"health_check_interval": &schema.Schema{
   181  							Type:         schema.TypeInt,
   182  							ValidateFunc: validateIntegerInRange(1, 5),
   183  							Optional:     true,
   184  						},
   185  						//http & https & tcp
   186  						"health_check_http_code": &schema.Schema{
   187  							Type: schema.TypeString,
   188  							ValidateFunc: validateAllowedSplitStringValue([]string{
   189  								string(slb.HTTP_2XX),
   190  								string(slb.HTTP_3XX),
   191  								string(slb.HTTP_4XX),
   192  								string(slb.HTTP_5XX)}, ","),
   193  							Optional: true,
   194  						},
   195  						//https
   196  						"ssl_certificate_id": &schema.Schema{
   197  							Type:     schema.TypeString,
   198  							Optional: true,
   199  						},
   200  						//https
   201  						//"ca_certificate_id": &schema.Schema{
   202  						//	Type:     schema.TypeString,
   203  						//	Optional: true,
   204  						//},
   205  					},
   206  				},
   207  				Set: resourceAliyunSlbListenerHash,
   208  			},
   209  
   210  			//deprecated
   211  			"instances": &schema.Schema{
   212  				Type:     schema.TypeSet,
   213  				Elem:     &schema.Schema{Type: schema.TypeString},
   214  				Optional: true,
   215  				Set:      schema.HashString,
   216  			},
   217  
   218  			"address": &schema.Schema{
   219  				Type:     schema.TypeString,
   220  				Computed: true,
   221  			},
   222  		},
   223  	}
   224  }
   225  
   226  func resourceAliyunSlbCreate(d *schema.ResourceData, meta interface{}) error {
   227  
   228  	slbconn := meta.(*AliyunClient).slbconn
   229  
   230  	var slbName string
   231  	if v, ok := d.GetOk("name"); ok {
   232  		slbName = v.(string)
   233  	} else {
   234  		slbName = resource.PrefixedUniqueId("tf-lb-")
   235  		d.Set("name", slbName)
   236  	}
   237  
   238  	slbArgs := &slb.CreateLoadBalancerArgs{
   239  		RegionId:         getRegion(d, meta),
   240  		LoadBalancerName: slbName,
   241  	}
   242  
   243  	if internet, ok := d.GetOk("internet"); ok && internet.(bool) {
   244  		slbArgs.AddressType = slb.InternetAddressType
   245  		d.Set("internet", true)
   246  	} else {
   247  		slbArgs.AddressType = slb.IntranetAddressType
   248  		d.Set("internet", false)
   249  	}
   250  
   251  	if v, ok := d.GetOk("internet_charge_type"); ok && v.(string) != "" {
   252  		slbArgs.InternetChargeType = slb.InternetChargeType(v.(string))
   253  	}
   254  
   255  	if v, ok := d.GetOk("bandwidth"); ok && v.(int) != 0 {
   256  		slbArgs.Bandwidth = v.(int)
   257  	}
   258  
   259  	if v, ok := d.GetOk("vswitch_id"); ok && v.(string) != "" {
   260  		slbArgs.VSwitchId = v.(string)
   261  	}
   262  	slb, err := slbconn.CreateLoadBalancer(slbArgs)
   263  	if err != nil {
   264  		return err
   265  	}
   266  
   267  	d.SetId(slb.LoadBalancerId)
   268  
   269  	return resourceAliyunSlbUpdate(d, meta)
   270  }
   271  
   272  func resourceAliyunSlbRead(d *schema.ResourceData, meta interface{}) error {
   273  	slbconn := meta.(*AliyunClient).slbconn
   274  	loadBalancer, err := slbconn.DescribeLoadBalancerAttribute(d.Id())
   275  	if err != nil {
   276  		if notFoundError(err) {
   277  			d.SetId("")
   278  			return nil
   279  		}
   280  
   281  		return err
   282  	}
   283  
   284  	if loadBalancer == nil {
   285  		d.SetId("")
   286  		return nil
   287  	}
   288  
   289  	d.Set("name", loadBalancer.LoadBalancerName)
   290  
   291  	if loadBalancer.AddressType == slb.InternetAddressType {
   292  		d.Set("internal", true)
   293  	} else {
   294  		d.Set("internal", false)
   295  	}
   296  	d.Set("internet_charge_type", loadBalancer.InternetChargeType)
   297  	d.Set("bandwidth", loadBalancer.Bandwidth)
   298  	d.Set("vswitch_id", loadBalancer.VSwitchId)
   299  	d.Set("address", loadBalancer.Address)
   300  
   301  	return nil
   302  }
   303  
   304  func resourceAliyunSlbUpdate(d *schema.ResourceData, meta interface{}) error {
   305  
   306  	slbconn := meta.(*AliyunClient).slbconn
   307  
   308  	d.Partial(true)
   309  
   310  	if d.HasChange("name") {
   311  		err := slbconn.SetLoadBalancerName(d.Id(), d.Get("name").(string))
   312  		if err != nil {
   313  			return err
   314  		}
   315  
   316  		d.SetPartial("name")
   317  	}
   318  
   319  	if d.Get("internet") == true && d.Get("internet_charge_type") == "paybybandwidth" {
   320  		//don't intranet web and paybybandwidth, then can modify bandwidth
   321  		if d.HasChange("bandwidth") {
   322  			args := &slb.ModifyLoadBalancerInternetSpecArgs{
   323  				LoadBalancerId: d.Id(),
   324  				Bandwidth:      d.Get("bandwidth").(int),
   325  			}
   326  			err := slbconn.ModifyLoadBalancerInternetSpec(args)
   327  			if err != nil {
   328  				return err
   329  			}
   330  
   331  			d.SetPartial("bandwidth")
   332  		}
   333  	}
   334  
   335  	if d.HasChange("listener") {
   336  		o, n := d.GetChange("listener")
   337  		os := o.(*schema.Set)
   338  		ns := n.(*schema.Set)
   339  
   340  		remove, _ := expandListeners(os.Difference(ns).List())
   341  		add, _ := expandListeners(ns.Difference(os).List())
   342  
   343  		if len(remove) > 0 {
   344  			for _, listener := range remove {
   345  				err := slbconn.DeleteLoadBalancerListener(d.Id(), listener.LoadBalancerPort)
   346  				if err != nil {
   347  					return fmt.Errorf("Failure removing outdated SLB listeners: %#v", err)
   348  				}
   349  			}
   350  		}
   351  
   352  		if len(add) > 0 {
   353  			for _, listener := range add {
   354  				err := createListener(slbconn, d.Id(), listener)
   355  				if err != nil {
   356  					return fmt.Errorf("Failure add SLB listeners: %#v", err)
   357  				}
   358  			}
   359  		}
   360  
   361  		d.SetPartial("listener")
   362  	}
   363  
   364  	// If we currently have instances, or did have instances,
   365  	// we want to figure out what to add and remove from the load
   366  	// balancer
   367  	if d.HasChange("instances") {
   368  		o, n := d.GetChange("instances")
   369  		os := o.(*schema.Set)
   370  		ns := n.(*schema.Set)
   371  		remove := expandBackendServers(os.Difference(ns).List())
   372  		add := expandBackendServers(ns.Difference(os).List())
   373  
   374  		if len(add) > 0 {
   375  			_, err := slbconn.AddBackendServers(d.Id(), add)
   376  			if err != nil {
   377  				return err
   378  			}
   379  		}
   380  		if len(remove) > 0 {
   381  			removeBackendServers := make([]string, 0, len(remove))
   382  			for _, e := range remove {
   383  				removeBackendServers = append(removeBackendServers, e.ServerId)
   384  			}
   385  			_, err := slbconn.RemoveBackendServers(d.Id(), removeBackendServers)
   386  			if err != nil {
   387  				return err
   388  			}
   389  		}
   390  
   391  		d.SetPartial("instances")
   392  	}
   393  
   394  	d.Partial(false)
   395  
   396  	return resourceAliyunSlbRead(d, meta)
   397  }
   398  
   399  func resourceAliyunSlbDelete(d *schema.ResourceData, meta interface{}) error {
   400  	conn := meta.(*AliyunClient).slbconn
   401  
   402  	return resource.Retry(5*time.Minute, func() *resource.RetryError {
   403  		err := conn.DeleteLoadBalancer(d.Id())
   404  
   405  		if err != nil {
   406  			return resource.NonRetryableError(err)
   407  		}
   408  
   409  		loadBalancer, err := conn.DescribeLoadBalancerAttribute(d.Id())
   410  		if err != nil {
   411  			e, _ := err.(*common.Error)
   412  			if e.ErrorResponse.Code == LoadBalancerNotFound {
   413  				return nil
   414  			}
   415  			return resource.NonRetryableError(err)
   416  		}
   417  		if loadBalancer != nil {
   418  			return resource.RetryableError(fmt.Errorf("LoadBalancer in use - trying again while it deleted."))
   419  		}
   420  		return nil
   421  	})
   422  }
   423  
   424  func resourceAliyunSlbListenerHash(v interface{}) int {
   425  	var buf bytes.Buffer
   426  	m := v.(map[string]interface{})
   427  	buf.WriteString(fmt.Sprintf("%d-", m["instance_port"].(int)))
   428  	buf.WriteString(fmt.Sprintf("%d-", m["lb_port"].(int)))
   429  	buf.WriteString(fmt.Sprintf("%s-",
   430  		strings.ToLower(m["lb_protocol"].(string))))
   431  
   432  	buf.WriteString(fmt.Sprintf("%d-", m["bandwidth"].(int)))
   433  
   434  	if v, ok := m["ssl_certificate_id"]; ok {
   435  		buf.WriteString(fmt.Sprintf("%s-", v.(string)))
   436  	}
   437  
   438  	return hashcode.String(buf.String())
   439  }
   440  
   441  func createListener(conn *slb.Client, loadBalancerId string, listener *Listener) error {
   442  
   443  	errTypeJudge := func(err error) error {
   444  		if err != nil {
   445  			if listenerType, ok := err.(*ListenerErr); ok {
   446  				if listenerType.ErrType == HealthCheckErrType {
   447  					return fmt.Errorf("When the HealthCheck is %s, then related HealthCheck parameter "+
   448  						"must have.", slb.OnFlag)
   449  				} else if listenerType.ErrType == StickySessionErrType {
   450  					return fmt.Errorf("When the StickySession is %s, then StickySessionType parameter "+
   451  						"must have.", slb.OnFlag)
   452  				} else if listenerType.ErrType == CookieTimeOutErrType {
   453  					return fmt.Errorf("When the StickySession is %s and StickySessionType is %s, "+
   454  						"then CookieTimeout parameter must have.", slb.OnFlag, slb.InsertStickySessionType)
   455  				} else if listenerType.ErrType == CookieErrType {
   456  					return fmt.Errorf("When the StickySession is %s and StickySessionType is %s, "+
   457  						"then Cookie parameter must have.", slb.OnFlag, slb.ServerStickySessionType)
   458  				}
   459  				return fmt.Errorf("slb listener check errtype not found.")
   460  			}
   461  		}
   462  		return nil
   463  	}
   464  
   465  	if listener.Protocol == strings.ToLower("tcp") {
   466  
   467  		args := getTcpListenerArgs(loadBalancerId, listener)
   468  
   469  		if err := conn.CreateLoadBalancerTCPListener(&args); err != nil {
   470  			return err
   471  		}
   472  	} else if listener.Protocol == strings.ToLower("http") {
   473  		args, argsErr := getHttpListenerArgs(loadBalancerId, listener)
   474  		if paramErr := errTypeJudge(argsErr); paramErr != nil {
   475  			return paramErr
   476  		}
   477  
   478  		if err := conn.CreateLoadBalancerHTTPListener(&args); err != nil {
   479  			return err
   480  		}
   481  	} else if listener.Protocol == strings.ToLower("https") {
   482  		listenerType, err := getHttpListenerType(loadBalancerId, listener)
   483  		if paramErr := errTypeJudge(err); paramErr != nil {
   484  			return paramErr
   485  		}
   486  
   487  		args := &slb.CreateLoadBalancerHTTPSListenerArgs{
   488  			HTTPListenerType: listenerType,
   489  		}
   490  		if listener.SSLCertificateId == "" {
   491  			return fmt.Errorf("Server Certificated Id cann't be null")
   492  		}
   493  
   494  		args.ServerCertificateId = listener.SSLCertificateId
   495  
   496  		if err := conn.CreateLoadBalancerHTTPSListener(args); err != nil {
   497  			return err
   498  		}
   499  	} else if listener.Protocol == strings.ToLower("udp") {
   500  		args := getUdpListenerArgs(loadBalancerId, listener)
   501  
   502  		if err := conn.CreateLoadBalancerUDPListener(&args); err != nil {
   503  			return err
   504  		}
   505  	}
   506  
   507  	if err := conn.StartLoadBalancerListener(loadBalancerId, listener.LoadBalancerPort); err != nil {
   508  		return err
   509  	}
   510  
   511  	return nil
   512  }
   513  
   514  func getTcpListenerArgs(loadBalancerId string, listener *Listener) slb.CreateLoadBalancerTCPListenerArgs {
   515  	args := slb.CreateLoadBalancerTCPListenerArgs{
   516  		LoadBalancerId:            loadBalancerId,
   517  		ListenerPort:              listener.LoadBalancerPort,
   518  		BackendServerPort:         listener.InstancePort,
   519  		Bandwidth:                 listener.Bandwidth,
   520  		Scheduler:                 listener.Scheduler,
   521  		PersistenceTimeout:        listener.PersistenceTimeout,
   522  		HealthCheckType:           listener.HealthCheckType,
   523  		HealthCheckDomain:         listener.HealthCheckDomain,
   524  		HealthCheckURI:            listener.HealthCheckURI,
   525  		HealthCheckConnectPort:    listener.HealthCheckConnectPort,
   526  		HealthyThreshold:          listener.HealthyThreshold,
   527  		UnhealthyThreshold:        listener.UnhealthyThreshold,
   528  		HealthCheckConnectTimeout: listener.HealthCheckTimeout,
   529  		HealthCheckInterval:       listener.HealthCheckInterval,
   530  		HealthCheckHttpCode:       listener.HealthCheckHttpCode,
   531  	}
   532  	return args
   533  }
   534  
   535  func getUdpListenerArgs(loadBalancerId string, listener *Listener) slb.CreateLoadBalancerUDPListenerArgs {
   536  	args := slb.CreateLoadBalancerUDPListenerArgs{
   537  		LoadBalancerId:            loadBalancerId,
   538  		ListenerPort:              listener.LoadBalancerPort,
   539  		BackendServerPort:         listener.InstancePort,
   540  		Bandwidth:                 listener.Bandwidth,
   541  		PersistenceTimeout:        listener.PersistenceTimeout,
   542  		HealthCheckConnectTimeout: listener.HealthCheckTimeout,
   543  		HealthCheckInterval:       listener.HealthCheckInterval,
   544  	}
   545  	return args
   546  }
   547  
   548  func getHttpListenerType(loadBalancerId string, listener *Listener) (listenType slb.HTTPListenerType, err error) {
   549  
   550  	if listener.HealthCheck == slb.OnFlag {
   551  		if listener.HealthCheckURI == "" || listener.HealthCheckDomain == "" || listener.HealthCheckConnectPort == 0 ||
   552  			listener.HealthyThreshold == 0 || listener.UnhealthyThreshold == 0 || listener.HealthCheckTimeout == 0 ||
   553  			listener.HealthCheckHttpCode == "" || listener.HealthCheckInterval == 0 {
   554  
   555  			errMsg := errors.New("err: HealthCheck empty.")
   556  			return listenType, &ListenerErr{HealthCheckErrType, errMsg}
   557  		}
   558  	}
   559  
   560  	if listener.StickySession == slb.OnFlag {
   561  		if listener.StickySessionType == "" {
   562  			errMsg := errors.New("err: stickySession empty.")
   563  			return listenType, &ListenerErr{StickySessionErrType, errMsg}
   564  		}
   565  
   566  		if listener.StickySessionType == slb.InsertStickySessionType {
   567  			if listener.CookieTimeout == 0 {
   568  				errMsg := errors.New("err: cookieTimeout empty.")
   569  				return listenType, &ListenerErr{CookieTimeOutErrType, errMsg}
   570  			}
   571  		} else if listener.StickySessionType == slb.ServerStickySessionType {
   572  			if listener.Cookie == "" {
   573  				errMsg := errors.New("err: cookie empty.")
   574  				return listenType, &ListenerErr{CookieErrType, errMsg}
   575  			}
   576  		}
   577  	}
   578  
   579  	httpListenertType := slb.HTTPListenerType{
   580  		LoadBalancerId:         loadBalancerId,
   581  		ListenerPort:           listener.LoadBalancerPort,
   582  		BackendServerPort:      listener.InstancePort,
   583  		Bandwidth:              listener.Bandwidth,
   584  		Scheduler:              listener.Scheduler,
   585  		HealthCheck:            listener.HealthCheck,
   586  		StickySession:          listener.StickySession,
   587  		StickySessionType:      listener.StickySessionType,
   588  		CookieTimeout:          listener.CookieTimeout,
   589  		Cookie:                 listener.Cookie,
   590  		HealthCheckDomain:      listener.HealthCheckDomain,
   591  		HealthCheckURI:         listener.HealthCheckURI,
   592  		HealthCheckConnectPort: listener.HealthCheckConnectPort,
   593  		HealthyThreshold:       listener.HealthyThreshold,
   594  		UnhealthyThreshold:     listener.UnhealthyThreshold,
   595  		HealthCheckTimeout:     listener.HealthCheckTimeout,
   596  		HealthCheckInterval:    listener.HealthCheckInterval,
   597  		HealthCheckHttpCode:    listener.HealthCheckHttpCode,
   598  	}
   599  
   600  	return httpListenertType, err
   601  }
   602  
   603  func getHttpListenerArgs(loadBalancerId string, listener *Listener) (listenType slb.CreateLoadBalancerHTTPListenerArgs, err error) {
   604  	httpListenerType, err := getHttpListenerType(loadBalancerId, listener)
   605  	if err != nil {
   606  		return listenType, err
   607  	}
   608  
   609  	httpArgs := slb.CreateLoadBalancerHTTPListenerArgs(httpListenerType)
   610  	return httpArgs, err
   611  }