/
create.go
109 lines (90 loc) · 2.97 KB
/
create.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
package tcnpazs
import (
"context"
"net"
"sort"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/giantswarm/ipam"
"github.com/giantswarm/microerror"
"github.com/giantswarm/aws-operator/v13/pkg/awstags"
"github.com/giantswarm/aws-operator/v13/service/controller/controllercontext"
"github.com/giantswarm/aws-operator/v13/service/controller/key"
)
func (r *Resource) EnsureCreated(ctx context.Context, obj interface{}) error {
cr, err := key.ToMachineDeployment(obj)
if err != nil {
return microerror.Mask(err)
}
cc, err := controllercontext.FromContext(ctx)
if err != nil {
return microerror.Mask(err)
}
// We need to cancel the resource early in case the ipam resource did not yet
// allocate a subnet for the node pool.
if key.MachineDeploymentSubnet(cr) == "" {
r.logger.Debugf(ctx, "cannot collect private subnets for availability zones")
r.logger.Debugf(ctx, "node pool subnet not yet allocated")
r.logger.Debugf(ctx, "canceling resource")
return nil
}
// Split the node pool subnet by the number of availability zones for further
// mapping below.
var subnets []net.IPNet
{
_, netip, err := net.ParseCIDR(key.MachineDeploymentSubnet(cr))
if err != nil {
return microerror.Mask(err)
}
subnets, err = ipam.Split(*netip, uint(len(key.MachineDeploymentAvailabilityZones(cr))))
if err != nil {
return microerror.Mask(err)
}
}
// Ensure a copy of the list of availability zones. This is absolutely
// critical for the mapping between availability zones and their split
// private subnets.
var azs []string
{
azs = append(azs, key.MachineDeploymentAvailabilityZones(cr)...)
sort.Strings(azs)
}
// Put the mapping between availability zones and their split subnets into the
// controller context spec in a deterministic way.
{
var list []controllercontext.ContextSpecTenantClusterTCNPAvailabilityZone
for i, az := range azs {
ng := natGatewayForAvailabilityZone(cc.Status.TenantCluster.TCCP.NATGateways, az)
if ng == nil {
r.logger.Debugf(ctx, "nat gateway information not available yet")
r.logger.Debugf(ctx, "canceling resource")
return nil
}
item := controllercontext.ContextSpecTenantClusterTCNPAvailabilityZone{
Name: az,
NATGateway: controllercontext.ContextSpecTenantClusterTCNPAvailabilityZoneNATGateway{
ID: *ng.NatGatewayId,
},
Subnet: controllercontext.ContextSpecTenantClusterTCNPAvailabilityZoneSubnet{
Private: controllercontext.ContextSpecTenantClusterTCNPAvailabilityZoneSubnetPrivate{
CIDR: subnets[i],
},
},
}
list = append(list, item)
}
cc.Spec.TenantCluster.TCNP.AvailabilityZones = list
}
return nil
}
func natGatewayForAvailabilityZone(natGateways []*ec2.NatGateway, availabilityZone string) *ec2.NatGateway {
for _, ng := range natGateways {
if awstags.ValueForKey(ng.Tags, key.TagStack) != key.StackTCCP {
continue
}
if awstags.ValueForKey(ng.Tags, key.TagAvailabilityZone) != availabilityZone {
continue
}
return ng
}
return nil
}