hcnloadbalancer.go 11 KB

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