hcnloadbalancer.go 11 KB

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