yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/openstack/loadbalancerlistener.go (about)

     1  // Copyright 2019 Yunion
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package openstack
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"net/url"
    21  	"strconv"
    22  	"time"
    23  
    24  	"github.com/coredns/coredns/plugin/pkg/log"
    25  
    26  	"yunion.io/x/jsonutils"
    27  	"yunion.io/x/pkg/errors"
    28  
    29  	api "yunion.io/x/cloudmux/pkg/apis/compute"
    30  	"yunion.io/x/cloudmux/pkg/cloudprovider"
    31  	"yunion.io/x/cloudmux/pkg/multicloud"
    32  )
    33  
    34  type SLoadbalancerListenerCreateParams struct {
    35  	Protocol                string         `json:"protocol,omitempty"`
    36  	Description             string         `json:"description,omitempty"`
    37  	AdminStateUp            bool           `json:"admin_state_up,omitempty"`
    38  	ConnectionLimit         *int           `json:"connection_limit,omitempty"`
    39  	ProtocolPort            string         `json:"protocol_port,omitempty"`
    40  	LoadbalancerID          string         `json:"loadbalancer_id,omitempty"`
    41  	DefaultPoolId           string         `json:"default_pool_id,omitempty"`
    42  	Name                    string         `json:"name,omitempty"`
    43  	InsertHeaders           SInsertHeaders `json:"insert_headers,omitempty"`
    44  	DefaultTLSContainerRef  string         `json:"default_tls_container_ref,omitempty"`
    45  	SniContainerRefs        []string       `json:"sni_container_refs,omitempty"`
    46  	TimeoutClientData       *int           `json:"timeout_client_data,omitempty"`
    47  	TimeoutMemberConnect    *int           `json:"timeout_member_connect,omitempty"`
    48  	TimeoutMemberData       *int           `json:"timeout_member_data,omitempty"`
    49  	TimeoutTCPInspect       *int           `json:"timeout_tcp_inspect,omitempty"`
    50  	Tags                    []string       `json:"tags,omitempty"`
    51  	ClientCaTLSContainerRef string         `json:"client_ca_tls_container_ref,omitempty"`
    52  	ClientAuthentication    string         `json:"client_authentication,omitempty"`
    53  	ClientCrlContainerRef   string         `json:"client_crl_container_ref,omitempty"`
    54  	AllowedCidrs            []string       `json:"allowed_cidrs,omitempty"`
    55  	TLSCiphers              string         `json:"tls_ciphers,omitempty"`
    56  	TLSVersions             []string       `json:"tls_versions,omitempty"`
    57  }
    58  
    59  type SLoadbalancerListenerUpdateParams struct {
    60  	Description             string         `json:"description,omitempty"`
    61  	AdminStateUp            bool           `json:"admin_state_up,omitempty"`
    62  	ConnectionLimit         *int           `json:"connection_limit,omitempty"`
    63  	DefaultPoolId           string         `json:"default_pool_id,omitempty"`
    64  	Name                    string         `json:"name,omitempty"`
    65  	InsertHeaders           SInsertHeaders `json:"insert_headers,omitempty"`
    66  	DefaultTLSContainerRef  string         `json:"default_tls_container_ref,omitempty"`
    67  	SniContainerRefs        []string       `json:"sni_container_refs,omitempty"`
    68  	TimeoutClientData       *int           `json:"timeout_client_data,omitempty"`
    69  	TimeoutMemberConnect    *int           `json:"timeout_member_connect,omitempty"`
    70  	TimeoutMemberData       *int           `json:"timeout_member_data,omitempty"`
    71  	TimeoutTCPInspect       *int           `json:"timeout_tcp_inspect,omitempty"`
    72  	Tags                    []string       `json:"tags,omitempty"`
    73  	ClientCaTLSContainerRef string         `json:"client_ca_tls_container_ref,omitempty"`
    74  	ClientAuthentication    string         `json:"client_authentication,omitempty"`
    75  	ClientCrlContainerRef   string         `json:"client_crl_container_ref,omitempty"`
    76  	AllowedCidrs            []string       `json:"allowed_cidrs,omitempty"`
    77  	TLSCiphers              string         `json:"tls_ciphers,omitempty"`
    78  	TLSVersions             []string       `json:"tls_versions,omitempty"`
    79  }
    80  
    81  type SInsertHeaders struct {
    82  	XForwardedPort string `json:"X-Forwarded-Port"`
    83  	XForwardedFor  string `json:"X-Forwarded-For"`
    84  }
    85  
    86  type SLoadbalancerListener struct {
    87  	multicloud.SResourceBase
    88  	multicloud.SLoadbalancerRedirectBase
    89  	OpenStackTags
    90  	region                  *SRegion
    91  	l7policies              []SLoadbalancerL7Policy
    92  	pools                   []SLoadbalancerPool
    93  	Description             string            `json:"description"`
    94  	AdminStateUp            bool              `json:"admin_state_up"`
    95  	ProjectID               string            `json:"project_id"`
    96  	Protocol                string            `json:"protocol"`
    97  	ProtocolPort            int               `json:"protocol_port"`
    98  	ProvisioningStatus      string            `json:"provisioning_status"`
    99  	DefaultTLSContainerRef  string            `json:"default_tls_container_ref"`
   100  	LoadbalancerIds         []SLoadbalancerID `json:"loadbalancers"`
   101  	InsertHeaders           SInsertHeaders    `json:"insert_headers"`
   102  	CreatedAt               string            `json:"created_at"`
   103  	UpdatedAt               string            `json:"updated_at"`
   104  	ID                      string            `json:"id"`
   105  	OperatingStatus         string            `json:"operating_status"`
   106  	DefaultPoolID           string            `json:"default_pool_id"`
   107  	SniContainerRefs        []string          `json:"sni_container_refs"`
   108  	L7PolicieIds            []SL7PolicieID    `json:"l7policies"`
   109  	Name                    string            `json:"name"`
   110  	TimeoutClientData       int               `json:"timeout_client_data"`
   111  	TimeoutMemberConnect    int               `json:"timeout_member_connect"`
   112  	TimeoutMemberData       int               `json:"timeout_member_data"`
   113  	TimeoutTCPInspect       int               `json:"timeout_tcp_inspect"`
   114  	Tags                    []string          `json:"tags"`
   115  	ClientCaTLSContainerRef string            `json:"client_ca_tls_container_ref"`
   116  	ClientAuthentication    string            `json:"client_authentication"`
   117  	ClientCrlContainerRef   string            `json:"client_crl_container_ref"`
   118  	AllowedCidrs            []string          `json:"allowed_cidrs"`
   119  	TLSCiphers              string            `json:"tls_ciphers"`
   120  	TLSVersions             []string          `json:"tls_versions"`
   121  }
   122  
   123  func (listener *SLoadbalancerListener) GetName() string {
   124  	if len(listener.Name) == 0 {
   125  		listener.Refresh()
   126  	}
   127  	if len(listener.Name) > 0 {
   128  		return listener.Name
   129  	}
   130  	return fmt.Sprintf("HTTP:%d", listener.ProtocolPort)
   131  }
   132  
   133  func (listener *SLoadbalancerListener) GetId() string {
   134  	return listener.ID
   135  }
   136  
   137  func (listener *SLoadbalancerListener) GetGlobalId() string {
   138  	return listener.GetId()
   139  }
   140  
   141  func (listener *SLoadbalancerListener) GetStatus() string {
   142  	switch listener.ProvisioningStatus {
   143  	case "ACTIVE":
   144  		return api.LB_STATUS_ENABLED
   145  	case "PENDING_CREATE":
   146  		return api.LB_CREATING
   147  	case "PENDING_UPDATE":
   148  		return api.LB_SYNC_CONF
   149  	case "PENDING_DELETE":
   150  		return api.LB_STATUS_DELETING
   151  	case "DELETED":
   152  		return api.LB_STATUS_DELETED
   153  	default:
   154  		return api.LB_STATUS_UNKNOWN
   155  	}
   156  }
   157  
   158  func (listener *SLoadbalancerListener) IsEmulated() bool {
   159  	return false
   160  }
   161  
   162  func (listener *SLoadbalancerListener) GetEgressMbps() int {
   163  
   164  	return 0
   165  }
   166  
   167  func (region *SRegion) GetLoadbalancerListeners() ([]SLoadbalancerListener, error) {
   168  	listeners := []SLoadbalancerListener{}
   169  	resource := "/v2/lbaas/listeners"
   170  	query := url.Values{}
   171  	for {
   172  		resp, err := region.lbList(resource, query)
   173  		if err != nil {
   174  			return nil, errors.Wrap(err, "lbList")
   175  		}
   176  		part := struct {
   177  			Listeners      []SLoadbalancerListener
   178  			ListenersLinks SNextLinks
   179  		}{}
   180  		err = resp.Unmarshal(&part)
   181  		if err != nil {
   182  			return nil, errors.Wrap(err, "resp.Unmarshal")
   183  		}
   184  		listeners = append(listeners, part.Listeners...)
   185  		marker := part.ListenersLinks.GetNextMark()
   186  		if len(marker) == 0 {
   187  			break
   188  		}
   189  		query.Set("marker", marker)
   190  	}
   191  
   192  	for i := 0; i < len(listeners); i++ {
   193  		listeners[i].region = region
   194  	}
   195  	for i := 0; i < len(listeners); i++ {
   196  		err := listeners[i].fetchLoadbalancerListenerL7Policies()
   197  		if err != nil {
   198  			return nil, errors.Wrap(err, "listener.fetchLoadbalancerListenerL7Policies()")
   199  		}
   200  	}
   201  
   202  	for i := 0; i < len(listeners); i++ {
   203  		err := listeners[i].fetchLoadbalancerPools()
   204  		if err != nil {
   205  			return nil, errors.Wrap(err, "listeners[i].fetchLoadbalancerPools()")
   206  		}
   207  	}
   208  
   209  	return listeners, nil
   210  }
   211  
   212  func (region *SRegion) GetLoadbalancerListenerbyId(listenerId string) (*SLoadbalancerListener, error) {
   213  	resp, err := region.lbGet(fmt.Sprintf("/v2/lbaas/listeners/%s", listenerId))
   214  	if err != nil {
   215  		return nil, errors.Wrapf(err, "region.Get(/v2/lbaas/listeners/%s)", listenerId)
   216  	}
   217  	listener := SLoadbalancerListener{}
   218  	err = resp.Unmarshal(&listener, "listener")
   219  	if err != nil {
   220  		return nil, errors.Wrap(err, "resp.Unmarshal(&listener, listener)")
   221  	}
   222  	listener.region = region
   223  	err = listener.fetchLoadbalancerListenerL7Policies()
   224  	if err != nil {
   225  		return nil, errors.Wrap(err, "listener.fetchLoadbalancerListenerL7Policies()")
   226  	}
   227  
   228  	err = listener.fetchLoadbalancerPools()
   229  	if err != nil {
   230  		return nil, errors.Wrap(err, "listeners[i].fetchLoadbalancerPools()")
   231  
   232  	}
   233  	return &listener, nil
   234  }
   235  
   236  func (region *SRegion) CreateLoadbalancerListener(loadbalancerId string, listenerParams *cloudprovider.SLoadbalancerListener) (*SLoadbalancerListener, error) {
   237  	type CreateParams struct {
   238  		Listener SLoadbalancerListenerCreateParams `json:"listener"`
   239  	}
   240  	params := CreateParams{}
   241  	params.Listener.AdminStateUp = true
   242  	params.Listener.LoadbalancerID = loadbalancerId
   243  	params.Listener.DefaultPoolId = listenerParams.BackendGroupID
   244  	params.Listener.Protocol = LB_PROTOCOL_MAP[listenerParams.ListenerType]
   245  	params.Listener.ProtocolPort = strconv.Itoa(listenerParams.ListenerPort)
   246  	if listenerParams.ClientIdleTimeout != 0 {
   247  		// 毫秒单位
   248  		msClientIdleTimeout := listenerParams.ClientIdleTimeout * 1000
   249  		params.Listener.TimeoutClientData = &msClientIdleTimeout
   250  	}
   251  	if listenerParams.BackendConnectTimeout != 0 {
   252  		msBackendConnectTimeout := listenerParams.BackendConnectTimeout * 1000
   253  		params.Listener.TimeoutMemberConnect = &msBackendConnectTimeout
   254  	}
   255  	if listenerParams.BackendIdleTimeout != 0 {
   256  		msBackendIdleTimeout := listenerParams.BackendIdleTimeout * 1000
   257  		params.Listener.TimeoutMemberData = &msBackendIdleTimeout
   258  	}
   259  
   260  	params.Listener.Name = listenerParams.Name
   261  	if listenerParams.XForwardedFor {
   262  		params.Listener.InsertHeaders.XForwardedFor = "true"
   263  	}
   264  	body, err := region.lbPost("/v2/lbaas/listeners", jsonutils.Marshal(params))
   265  	if err != nil {
   266  		return nil, errors.Wrap(err, "region.Post(/v2/lbaas/listeners)")
   267  	}
   268  	slistener := SLoadbalancerListener{}
   269  	slistener.region = region
   270  	return &slistener, body.Unmarshal(&slistener, "listener")
   271  }
   272  
   273  func (listener *SLoadbalancerListener) Refresh() error {
   274  	newlistener, err := listener.region.GetLoadbalancerListenerbyId(listener.ID)
   275  	if err != nil {
   276  		return errors.Wrapf(err, "listener.region.GetLoadbalancerListenerbyId(%s)", listener.ID)
   277  	}
   278  	return jsonutils.Update(listener, newlistener)
   279  }
   280  
   281  func (listener *SLoadbalancerListener) GetListenerType() string {
   282  	switch listener.Protocol {
   283  	case "HTTP":
   284  		return api.LB_LISTENER_TYPE_HTTP
   285  	case "HTTPS":
   286  		return api.LB_LISTENER_TYPE_HTTPS
   287  	case "TERMINATED_HTTPS":
   288  		return api.LB_LISTENER_TYPE_TERMINATED_HTTPS
   289  	case "TCP":
   290  		return api.LB_LISTENER_TYPE_TCP
   291  	case "UDP":
   292  		return api.LB_LISTENER_TYPE_UDP
   293  	default:
   294  		return ""
   295  	}
   296  }
   297  
   298  func (listener *SLoadbalancerListener) GetListenerPort() int {
   299  	return listener.ProtocolPort
   300  }
   301  
   302  func (listener *SLoadbalancerListener) GetBackendGroupId() string {
   303  	return listener.DefaultPoolID
   304  }
   305  
   306  func (listener *SLoadbalancerListener) GetBackendServerPort() int {
   307  	return listener.ProtocolPort
   308  }
   309  
   310  func (listener *SLoadbalancerListener) GetScheduler() string {
   311  	pool, err := listener.fetchFeaturePool()
   312  	if err != nil {
   313  		log.Errorf("GetScheduler():listener.fetchFeaturePool():%s", err)
   314  		return ""
   315  	}
   316  	switch pool.LbAlgorithm {
   317  	case "ROUND_ROBIN":
   318  		return api.LB_SCHEDULER_WRR
   319  	case "LEAST_CONNECTIONS":
   320  		return api.LB_SCHEDULER_WLC
   321  	case "SOURCE_IP":
   322  		return api.LB_SCHEDULER_SCH
   323  	case "SOURCE_IP_PORT":
   324  		return api.LB_SCHEDULER_TCH
   325  	default:
   326  		return ""
   327  	}
   328  }
   329  
   330  func (listener *SLoadbalancerListener) GetAclStatus() string {
   331  	if len(listener.AllowedCidrs) > 0 {
   332  		return api.LB_BOOL_ON
   333  	}
   334  	return api.LB_BOOL_OFF
   335  }
   336  
   337  func (listener *SLoadbalancerListener) GetAclType() string {
   338  	return api.LB_ACL_TYPE_WHITE
   339  }
   340  
   341  func (listener *SLoadbalancerListener) GetAclId() string {
   342  	return ""
   343  }
   344  
   345  func (listener *SLoadbalancerListener) GetHealthCheck() string {
   346  	pool, err := listener.fetchFeaturePool()
   347  	if err != nil {
   348  		log.Errorf("GetHealthCheck():listener.fetchFeaturePool():%s", err)
   349  		return ""
   350  	}
   351  	if pool.healthmonitor != nil {
   352  		return api.LB_BOOL_ON
   353  	}
   354  	return api.LB_BOOL_OFF
   355  
   356  }
   357  
   358  func (listener *SLoadbalancerListener) GetHealthCheckType() string {
   359  	pool, err := listener.fetchFeaturePool()
   360  	if err != nil {
   361  		log.Errorf("GetHealthCheckType():listener.fetchFeaturePool():%s", err)
   362  		return ""
   363  	}
   364  	if pool.healthmonitor == nil {
   365  		return ""
   366  	}
   367  	switch pool.healthmonitor.Type {
   368  	case "HTTP":
   369  		return api.LB_HEALTH_CHECK_HTTP
   370  	case "HTTPS":
   371  		return api.LB_HEALTH_CHECK_HTTPS
   372  	case "TCP":
   373  		return api.LB_HEALTH_CHECK_TCP
   374  	case "UDP-CONNECT":
   375  		return api.LB_HEALTH_CHECK_UDP
   376  	default:
   377  		return ""
   378  	}
   379  }
   380  
   381  func (listener *SLoadbalancerListener) GetHealthCheckDomain() string {
   382  	pool, err := listener.fetchFeaturePool()
   383  	if err != nil {
   384  		log.Errorf("GetHealthCheckDomain():listener.fetchFeaturePool():%s", err)
   385  		return ""
   386  	}
   387  	if pool.healthmonitor == nil {
   388  		return ""
   389  	}
   390  	return pool.healthmonitor.DomainName
   391  }
   392  
   393  func (listener *SLoadbalancerListener) GetHealthCheckURI() string {
   394  	pool, err := listener.fetchFeaturePool()
   395  	if err != nil {
   396  		log.Errorf("GetHealthCheckURI():listener.fetchFeaturePool():%s", err)
   397  		return ""
   398  	}
   399  	if pool.healthmonitor == nil {
   400  		return ""
   401  	}
   402  	return pool.healthmonitor.URLPath
   403  }
   404  
   405  func (listener *SLoadbalancerListener) GetHealthCheckCode() string {
   406  	pool, err := listener.fetchFeaturePool()
   407  	if err != nil {
   408  		log.Errorf("GetHealthCheckCode():listener.fetchFeaturePool():%s", err)
   409  		return ""
   410  	}
   411  	if pool.healthmonitor == nil {
   412  		return ""
   413  	}
   414  	return pool.healthmonitor.ExpectedCodes
   415  }
   416  
   417  func (listener *SLoadbalancerListener) GetHealthCheckRise() int {
   418  	pool, err := listener.fetchFeaturePool()
   419  	if err != nil {
   420  		log.Errorf("GetHealthCheckRise():listener.fetchFeaturePool():%s", err)
   421  		return 0
   422  	}
   423  	if pool.healthmonitor == nil {
   424  		return 0
   425  	}
   426  	return pool.healthmonitor.MaxRetries
   427  }
   428  
   429  func (listener *SLoadbalancerListener) GetHealthCheckFail() int {
   430  	pool, err := listener.fetchFeaturePool()
   431  	if err != nil {
   432  		log.Errorf("GetHealthCheckFail():listener.fetchFeaturePool():%s", err)
   433  		return 0
   434  	}
   435  	if pool.healthmonitor == nil {
   436  		return 0
   437  	}
   438  	return pool.healthmonitor.MaxRetriesDown
   439  }
   440  
   441  func (listener *SLoadbalancerListener) GetHealthCheckTimeout() int {
   442  	pool, err := listener.fetchFeaturePool()
   443  	if err != nil {
   444  		log.Errorf("GetHealthCheckTimeout():listener.fetchFeaturePool():%s", err)
   445  		return 0
   446  	}
   447  	if pool.healthmonitor == nil {
   448  		return 0
   449  	}
   450  	return pool.healthmonitor.Timeout
   451  }
   452  
   453  func (listener *SLoadbalancerListener) GetHealthCheckInterval() int {
   454  	pool, err := listener.fetchFeaturePool()
   455  	if err != nil {
   456  		log.Errorf("GetHealthCheckInterval():listener.fetchFeaturePool():%s", err)
   457  		return 0
   458  	}
   459  	if pool.healthmonitor == nil {
   460  		return 0
   461  	}
   462  	return pool.healthmonitor.Delay
   463  }
   464  
   465  func (listener *SLoadbalancerListener) GetHealthCheckReq() string {
   466  	return ""
   467  }
   468  
   469  func (listener *SLoadbalancerListener) GetHealthCheckExp() string {
   470  	return ""
   471  }
   472  
   473  func (listener *SLoadbalancerListener) GetStickySession() string {
   474  	pool, err := listener.fetchFeaturePool()
   475  	if err != nil {
   476  		log.Errorf("GetStickySession():listener.fetchFeaturePool():%s", err)
   477  		return api.LB_BOOL_OFF
   478  	}
   479  	stickySession, err := pool.GetStickySession()
   480  	if err != nil {
   481  		log.Errorf("GetStickySession():listener.fetchFeaturePool():%s", err)
   482  		return api.LB_BOOL_OFF
   483  	}
   484  	if stickySession == nil {
   485  		return ""
   486  	}
   487  	return stickySession.StickySession
   488  }
   489  
   490  func (listener *SLoadbalancerListener) GetStickySessionType() string {
   491  	pool, err := listener.fetchFeaturePool()
   492  	if err != nil {
   493  		log.Errorf("GetStickySession():listener.fetchFeaturePool():%s", err)
   494  		return ""
   495  	}
   496  	stickySession, err := pool.GetStickySession()
   497  	if err != nil {
   498  		log.Errorf("GetStickySession():listener.fetchFeaturePool():%s", err)
   499  		return ""
   500  	}
   501  	if stickySession == nil {
   502  		return ""
   503  	}
   504  	return stickySession.StickySessionType
   505  }
   506  
   507  func (listener *SLoadbalancerListener) GetStickySessionCookie() string {
   508  	pool, err := listener.fetchFeaturePool()
   509  	if err != nil {
   510  		log.Errorf("GetStickySession():listener.fetchFeaturePool():%s", err)
   511  		return ""
   512  	}
   513  	stickySession, err := pool.GetStickySession()
   514  	if err != nil {
   515  		log.Errorf("GetStickySession():listener.fetchFeaturePool():%s", err)
   516  		return ""
   517  	}
   518  	if stickySession == nil {
   519  		return ""
   520  	}
   521  	return stickySession.StickySessionCookie
   522  }
   523  
   524  func (listener *SLoadbalancerListener) GetStickySessionCookieTimeout() int {
   525  	pool, err := listener.fetchFeaturePool()
   526  	if err != nil {
   527  		log.Errorf("GetStickySession():listener.fetchFeaturePool():%s", err)
   528  		return 0
   529  	}
   530  	stickySession, err := pool.GetStickySession()
   531  	if err != nil {
   532  		log.Errorf("GetStickySession():listener.fetchFeaturePool():%s", err)
   533  		return 0
   534  	}
   535  	if stickySession == nil {
   536  		return 0
   537  	}
   538  	return stickySession.StickySessionCookieTimeout
   539  }
   540  
   541  func (listener *SLoadbalancerListener) XForwardedForEnabled() bool {
   542  	if listener.InsertHeaders.XForwardedFor == "true" {
   543  		return true
   544  	}
   545  	return false
   546  }
   547  
   548  func (listener *SLoadbalancerListener) GzipEnabled() bool {
   549  	return false
   550  }
   551  
   552  func (listener *SLoadbalancerListener) GetCertificateId() string {
   553  	return ""
   554  }
   555  
   556  func (listener *SLoadbalancerListener) GetTLSCipherPolicy() string {
   557  	return listener.TLSCiphers
   558  }
   559  
   560  func (listener *SLoadbalancerListener) HTTP2Enabled() bool {
   561  	return false
   562  }
   563  
   564  func (listener *SLoadbalancerListener) fetchLoadbalancerListenerL7Policies() error {
   565  	l7policies := []SLoadbalancerL7Policy{}
   566  	for i := 0; i < len(listener.L7PolicieIds); i++ {
   567  		l7policy, err := listener.region.GetLoadbalancerL7PolicybyId(listener.L7PolicieIds[i].ID)
   568  		if err != nil {
   569  			return errors.Wrapf(err, "listener.region.GetLoadbalancerL7PolicybyId(%s)", listener.L7PolicieIds[i].ID)
   570  		}
   571  		l7policies = append(l7policies, *l7policy)
   572  	}
   573  	listener.l7policies = l7policies
   574  	return nil
   575  }
   576  
   577  func (listener *SLoadbalancerListener) GetILoadbalancerListenerRules() ([]cloudprovider.ICloudLoadbalancerListenerRule, error) {
   578  	iRules := []cloudprovider.ICloudLoadbalancerListenerRule{}
   579  	for i := 0; i < len(listener.l7policies); i++ {
   580  		for j := 0; j < len(listener.l7policies[i].l7rules); j++ {
   581  			iRules = append(iRules, &listener.l7policies[i].l7rules[j])
   582  		}
   583  	}
   584  	return iRules, nil
   585  }
   586  
   587  func (region *SRegion) DeleteLoadbalancerListener(listenerId string) error {
   588  	_, err := region.lbDelete(fmt.Sprintf("/v2/lbaas/listeners/%s", listenerId))
   589  	if err != nil {
   590  		return errors.Wrapf(err, `region.lbDelete("/v2/lbaas/listeners/%s")`, listenerId)
   591  	}
   592  	return nil
   593  }
   594  
   595  func (listener *SLoadbalancerListener) Delete(ctx context.Context) error {
   596  	waitLbResStatus(listener, 10*time.Second, 1*time.Minute)
   597  	return listener.region.DeleteLoadbalancerListener(listener.ID)
   598  }
   599  
   600  func (listener *SLoadbalancerListener) CreateILoadBalancerListenerRule(rule *cloudprovider.SLoadbalancerListenerRule) (cloudprovider.ICloudLoadbalancerListenerRule, error) {
   601  	l7policy, err := listener.region.CreateLoadbalancerL7Policy(listener.ID, rule)
   602  	if err != nil {
   603  		return nil, errors.Wrapf(err, `listener.region.CreateLoadbalancerL7Policy(%s, rule)`, listener.ID)
   604  	}
   605  	// async wait
   606  	err = waitLbResStatus(l7policy, 10*time.Second, 8*time.Minute)
   607  	if err != nil {
   608  		return nil, errors.Wrap(err, `waitLbResStatus(l7policy, 10*time.Second, 8*time.Minute)`)
   609  	}
   610  
   611  	l7rule, err := listener.region.CreateLoadbalancerL7Rule(l7policy.ID, rule)
   612  	if err != nil {
   613  		return nil, errors.Wrapf(err, `listener.region.CreateLoadbalancerL7Rule(%s, rule)`, l7policy.ID)
   614  	}
   615  	l7rule.policy = l7policy
   616  	// async wait
   617  	err = waitLbResStatus(l7rule, 10*time.Second, 8*time.Minute)
   618  	if err != nil {
   619  		return nil, errors.Wrap(err, `waitLbResStatus(l7rule, 10*time.Second, 8*time.Minute)`)
   620  	}
   621  	return l7rule, nil
   622  }
   623  
   624  func (listener *SLoadbalancerListener) GetILoadBalancerListenerRuleById(ruleId string) (cloudprovider.ICloudLoadbalancerListenerRule, error) {
   625  	for i := 0; i < len(listener.l7policies); i++ {
   626  		for j := 0; j < len(listener.l7policies[i].l7rules); j++ {
   627  			if listener.l7policies[i].l7rules[j].GetId() == ruleId {
   628  				return &listener.l7policies[i].l7rules[j], nil
   629  			}
   630  		}
   631  	}
   632  	return nil, nil
   633  }
   634  
   635  func (listener *SLoadbalancerListener) fetchLoadbalancerPools() error {
   636  	pools := []SLoadbalancerPool{}
   637  	if len(listener.DefaultPoolID) > 0 {
   638  		defaultPool, err := listener.region.GetLoadbalancerPoolById(listener.DefaultPoolID)
   639  		if err != nil {
   640  			return errors.Wrapf(err, "listener.region.GetLoadbalancerPoolById(%s)", listener.DefaultPoolID)
   641  		}
   642  		pools = append(pools, *defaultPool)
   643  	}
   644  	for i := 0; i < len(listener.l7policies); i++ {
   645  		if len(listener.l7policies[i].RedirectPoolID) > 0 {
   646  			policyPool, err := listener.region.GetLoadbalancerPoolById(listener.l7policies[i].RedirectPoolID)
   647  			if err != nil {
   648  				return errors.Wrapf(err, "listener.region.GetLoadbalancerPoolById(%s)", listener.l7policies[i].RedirectPoolID)
   649  			}
   650  			pools = append(pools, *policyPool)
   651  		}
   652  	}
   653  	listener.pools = pools
   654  	return nil
   655  }
   656  
   657  func (listener *SLoadbalancerListener) fetchFeaturePool() (*SLoadbalancerPool, error) {
   658  	if len(listener.pools) < 1 {
   659  		return nil, fmt.Errorf("can't find pool with healthmonitor")
   660  	}
   661  	for i := 0; i < len(listener.pools); i++ {
   662  		if listener.pools[i].healthmonitor != nil {
   663  			return &listener.pools[i], nil
   664  		}
   665  	}
   666  	return &listener.pools[0], nil
   667  }
   668  
   669  func (region *SRegion) UpdateLoadBalancerListenerAdminStateUp(AdminStateUp bool, loadbalancerListenerId string) error {
   670  	params := jsonutils.NewDict()
   671  	poolParam := jsonutils.NewDict()
   672  	poolParam.Add(jsonutils.NewBool(AdminStateUp), "admin_state_up")
   673  	params.Add(poolParam, "listener")
   674  	_, err := region.lbUpdate(fmt.Sprintf("/v2/lbaas/listeners/%s", loadbalancerListenerId), params)
   675  	if err != nil {
   676  		return errors.Wrapf(err, `region.lbUpdate(/v2/lbaas/listeners/%s, params)`, loadbalancerListenerId)
   677  	}
   678  	return nil
   679  }
   680  
   681  func (region *SRegion) UpdateLoadBalancerListener(loadbalancerListenerId string, lblis *cloudprovider.SLoadbalancerListener) error {
   682  	type UpdateParams struct {
   683  		Listener SLoadbalancerListenerUpdateParams `json:"listener"`
   684  	}
   685  	params := UpdateParams{}
   686  	params.Listener.AdminStateUp = true
   687  	params.Listener.DefaultPoolId = lblis.BackendGroupID
   688  
   689  	if lblis.ClientIdleTimeout != 0 {
   690  		// 毫秒单位
   691  		msClientIdleTimeout := lblis.ClientIdleTimeout * 1000
   692  		params.Listener.TimeoutClientData = &msClientIdleTimeout
   693  	}
   694  	if lblis.BackendConnectTimeout != 0 {
   695  		msBackendConnectTimeout := lblis.BackendConnectTimeout * 1000
   696  		params.Listener.TimeoutMemberConnect = &msBackendConnectTimeout
   697  	}
   698  	if lblis.BackendIdleTimeout != 0 {
   699  		msBackendIdleTimeout := lblis.BackendIdleTimeout * 1000
   700  		params.Listener.TimeoutMemberData = &msBackendIdleTimeout
   701  	}
   702  	params.Listener.Name = lblis.Name
   703  	if lblis.XForwardedFor {
   704  		params.Listener.InsertHeaders.XForwardedFor = "true"
   705  	}
   706  	_, err := region.lbUpdate(fmt.Sprintf("/v2/lbaas/listeners/%s", loadbalancerListenerId), jsonutils.Marshal(params))
   707  	if err != nil {
   708  		return errors.Wrapf(err, `region.lbUpdate(/v2/lbaas/listeners/%s, jsonutils.Marshal(params))`, loadbalancerListenerId)
   709  	}
   710  	return nil
   711  }
   712  
   713  func (listener *SLoadbalancerListener) Start() error {
   714  	// ensure listener status
   715  	err := waitLbResStatus(listener, 10*time.Second, 8*time.Minute)
   716  	if err != nil {
   717  		return errors.Wrap(err, ` waitLbResStatus(listener, 10*time.Second, 8*time.Minute)`)
   718  	}
   719  	err = listener.region.UpdateLoadBalancerListenerAdminStateUp(true, listener.ID)
   720  	if err != nil {
   721  		return errors.Wrapf(err, `listener.region.UpdateLoadBalancerListenerAdminStateUp(true, %s)`, listener.ID)
   722  	}
   723  	err = waitLbResStatus(listener, 10*time.Second, 8*time.Minute)
   724  	if err != nil {
   725  		return errors.Wrap(err, `waitLbResStatus(listener, 10*time.Second, 8*time.Minute)`)
   726  	}
   727  	return nil
   728  }
   729  
   730  func (listener *SLoadbalancerListener) Stop() error {
   731  	// ensure listener status
   732  	err := waitLbResStatus(listener, 10*time.Second, 8*time.Minute)
   733  	if err != nil {
   734  		return errors.Wrap(err, ` waitLbResStatus(listener, 10*time.Second, 8*time.Minute)`)
   735  	}
   736  	err = listener.region.UpdateLoadBalancerListenerAdminStateUp(false, listener.ID)
   737  	if err != nil {
   738  		return errors.Wrapf(err, `listener.region.UpdateLoadBalancerListenerAdminStateUp(false,%s)`, listener.ID)
   739  	}
   740  	err = waitLbResStatus(listener, 10*time.Second, 8*time.Minute)
   741  	if err != nil {
   742  		return errors.Wrap(err, `waitLbResStatus(listener, 10*time.Second, 8*time.Minute)`)
   743  	}
   744  	return nil
   745  }
   746  
   747  func (listener *SLoadbalancerListener) Sync(ctx context.Context, lblis *cloudprovider.SLoadbalancerListener) error {
   748  	// ensure listener status
   749  	err := waitLbResStatus(listener, 10*time.Second, 8*time.Minute)
   750  	if err != nil {
   751  		return errors.Wrap(err, ` waitLbResStatus(listener, 10*time.Second, 8*time.Minute)`)
   752  	}
   753  	err = listener.region.UpdateLoadBalancerListener(listener.ID, lblis)
   754  	if err != nil {
   755  		return errors.Wrapf(err, `listener.region.UpdateLoadBalancerListener(%s, lblis)`, listener.ID)
   756  	}
   757  	err = waitLbResStatus(listener, 10*time.Second, 8*time.Minute)
   758  	if err != nil {
   759  		return errors.Wrap(err, `waitLbResStatus(listener, 10*time.Second, 8*time.Minute)`)
   760  	}
   761  	return nil
   762  }
   763  
   764  func (listener *SLoadbalancerListener) GetProjectId() string {
   765  	return listener.ProjectID
   766  }
   767  
   768  func (listener *SLoadbalancerListener) GetClientIdleTimeout() int {
   769  	return 0
   770  }
   771  
   772  func (listener *SLoadbalancerListener) GetBackendConnectTimeout() int {
   773  	return 0
   774  }