1
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
14 type LoadBalancerPortMapping struct {
15 Protocol uint32 `json:",omitempty"`
16 InternalPort uint16 `json:",omitempty"`
17 ExternalPort uint16 `json:",omitempty"`
18 DistributionType LoadBalancerDistribution `json:",omitempty"`
19 Flags LoadBalancerPortMappingFlags `json:",omitempty"`
20 }
21
22
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"`
31 }
32
33
34 type LoadBalancerFlags uint32
35
36 var (
37
38 LoadBalancerFlagsNone LoadBalancerFlags = 0
39
40 LoadBalancerFlagsDSR LoadBalancerFlags = 1
41 LoadBalancerFlagsIPv6 LoadBalancerFlags = 2
42 )
43
44
45 type LoadBalancerPortMappingFlags uint32
46
47 var (
48
49 LoadBalancerPortMappingFlagsNone LoadBalancerPortMappingFlags
50
51 LoadBalancerPortMappingFlagsILB LoadBalancerPortMappingFlags = 1
52
53 LoadBalancerPortMappingFlagsLocalRoutedVIP LoadBalancerPortMappingFlags = 2
54
55 LoadBalancerPortMappingFlagsUseMux LoadBalancerPortMappingFlags = 4
56
57 LoadBalancerPortMappingFlagsPreserveDIP LoadBalancerPortMappingFlags = 8
58 )
59
60
61 type LoadBalancerDistribution uint32
62
63 var (
64
65 LoadBalancerDistributionNone LoadBalancerDistribution
66
67 LoadBalancerDistributionSourceIPProtocol LoadBalancerDistribution = 1
68
69 LoadBalancerDistributionSourceIP LoadBalancerDistribution = 2
70 )
71
72 func getLoadBalancer(loadBalancerGUID guid.GUID, query string) (*HostComputeLoadBalancer, error) {
73
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
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
90 hr = hcnCloseLoadBalancer(loadBalancerHandle)
91 if err := checkForErrors("hcnCloseLoadBalancer", hr, nil); err != nil {
92 return nil, err
93 }
94
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
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
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
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
154 hr = hcnCloseLoadBalancer(loadBalancerHandle)
155 if err := checkForErrors("hcnCloseLoadBalancer", hr, nil); err != nil {
156 return nil, err
157 }
158
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
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
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
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
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
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
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
260 loadBalancer.HostComputeEndpoints = append(loadBalancer.HostComputeEndpoints, endpoint.Id)
261
262 return loadBalancer.Create()
263 }
264
265
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
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
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