~abp998/gwacl/subscription

123.1.3 by Gavin Panella
Test the happy path of ListInstances.
1
// Copyright 2013 Canonical Ltd.  This software is licensed under the
2
// GNU Lesser General Public License version 3 (see the file COPYING).
3
4
package gwacl
5
153.2.13 by Gavin Panella
Demonstrate deleting VM disks.
6
import (
174.1.30 by Gavin Panella
Throw a wobbly when a virtual network already exists.
7
    "fmt"
153.2.13 by Gavin Panella
Demonstrate deleting VM disks.
8
    "sort"
163.2.1 by Raphael Badin
Add by-prefix filtering capacities to ListSpecificHostedServicesRequest.
9
    "strings"
153.2.13 by Gavin Panella
Demonstrate deleting VM disks.
10
)
11
128.1.2 by Gavin Panella
Switch to using a struct for arguments to ListInstances.
12
type ListInstancesRequest struct {
13
    ServiceName string
14
}
15
128.1.1 by Gavin Panella
Accept a serviceName parameter to ListInstances.
16
// ListInstances returns a slice of all instances for all deployments for the
128.1.4 by Gavin Panella
Update docstring.
17
// given hosted service name.
128.1.2 by Gavin Panella
Switch to using a struct for arguments to ListInstances.
18
func (api *ManagementAPI) ListInstances(request *ListInstancesRequest) ([]RoleInstance, error) {
128.1.1 by Gavin Panella
Accept a serviceName parameter to ListInstances.
19
    instances := []RoleInstance{}
128.1.2 by Gavin Panella
Switch to using a struct for arguments to ListInstances.
20
    properties, err := api.GetHostedServiceProperties(request.ServiceName, true)
123.1.3 by Gavin Panella
Test the happy path of ListInstances.
21
    if err != nil {
22
        return nil, err
23
    }
128.1.1 by Gavin Panella
Accept a serviceName parameter to ListInstances.
24
    for _, deployment := range properties.Deployments {
25
        instances = append(instances, deployment.RoleInstanceList...)
123.1.3 by Gavin Panella
Test the happy path of ListInstances.
26
    }
27
    return instances, nil
28
}
135.1.1 by Gavin Panella
New convenience function ListDeployments.
29
143.1.1 by Jeroen Vermeulen
Split off ListAllDeployments from ListDeployments, so that an empty slice of deployments no longer means 'all deployments'; in ListDeployments, use a map for the desired names to simplify lookup.
30
// ListAllDeploymentsRequest is a parameter object for ListAllDeployments.
31
type ListAllDeploymentsRequest struct {
32
    // ServiceName restricts the listing to the given service.
33
    ServiceName string
34
}
35
36
// ListAllDeployments returns a slice containing all deployments that match
37
// the request.
38
func (api *ManagementAPI) ListAllDeployments(request *ListAllDeploymentsRequest) ([]Deployment, error) {
39
    properties, err := api.GetHostedServiceProperties(request.ServiceName, true)
40
    if err != nil {
41
        return nil, err
42
    }
43
    return properties.Deployments, nil
44
}
45
46
// ListDeploymentsRequest is a parameter object for ListDeployments.
135.1.1 by Gavin Panella
New convenience function ListDeployments.
47
type ListDeploymentsRequest struct {
143.1.1 by Jeroen Vermeulen
Split off ListAllDeployments from ListDeployments, so that an empty slice of deployments no longer means 'all deployments'; in ListDeployments, use a map for the desired names to simplify lookup.
48
    // ServiceName restricts the listing to the given service.
49
    ServiceName string
50
    // DeploymentNames is a set (its value type is ignored) that restricts the
51
    // listing to those deployments which it contains.
143.1.2 by Jeroen Vermeulen
Use slice, not map, because it's slightly easier on the caller... Why doesn't Go have sets?
52
    DeploymentNames []string
135.1.1 by Gavin Panella
New convenience function ListDeployments.
53
}
54
143.1.1 by Jeroen Vermeulen
Split off ListAllDeployments from ListDeployments, so that an empty slice of deployments no longer means 'all deployments'; in ListDeployments, use a map for the desired names to simplify lookup.
55
// ListDeployments returns a slice containing specific deployments, insofar
56
// as they match the request.
135.1.1 by Gavin Panella
New convenience function ListDeployments.
57
func (api *ManagementAPI) ListDeployments(request *ListDeploymentsRequest) ([]Deployment, error) {
58
    properties, err := api.GetHostedServiceProperties(request.ServiceName, true)
59
    if err != nil {
60
        return nil, err
61
    }
135.1.2 by Gavin Panella
Permit filtering deployments by name.
62
    // Filter the deployment list according to the given names.
143.1.2 by Jeroen Vermeulen
Use slice, not map, because it's slightly easier on the caller... Why doesn't Go have sets?
63
    filter := make(map[string]bool)
64
    for _, name := range request.DeploymentNames {
65
        filter[name] = true
66
    }
135.1.2 by Gavin Panella
Permit filtering deployments by name.
67
    deployments := []Deployment{}
68
    for _, deployment := range properties.Deployments {
143.1.2 by Jeroen Vermeulen
Use slice, not map, because it's slightly easier on the caller... Why doesn't Go have sets?
69
        if _, ok := filter[deployment.Name]; ok {
143.1.1 by Jeroen Vermeulen
Split off ListAllDeployments from ListDeployments, so that an empty slice of deployments no longer means 'all deployments'; in ListDeployments, use a map for the desired names to simplify lookup.
70
            deployments = append(deployments, deployment)
135.1.2 by Gavin Panella
Permit filtering deployments by name.
71
        }
72
    }
73
    return deployments, nil
135.1.1 by Gavin Panella
New convenience function ListDeployments.
74
}
153.2.1 by Gavin Panella
DestroyDeployment WIP.
75
161.1.1 by Raphael Badin
Add ListSpecificHostedServices.
76
type ListSpecificHostedServicesRequest struct {
163.2.2 by Raphael Badin
Add tListPrefixedHostedServices.
77
    ServiceNames []string
161.1.1 by Raphael Badin
Add ListSpecificHostedServices.
78
}
79
80
// ListSpecificHostedServices returns a slice containing specific
81
// HostedServiceDescriptor objects, insofar as they match the request.
82
func (api *ManagementAPI) ListSpecificHostedServices(request *ListSpecificHostedServicesRequest) ([]HostedServiceDescriptor, error) {
163.2.2 by Raphael Badin
Add tListPrefixedHostedServices.
83
    allServices, err := api.ListHostedServices()
84
    if err != nil {
85
        return nil, err
86
    }
87
    // Filter the service list according to the given names.
88
    filter := make(map[string]bool)
89
    for _, name := range request.ServiceNames {
90
        filter[name] = true
91
    }
92
    services := []HostedServiceDescriptor{}
93
    for _, service := range allServices {
94
        if _, ok := filter[service.ServiceName]; ok {
95
            services = append(services, service)
96
        }
97
    }
98
    return services, nil
99
}
100
101
type ListPrefixedHostedServicesRequest struct {
102
    ServiceNamePrefix string
103
}
104
105
// ListPrefixedHostedServices returns a slice containing specific
106
// HostedServiceDescriptor objects, insofar as they match the request.
107
func (api *ManagementAPI) ListPrefixedHostedServices(request *ListPrefixedHostedServicesRequest) ([]HostedServiceDescriptor, error) {
163.2.1 by Raphael Badin
Add by-prefix filtering capacities to ListSpecificHostedServicesRequest.
108
    services, err := api.ListHostedServices()
161.1.1 by Raphael Badin
Add ListSpecificHostedServices.
109
    if err != nil {
110
        return nil, err
111
    }
163.2.3 by Raphael Badin
Review fixes.
112
    resServices := []HostedServiceDescriptor{}
113
    for _, service := range services {
114
        if strings.HasPrefix(service.ServiceName, request.ServiceNamePrefix) {
115
            resServices = append(resServices, service)
161.1.1 by Raphael Badin
Add ListSpecificHostedServices.
116
        }
117
    }
163.2.3 by Raphael Badin
Review fixes.
118
    services = resServices
161.1.1 by Raphael Badin
Add ListSpecificHostedServices.
119
    return services, nil
120
}
121
153.2.1 by Gavin Panella
DestroyDeployment WIP.
122
type DestroyDeploymentRequest struct {
123
    ServiceName    string
124
    DeploymentName string
125
}
126
127
// DestroyDeployment brings down all resources within a deployment - running
162.1.4 by Raphael Badin
Do not shutdown the VMs.
128
// instances, disks, etc. - and deletes the deployment itself.
153.2.1 by Gavin Panella
DestroyDeployment WIP.
129
func (api *ManagementAPI) DestroyDeployment(request *DestroyDeploymentRequest) error {
130
    deployment, err := api.GetDeployment(&GetDeploymentRequest{
131
        ServiceName:    request.ServiceName,
132
        DeploymentName: request.DeploymentName,
133
    })
134
    if err != nil {
153.2.17 by Gavin Panella
Succeed when deployment is not found.
135
        if IsNotFoundError(err) {
136
            return nil
137
        }
153.2.1 by Gavin Panella
DestroyDeployment WIP.
138
        return err
139
    }
162.1.4 by Raphael Badin
Do not shutdown the VMs.
140
    // 1. Get the list of the VM disks.
153.2.13 by Gavin Panella
Demonstrate deleting VM disks.
141
    diskNameMap := make(map[string]bool)
153.2.1 by Gavin Panella
DestroyDeployment WIP.
142
    for _, role := range deployment.RoleList {
143
        for _, osVHD := range role.OSVirtualHardDisk {
153.2.13 by Gavin Panella
Demonstrate deleting VM disks.
144
            diskNameMap[osVHD.DiskName] = true
153.2.1 by Gavin Panella
DestroyDeployment WIP.
145
        }
146
    }
162.1.4 by Raphael Badin
Do not shutdown the VMs.
147
    // 2. Delete deployment.  This will delete all the role instances inside
148
    // this deployment as a side effect.
149
    err = api.DeleteDeployment(request.ServiceName, request.DeploymentName)
150
    if err != nil && !IsNotFoundError(err) {
151
        return err
152
    }
153.2.13 by Gavin Panella
Demonstrate deleting VM disks.
153
    // Sort the disk names to aid testing.
154
    diskNames := []string{}
155
    for diskName := range diskNameMap {
156
        diskNames = append(diskNames, diskName)
157
    }
158
    sort.Strings(diskNames)
162.1.4 by Raphael Badin
Do not shutdown the VMs.
159
    // 3. Delete the disks.
153.2.13 by Gavin Panella
Demonstrate deleting VM disks.
160
    for _, diskName := range diskNames {
182.2.7 by Julian Edwards
Make DeleteDisk take a request struct param
161
        err = api.DeleteDisk(&DeleteDiskRequest{
162
            DiskName:   diskName,
220.1.1 by Andrew Wilkins
Delete OS disk blobs in DestroyDeployment
163
            DeleteBlob: true})
153.2.19 by Gavin Panella
Succeed when deployment assets are not found.
164
        if err != nil && !IsNotFoundError(err) {
153.2.1 by Gavin Panella
DestroyDeployment WIP.
165
            return err
166
        }
167
    }
168
    // Done.
169
    return nil
170
}
162.2.1 by Gavin Panella
Testing the happy path of DeleteHostedService.
171
172
type DestroyHostedServiceRequest struct {
173
    ServiceName string
174
}
175
176
// DestroyHostedService destroys all of the hosted service's contained
177
// deployments then deletes the hosted service itself.
178
func (api *ManagementAPI) DestroyHostedService(request *DestroyHostedServiceRequest) error {
179
    // 1. Get properties.
180
    properties, err := api.GetHostedServiceProperties(request.ServiceName, true)
181
    if err != nil {
182
        if IsNotFoundError(err) {
183
            return nil
184
        }
185
        return err
186
    }
187
    // 2. Delete deployments.
188
    for _, deployment := range properties.Deployments {
189
        err := api.DestroyDeployment(&DestroyDeploymentRequest{
190
            ServiceName:    request.ServiceName,
191
            DeploymentName: deployment.Name,
192
        })
162.2.7 by Gavin Panella
Remove debug logging, and format.
193
        if err != nil {
162.2.1 by Gavin Panella
Testing the happy path of DeleteHostedService.
194
            return err
195
        }
196
    }
197
    // 3. Delete service.
198
    err = api.DeleteHostedService(request.ServiceName)
199
    if err != nil && !IsNotFoundError(err) {
200
        return err
201
    }
202
    // Done.
203
    return nil
204
}
174.1.13 by Gavin Panella
Work in progress.
205
174.1.14 by Gavin Panella
Hook AddVirtualNetworkSite into the example.
206
func (api *ManagementAPI) AddVirtualNetworkSite(site *VirtualNetworkSite) error {
207
    // Obtain the current network config, which we will then modify.
174.1.13 by Gavin Panella
Work in progress.
208
    networkConfig, err := api.GetNetworkConfiguration()
209
    if err != nil {
210
        return err
211
    }
212
    if networkConfig == nil {
213
        // There's no config yet.
174.1.29 by Gavin Panella
Simplify AddVirtualNetworkSite (courtesy of jtv).
214
        networkConfig = &NetworkConfiguration{XMLNS: XMLNS_NC}
174.1.13 by Gavin Panella
Work in progress.
215
    }
174.1.15 by Gavin Panella
Add RemoveVirtualNetworkSite and hook it into the example.
216
    if networkConfig.VirtualNetworkSites == nil {
174.1.29 by Gavin Panella
Simplify AddVirtualNetworkSite (courtesy of jtv).
217
        networkConfig.VirtualNetworkSites = &[]VirtualNetworkSite{}
174.1.15 by Gavin Panella
Add RemoveVirtualNetworkSite and hook it into the example.
218
    }
174.1.13 by Gavin Panella
Work in progress.
219
    // Check to see if this network already exists.
174.1.14 by Gavin Panella
Hook AddVirtualNetworkSite into the example.
220
    for _, existingSite := range *networkConfig.VirtualNetworkSites {
221
        if existingSite.Name == site.Name {
174.1.13 by Gavin Panella
Work in progress.
222
            // Network already defined.
174.1.30 by Gavin Panella
Throw a wobbly when a virtual network already exists.
223
            return fmt.Errorf("could not add virtual network: %q already exists", site.Name)
174.1.13 by Gavin Panella
Work in progress.
224
        }
225
    }
174.1.14 by Gavin Panella
Hook AddVirtualNetworkSite into the example.
226
    // Add the network to the configuration.
174.1.29 by Gavin Panella
Simplify AddVirtualNetworkSite (courtesy of jtv).
227
    virtualNetworkSites := append(*networkConfig.VirtualNetworkSites, *site)
174.1.13 by Gavin Panella
Work in progress.
228
    networkConfig.VirtualNetworkSites = &virtualNetworkSites
174.1.14 by Gavin Panella
Hook AddVirtualNetworkSite into the example.
229
    // Put it back up to Azure. There's a race here...
230
    return api.SetNetworkConfiguration(networkConfig)
174.1.13 by Gavin Panella
Work in progress.
231
}
174.1.15 by Gavin Panella
Add RemoveVirtualNetworkSite and hook it into the example.
232
233
func (api *ManagementAPI) RemoveVirtualNetworkSite(siteName string) error {
234
    // Obtain the current network config, which we will then modify.
235
    networkConfig, err := api.GetNetworkConfiguration()
236
    if err != nil {
237
        return err
238
    }
239
    if networkConfig == nil || networkConfig.VirtualNetworkSites == nil {
240
        // There's no config, nothing to do.
241
        return nil
242
    }
243
    // Remove all references to the specified virtual network site name.
244
    virtualNetworkSites := []VirtualNetworkSite{}
245
    for _, existingSite := range *networkConfig.VirtualNetworkSites {
246
        if existingSite.Name != siteName {
247
            virtualNetworkSites = append(virtualNetworkSites, existingSite)
248
        }
249
    }
250
    if len(virtualNetworkSites) < len(*networkConfig.VirtualNetworkSites) {
251
        // Put it back up to Azure. There's a race here...
252
        networkConfig.VirtualNetworkSites = &virtualNetworkSites
253
        return api.SetNetworkConfiguration(networkConfig)
254
    }
255
    return nil
256
}
189.1.1 by Julian Edwards
first stab at an implementation of AddRoleEndpoints. Screw TDD.
257
211.1.1 by Raphael Badin
Add ListRoleEndpoints method.
258
type ListRoleEndpointsRequest struct {
259
    ServiceName    string
260
    DeploymentName string
261
    RoleName       string
262
}
263
264
// ListRoleEndpoints lists the open endpoints for the named service/deployment/role name.
265
func (api *ManagementAPI) ListRoleEndpoints(request *ListRoleEndpointsRequest) ([]InputEndpoint, error) {
266
    var err error
267
    vmRole, err := api.GetRole(&GetRoleRequest{
268
        ServiceName:    request.ServiceName,
269
        DeploymentName: request.DeploymentName,
270
        RoleName:       request.RoleName})
271
272
    if err != nil {
273
        return nil, err
274
    }
275
276
    for i, configSet := range vmRole.ConfigurationSets {
277
        if configSet.ConfigurationSetType == CONFIG_SET_NETWORK {
278
            endpointsP := vmRole.ConfigurationSets[i].InputEndpoints
279
            if endpointsP != nil {
280
                return *endpointsP, nil
281
            }
282
        }
283
    }
284
    return []InputEndpoint{}, nil
285
}
286
192.2.15 by Gavin Panella
Fix typo.
287
type AddRoleEndpointsRequest struct {
189.1.1 by Julian Edwards
first stab at an implementation of AddRoleEndpoints. Screw TDD.
288
    ServiceName    string
289
    DeploymentName string
290
    RoleName       string
189.1.2 by Julian Edwards
fix syntax
291
    InputEndpoints []InputEndpoint
189.1.1 by Julian Edwards
first stab at an implementation of AddRoleEndpoints. Screw TDD.
292
}
293
294
// AddRoleEndpoints appends the supplied endpoints to the existing endpoints
295
// for the named service/deployment/role name.  Note that the Azure API
296
// leaves this open to a race condition between fetching and updating the role.
192.2.15 by Gavin Panella
Fix typo.
297
func (api *ManagementAPI) AddRoleEndpoints(request *AddRoleEndpointsRequest) error {
189.1.1 by Julian Edwards
first stab at an implementation of AddRoleEndpoints. Screw TDD.
298
    var err error
189.1.2 by Julian Edwards
fix syntax
299
    vmRole, err := api.GetRole(&GetRoleRequest{
189.1.1 by Julian Edwards
first stab at an implementation of AddRoleEndpoints. Screw TDD.
300
        ServiceName:    request.ServiceName,
301
        DeploymentName: request.DeploymentName,
302
        RoleName:       request.RoleName})
303
304
    if err != nil {
305
        return err
306
    }
307
189.1.2 by Julian Edwards
fix syntax
308
    for i, configSet := range vmRole.ConfigurationSets {
189.1.11 by Julian Edwards
review comments
309
        // TODO: Is NetworkConfiguration always present?
192.2.4 by Gavin Panella
Switch to consts for LinuxProvisioningConfiguration and NetworkConfiguration.
310
        if configSet.ConfigurationSetType == CONFIG_SET_NETWORK {
189.1.6 by Julian Edwards
Complete test and fix implementation to handle tested case (and more, untested yet)
311
            endpointsP := vmRole.ConfigurationSets[i].InputEndpoints
312
            if endpointsP == nil {
189.1.11 by Julian Edwards
review comments
313
                // No endpoints set at all, initialise it to be empty.
314
                vmRole.ConfigurationSets[i].InputEndpoints = &[]InputEndpoint{}
189.1.6 by Julian Edwards
Complete test and fix implementation to handle tested case (and more, untested yet)
315
            }
189.1.11 by Julian Edwards
review comments
316
            // Append to existing endpoints.
317
            // TODO: Check clashing endpoint. LocalPort/Name/Port unique?
318
            endpoints := append(
319
                *vmRole.ConfigurationSets[i].InputEndpoints,
320
                request.InputEndpoints...)
321
            vmRole.ConfigurationSets[i].InputEndpoints = &endpoints
189.1.6 by Julian Edwards
Complete test and fix implementation to handle tested case (and more, untested yet)
322
323
            break // Only one NetworkConfiguration so exit loop now.
189.1.1 by Julian Edwards
first stab at an implementation of AddRoleEndpoints. Screw TDD.
324
        }
325
    }
326
327
    // Enjoy this race condition.
189.1.2 by Julian Edwards
fix syntax
328
    err = api.UpdateRole(&UpdateRoleRequest{
189.1.1 by Julian Edwards
first stab at an implementation of AddRoleEndpoints. Screw TDD.
329
        ServiceName:      request.ServiceName,
330
        DeploymentName:   request.DeploymentName,
331
        RoleName:         request.RoleName,
332
        PersistentVMRole: vmRole})
333
    if err != nil {
334
        return err
335
    }
336
    return nil
337
}
192.2.1 by Gavin Panella
New method RemoveRoleEndpoints.
338
192.2.13 by Gavin Panella
Fix typo.
339
// CompareInputEndpoints attempts to compare two InputEndpoint objects in a
340
// way that's congruent with how Windows's Azure considers them. The name is
192.2.16 by Gavin Panella
Improve doc for CompareInputEndpoints.
341
// always ignored, as is LoadBalancerProbe. When LoadBalancedEndpointSetName
342
// is set (not the empty string), all the fields - LocalPort, Port, Protocol,
343
// VIP and LoadBalancedEndpointSetName - are used for the comparison. When
344
// LoadBalancedEndpointSetName is the empty string, all except LocalPort -
345
// effectively Port, Protocol and VIP - are used for comparison.
192.2.5 by Gavin Panella
Break out comparison of InputEndpoints into a separate function.
346
func CompareInputEndpoints(a, b *InputEndpoint) bool {
347
    if a.LoadBalancedEndpointSetName == "" {
348
        return a.Port == b.Port && a.Protocol == b.Protocol && a.VIP == b.VIP
349
    } else {
350
        return (a.LoadBalancedEndpointSetName == b.LoadBalancedEndpointSetName &&
351
            a.LocalPort == b.LocalPort && a.Port == b.Port &&
352
            a.Protocol == b.Protocol && a.VIP == b.VIP)
353
    }
354
}
355
192.2.8 by Gavin Panella
Reorder.
356
type RemoveRoleEndpointsRequest struct {
357
    ServiceName    string
358
    DeploymentName string
359
    RoleName       string
360
    InputEndpoints []InputEndpoint
361
}
362
192.2.6 by Gavin Panella
Comment on RemoveRoleEndpoint.
363
// RemoveRoleEndpoints attempts to remove the given endpoints from the
364
// specified role. It uses `CompareInputEndpoints` to determine when there's a
365
// match between the given endpoint and one already configured.
192.2.3 by Gavin Panella
Fix typo.
366
func (api *ManagementAPI) RemoveRoleEndpoints(request *RemoveRoleEndpointsRequest) error {
192.2.10 by Gavin Panella
Don't make the role filtering function public yet.
367
    filterRequest := filterRoleEndpointsRequest{
192.2.7 by Gavin Panella
Redefine RemoveRoleEndpoints in terms of new method FilterRoleEndpoints.
368
        ServiceName:    request.ServiceName,
369
        DeploymentName: request.DeploymentName,
370
        RoleName:       request.RoleName,
192.2.11 by Gavin Panella
Simplify filter definition.
371
        Filter: func(a *InputEndpoint) bool {
372
            for _, b := range request.InputEndpoints {
373
                if CompareInputEndpoints(a, &b) {
192.2.7 by Gavin Panella
Redefine RemoveRoleEndpoints in terms of new method FilterRoleEndpoints.
374
                    return false
375
                }
376
            }
377
            return true
378
        },
379
    }
192.2.10 by Gavin Panella
Don't make the role filtering function public yet.
380
    return api.filterRoleEndpoints(&filterRequest)
192.2.7 by Gavin Panella
Redefine RemoveRoleEndpoints in terms of new method FilterRoleEndpoints.
381
}
382
192.2.9 by Gavin Panella
Document the filter function.
383
// Returns true to keep the endpoint defined in the role's configuration,
384
// false to remove it. It is also welcome to mutate endpoints; they are passed
385
// by reference.
192.2.10 by Gavin Panella
Don't make the role filtering function public yet.
386
type inputEndpointFilter func(*InputEndpoint) bool
192.2.9 by Gavin Panella
Document the filter function.
387
192.2.10 by Gavin Panella
Don't make the role filtering function public yet.
388
type filterRoleEndpointsRequest struct {
192.2.7 by Gavin Panella
Redefine RemoveRoleEndpoints in terms of new method FilterRoleEndpoints.
389
    ServiceName    string
390
    DeploymentName string
391
    RoleName       string
192.2.10 by Gavin Panella
Don't make the role filtering function public yet.
392
    Filter         inputEndpointFilter
192.2.7 by Gavin Panella
Redefine RemoveRoleEndpoints in terms of new method FilterRoleEndpoints.
393
}
394
192.2.12 by Gavin Panella
Explain why filterRoleEndpoints() is private.
395
// filterRoleEndpoints is a general role endpoint filtering function. It is
396
// private because it is only a support function for RemoveRoleEndpoints, and
397
// is not tested directly.
192.2.10 by Gavin Panella
Don't make the role filtering function public yet.
398
func (api *ManagementAPI) filterRoleEndpoints(request *filterRoleEndpointsRequest) error {
192.2.1 by Gavin Panella
New method RemoveRoleEndpoints.
399
    role, err := api.GetRole(&GetRoleRequest{
400
        ServiceName:    request.ServiceName,
401
        DeploymentName: request.DeploymentName,
402
        RoleName:       request.RoleName,
403
    })
404
    if err != nil {
405
        return err
406
    }
407
    for index, configSet := range role.ConfigurationSets {
192.2.4 by Gavin Panella
Switch to consts for LinuxProvisioningConfiguration and NetworkConfiguration.
408
        if configSet.ConfigurationSetType == CONFIG_SET_NETWORK {
192.2.1 by Gavin Panella
New method RemoveRoleEndpoints.
409
            if configSet.InputEndpoints != nil {
410
                endpoints := []InputEndpoint{}
411
                for _, existingEndpoint := range *configSet.InputEndpoints {
192.2.7 by Gavin Panella
Redefine RemoveRoleEndpoints in terms of new method FilterRoleEndpoints.
412
                    if request.Filter(&existingEndpoint) {
192.2.1 by Gavin Panella
New method RemoveRoleEndpoints.
413
                        endpoints = append(endpoints, existingEndpoint)
414
                    }
415
                }
416
                if len(endpoints) == 0 {
417
                    configSet.InputEndpoints = nil
418
                } else {
419
                    configSet.InputEndpoints = &endpoints
420
                }
421
            }
422
        }
423
        // Update the role; implicit copying is a nuisance.
424
        role.ConfigurationSets[index] = configSet
425
    }
426
    return api.UpdateRole(&UpdateRoleRequest{
427
        ServiceName:      request.ServiceName,
428
        DeploymentName:   request.DeploymentName,
429
        RoleName:         request.RoleName,
430
        PersistentVMRole: role,
431
    })
432
}