...

Source file src/github.com/Microsoft/hcsshim/hcn/hcnloadbalancer.go

Documentation: github.com/Microsoft/hcsshim/hcn

     1  //go:build windows
     2  
     3  package hcn
     4  
     5  import (
     6  	"encoding/json"
     7  
     8  	"github.com/Microsoft/go-winio/pkg/guid"
     9  	"github.com/Microsoft/hcsshim/internal/interop"
    10  	"github.com/sirupsen/logrus"
    11  )
    12  
    13  // LoadBalancerPortMapping is associated with HostComputeLoadBalancer
    14  type LoadBalancerPortMapping struct {
    15  	Protocol         uint32                       `json:",omitempty"` // EX: TCP = 6, UDP = 17
    16  	InternalPort     uint16                       `json:",omitempty"`
    17  	ExternalPort     uint16                       `json:",omitempty"`
    18  	DistributionType LoadBalancerDistribution     `json:",omitempty"` // EX: Distribute per connection = 0, distribute traffic of the same protocol per client IP = 1, distribute per client IP = 2
    19  	Flags            LoadBalancerPortMappingFlags `json:",omitempty"`
    20  }
    21  
    22  // HostComputeLoadBalancer represents software load balancer.
    23  type HostComputeLoadBalancer struct {
    24  	Id                   string                    `json:"ID,omitempty"`
    25  	HostComputeEndpoints []string                  `json:",omitempty"`
    26  	SourceVIP            string                    `json:",omitempty"`
    27  	FrontendVIPs         []string                  `json:",omitempty"`
    28  	PortMappings         []LoadBalancerPortMapping `json:",omitempty"`
    29  	SchemaVersion        SchemaVersion             `json:",omitempty"`
    30  	Flags                LoadBalancerFlags         `json:",omitempty"` // 0: None, 1: EnableDirectServerReturn
    31  }
    32  
    33  // LoadBalancerFlags modify settings for a loadbalancer.
    34  type LoadBalancerFlags uint32
    35  
    36  var (
    37  	// LoadBalancerFlagsNone is the default.
    38  	LoadBalancerFlagsNone LoadBalancerFlags = 0
    39  	// LoadBalancerFlagsDSR enables Direct Server Return (DSR)
    40  	LoadBalancerFlagsDSR  LoadBalancerFlags = 1
    41  	LoadBalancerFlagsIPv6 LoadBalancerFlags = 2
    42  )
    43  
    44  // LoadBalancerPortMappingFlags are special settings on a loadbalancer.
    45  type LoadBalancerPortMappingFlags uint32
    46  
    47  var (
    48  	// LoadBalancerPortMappingFlagsNone is the default.
    49  	LoadBalancerPortMappingFlagsNone LoadBalancerPortMappingFlags
    50  	// LoadBalancerPortMappingFlagsILB enables internal loadbalancing.
    51  	LoadBalancerPortMappingFlagsILB LoadBalancerPortMappingFlags = 1
    52  	// LoadBalancerPortMappingFlagsLocalRoutedVIP enables VIP access from the host.
    53  	LoadBalancerPortMappingFlagsLocalRoutedVIP LoadBalancerPortMappingFlags = 2
    54  	// LoadBalancerPortMappingFlagsUseMux enables DSR for NodePort access of VIP.
    55  	LoadBalancerPortMappingFlagsUseMux LoadBalancerPortMappingFlags = 4
    56  	// LoadBalancerPortMappingFlagsPreserveDIP delivers packets with destination IP as the VIP.
    57  	LoadBalancerPortMappingFlagsPreserveDIP LoadBalancerPortMappingFlags = 8
    58  )
    59  
    60  // LoadBalancerDistribution specifies how the loadbalancer distributes traffic.
    61  type LoadBalancerDistribution uint32
    62  
    63  var (
    64  	// LoadBalancerDistributionNone is the default and loadbalances each connection to the same pod.
    65  	LoadBalancerDistributionNone LoadBalancerDistribution
    66  	// LoadBalancerDistributionSourceIPProtocol loadbalances all traffic of the same protocol from a client IP to the same pod.
    67  	LoadBalancerDistributionSourceIPProtocol LoadBalancerDistribution = 1
    68  	// LoadBalancerDistributionSourceIP loadbalances all traffic from a client IP to the same pod.
    69  	LoadBalancerDistributionSourceIP LoadBalancerDistribution = 2
    70  )
    71  
    72  func getLoadBalancer(loadBalancerGUID guid.GUID, query string) (*HostComputeLoadBalancer, error) {
    73  	// Open loadBalancer.
    74  	var (
    75  		loadBalancerHandle hcnLoadBalancer
    76  		resultBuffer       *uint16
    77  		propertiesBuffer   *uint16
    78  	)
    79  	hr := hcnOpenLoadBalancer(&loadBalancerGUID, &loadBalancerHandle, &resultBuffer)
    80  	if err := checkForErrors("hcnOpenLoadBalancer", hr, resultBuffer); err != nil {
    81  		return nil, err
    82  	}
    83  	// Query loadBalancer.
    84  	hr = hcnQueryLoadBalancerProperties(loadBalancerHandle, query, &propertiesBuffer, &resultBuffer)
    85  	if err := checkForErrors("hcnQueryLoadBalancerProperties", hr, resultBuffer); err != nil {
    86  		return nil, err
    87  	}
    88  	properties := interop.ConvertAndFreeCoTaskMemString(propertiesBuffer)
    89  	// Close loadBalancer.
    90  	hr = hcnCloseLoadBalancer(loadBalancerHandle)
    91  	if err := checkForErrors("hcnCloseLoadBalancer", hr, nil); err != nil {
    92  		return nil, err
    93  	}
    94  	// Convert output to HostComputeLoadBalancer
    95  	var outputLoadBalancer HostComputeLoadBalancer
    96  	if err := json.Unmarshal([]byte(properties), &outputLoadBalancer); err != nil {
    97  		return nil, err
    98  	}
    99  	return &outputLoadBalancer, nil
   100  }
   101  
   102  func enumerateLoadBalancers(query string) ([]HostComputeLoadBalancer, error) {
   103  	// Enumerate all LoadBalancer Guids
   104  	var (
   105  		resultBuffer       *uint16
   106  		loadBalancerBuffer *uint16
   107  	)
   108  	hr := hcnEnumerateLoadBalancers(query, &loadBalancerBuffer, &resultBuffer)
   109  	if err := checkForErrors("hcnEnumerateLoadBalancers", hr, resultBuffer); err != nil {
   110  		return nil, err
   111  	}
   112  
   113  	loadBalancers := interop.ConvertAndFreeCoTaskMemString(loadBalancerBuffer)
   114  	var loadBalancerIds []guid.GUID
   115  	if err := json.Unmarshal([]byte(loadBalancers), &loadBalancerIds); err != nil {
   116  		return nil, err
   117  	}
   118  
   119  	var outputLoadBalancers []HostComputeLoadBalancer
   120  	for _, loadBalancerGUID := range loadBalancerIds {
   121  		loadBalancer, err := getLoadBalancer(loadBalancerGUID, query)
   122  		if err != nil {
   123  			return nil, err
   124  		}
   125  		outputLoadBalancers = append(outputLoadBalancers, *loadBalancer)
   126  	}
   127  	return outputLoadBalancers, nil
   128  }
   129  
   130  func createLoadBalancer(settings string) (*HostComputeLoadBalancer, error) {
   131  	// Create new loadBalancer.
   132  	var (
   133  		loadBalancerHandle hcnLoadBalancer
   134  		resultBuffer       *uint16
   135  		propertiesBuffer   *uint16
   136  	)
   137  	loadBalancerGUID := guid.GUID{}
   138  	hr := hcnCreateLoadBalancer(&loadBalancerGUID, settings, &loadBalancerHandle, &resultBuffer)
   139  	if err := checkForErrors("hcnCreateLoadBalancer", hr, resultBuffer); err != nil {
   140  		return nil, err
   141  	}
   142  	// Query loadBalancer.
   143  	hcnQuery := defaultQuery()
   144  	query, err := json.Marshal(hcnQuery)
   145  	if err != nil {
   146  		return nil, err
   147  	}
   148  	hr = hcnQueryLoadBalancerProperties(loadBalancerHandle, string(query), &propertiesBuffer, &resultBuffer)
   149  	if err := checkForErrors("hcnQueryLoadBalancerProperties", hr, resultBuffer); err != nil {
   150  		return nil, err
   151  	}
   152  	properties := interop.ConvertAndFreeCoTaskMemString(propertiesBuffer)
   153  	// Close loadBalancer.
   154  	hr = hcnCloseLoadBalancer(loadBalancerHandle)
   155  	if err := checkForErrors("hcnCloseLoadBalancer", hr, nil); err != nil {
   156  		return nil, err
   157  	}
   158  	// Convert output to HostComputeLoadBalancer
   159  	var outputLoadBalancer HostComputeLoadBalancer
   160  	if err := json.Unmarshal([]byte(properties), &outputLoadBalancer); err != nil {
   161  		return nil, err
   162  	}
   163  	return &outputLoadBalancer, nil
   164  }
   165  
   166  func deleteLoadBalancer(loadBalancerID string) error {
   167  	loadBalancerGUID, err := guid.FromString(loadBalancerID)
   168  	if err != nil {
   169  		return errInvalidLoadBalancerID
   170  	}
   171  	var resultBuffer *uint16
   172  	hr := hcnDeleteLoadBalancer(&loadBalancerGUID, &resultBuffer)
   173  	if err := checkForErrors("hcnDeleteLoadBalancer", hr, resultBuffer); err != nil {
   174  		return err
   175  	}
   176  	return nil
   177  }
   178  
   179  // ListLoadBalancers makes a call to list all available loadBalancers.
   180  func ListLoadBalancers() ([]HostComputeLoadBalancer, error) {
   181  	hcnQuery := defaultQuery()
   182  	loadBalancers, err := ListLoadBalancersQuery(hcnQuery)
   183  	if err != nil {
   184  		return nil, err
   185  	}
   186  	return loadBalancers, nil
   187  }
   188  
   189  // ListLoadBalancersQuery makes a call to query the list of available loadBalancers.
   190  func ListLoadBalancersQuery(query HostComputeQuery) ([]HostComputeLoadBalancer, error) {
   191  	queryJSON, err := json.Marshal(query)
   192  	if err != nil {
   193  		return nil, err
   194  	}
   195  
   196  	loadBalancers, err := enumerateLoadBalancers(string(queryJSON))
   197  	if err != nil {
   198  		return nil, err
   199  	}
   200  	return loadBalancers, nil
   201  }
   202  
   203  // GetLoadBalancerByID returns the LoadBalancer specified by Id.
   204  func GetLoadBalancerByID(loadBalancerID string) (*HostComputeLoadBalancer, error) {
   205  	hcnQuery := defaultQuery()
   206  	mapA := map[string]string{"ID": loadBalancerID}
   207  	filter, err := json.Marshal(mapA)
   208  	if err != nil {
   209  		return nil, err
   210  	}
   211  	hcnQuery.Filter = string(filter)
   212  
   213  	loadBalancers, err := ListLoadBalancersQuery(hcnQuery)
   214  	if err != nil {
   215  		return nil, err
   216  	}
   217  	if len(loadBalancers) == 0 {
   218  		return nil, LoadBalancerNotFoundError{LoadBalancerId: loadBalancerID}
   219  	}
   220  	return &loadBalancers[0], err
   221  }
   222  
   223  // Create LoadBalancer.
   224  func (loadBalancer *HostComputeLoadBalancer) Create() (*HostComputeLoadBalancer, error) {
   225  	logrus.Debugf("hcn::HostComputeLoadBalancer::Create id=%s", loadBalancer.Id)
   226  
   227  	jsonString, err := json.Marshal(loadBalancer)
   228  	if err != nil {
   229  		return nil, err
   230  	}
   231  
   232  	logrus.Debugf("hcn::HostComputeLoadBalancer::Create JSON: %s", jsonString)
   233  	loadBalancer, hcnErr := createLoadBalancer(string(jsonString))
   234  	if hcnErr != nil {
   235  		return nil, hcnErr
   236  	}
   237  	return loadBalancer, nil
   238  }
   239  
   240  // Delete LoadBalancer.
   241  func (loadBalancer *HostComputeLoadBalancer) Delete() error {
   242  	logrus.Debugf("hcn::HostComputeLoadBalancer::Delete id=%s", loadBalancer.Id)
   243  
   244  	if err := deleteLoadBalancer(loadBalancer.Id); err != nil {
   245  		return err
   246  	}
   247  	return nil
   248  }
   249  
   250  // AddEndpoint add an endpoint to a LoadBalancer
   251  func (loadBalancer *HostComputeLoadBalancer) AddEndpoint(endpoint *HostComputeEndpoint) (*HostComputeLoadBalancer, error) {
   252  	logrus.Debugf("hcn::HostComputeLoadBalancer::AddEndpoint loadBalancer=%s endpoint=%s", loadBalancer.Id, endpoint.Id)
   253  
   254  	err := loadBalancer.Delete()
   255  	if err != nil {
   256  		return nil, err
   257  	}
   258  
   259  	// Add Endpoint to the Existing List
   260  	loadBalancer.HostComputeEndpoints = append(loadBalancer.HostComputeEndpoints, endpoint.Id)
   261  
   262  	return loadBalancer.Create()
   263  }
   264  
   265  // RemoveEndpoint removes an endpoint from a LoadBalancer
   266  func (loadBalancer *HostComputeLoadBalancer) RemoveEndpoint(endpoint *HostComputeEndpoint) (*HostComputeLoadBalancer, error) {
   267  	logrus.Debugf("hcn::HostComputeLoadBalancer::RemoveEndpoint loadBalancer=%s endpoint=%s", loadBalancer.Id, endpoint.Id)
   268  
   269  	err := loadBalancer.Delete()
   270  	if err != nil {
   271  		return nil, err
   272  	}
   273  
   274  	// Create a list of all the endpoints besides the one being removed
   275  	var endpoints []string
   276  	for _, endpointReference := range loadBalancer.HostComputeEndpoints {
   277  		if endpointReference == endpoint.Id {
   278  			continue
   279  		}
   280  		endpoints = append(endpoints, endpointReference)
   281  	}
   282  	loadBalancer.HostComputeEndpoints = endpoints
   283  	return loadBalancer.Create()
   284  }
   285  
   286  // AddLoadBalancer for the specified endpoints
   287  func AddLoadBalancer(endpoints []HostComputeEndpoint, flags LoadBalancerFlags, portMappingFlags LoadBalancerPortMappingFlags, sourceVIP string, frontendVIPs []string, protocol uint16, internalPort uint16, externalPort uint16) (*HostComputeLoadBalancer, error) {
   288  	logrus.Debugf("hcn::HostComputeLoadBalancer::AddLoadBalancer endpointId=%v, LoadBalancerFlags=%v, LoadBalancerPortMappingFlags=%v, sourceVIP=%s, frontendVIPs=%v, protocol=%v, internalPort=%v, externalPort=%v", endpoints, flags, portMappingFlags, sourceVIP, frontendVIPs, protocol, internalPort, externalPort)
   289  
   290  	loadBalancer := &HostComputeLoadBalancer{
   291  		SourceVIP: sourceVIP,
   292  		PortMappings: []LoadBalancerPortMapping{
   293  			{
   294  				Protocol:     uint32(protocol),
   295  				InternalPort: internalPort,
   296  				ExternalPort: externalPort,
   297  				Flags:        portMappingFlags,
   298  			},
   299  		},
   300  		FrontendVIPs: frontendVIPs,
   301  		SchemaVersion: SchemaVersion{
   302  			Major: 2,
   303  			Minor: 0,
   304  		},
   305  		Flags: flags,
   306  	}
   307  
   308  	for _, endpoint := range endpoints {
   309  		loadBalancer.HostComputeEndpoints = append(loadBalancer.HostComputeEndpoints, endpoint.Id)
   310  	}
   311  
   312  	return loadBalancer.Create()
   313  }
   314  

View as plain text