Skip to content

Commit ed70ecb

Browse files
authored
Merge pull request #424 from shapeblue/make-offering-configurable
Make network & VPC offering configurable
2 parents 49eea04 + 95f94eb commit ed70ecb

21 files changed

+381
-45
lines changed

api/v1beta3/cloudstackfailuredomain_types.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,13 @@ type Network struct {
6262
// +optional
6363
Netmask string `json:"netmask,omitempty"`
6464

65+
// Cloudstack Network Offering the cluster is built in.
66+
// Default is "DefaultIsolatedNetworkOfferingWithSourceNatService" for
67+
// isolated networks and "DefaultIsolatedNetworkOfferingForVpcNetworks"
68+
// for VPC networks.
69+
// +optional
70+
Offering string `json:"offering,omitempty"`
71+
6572
// Cloudstack VPC the network belongs to.
6673
// +optional
6774
VPC *VPC `json:"vpc,omitempty"`
@@ -79,6 +86,11 @@ type VPC struct {
7986
// CIDR for the VPC.
8087
// +optional
8188
CIDR string `json:"cidr,omitempty"`
89+
90+
// Cloudstack VPC Offering for the network.
91+
// Default is "Default VPC offering"
92+
// +optional
93+
Offering string `json:"offering,omitempty"`
8294
}
8395

8496
// CloudStackZoneSpec specifies a Zone's details.

api/v1beta3/cloudstackisolatednetwork_types.go

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,13 @@ type CloudStackIsolatedNetworkSpec struct {
4848
// +optional
4949
Netmask string `json:"netmask,omitempty"`
5050

51+
// Offering for the network.
52+
// Default is "DefaultIsolatedNetworkOfferingWithSourceNatService" for
53+
// isolated networks and "DefaultIsolatedNetworkOfferingForVpcNetworks"
54+
// for VPC networks.
55+
// +optional
56+
Offering string `json:"offering,omitempty"`
57+
5158
// VPC the network belongs to.
5259
// +optional
5360
VPC *VPC `json:"vpc,omitempty"`
@@ -67,12 +74,13 @@ type CloudStackIsolatedNetworkStatus struct {
6774

6875
func (n *CloudStackIsolatedNetwork) Network() *Network {
6976
return &Network{
70-
Name: n.Spec.Name,
71-
Type: "IsolatedNetwork",
72-
ID: n.Spec.ID,
73-
Gateway: n.Spec.Gateway,
74-
Netmask: n.Spec.Netmask,
75-
VPC: n.Spec.VPC,
77+
Name: n.Spec.Name,
78+
Type: "IsolatedNetwork",
79+
ID: n.Spec.ID,
80+
Gateway: n.Spec.Gateway,
81+
Netmask: n.Spec.Netmask,
82+
VPC: n.Spec.VPC,
83+
Offering: n.Spec.Offering,
7684
}
7785
}
7886

config/crd/bases/infrastructure.cluster.x-k8s.io_cloudstackclusters.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,12 @@ spec:
406406
description: Cloudstack Network Netmask the cluster
407407
is built in.
408408
type: string
409+
offering:
410+
description: Cloudstack Network Offering the cluster
411+
is built in. Default is "DefaultIsolatedNetworkOfferingWithSourceNatService"
412+
for isolated networks and "DefaultIsolatedNetworkOfferingForVpcNetworks"
413+
for VPC networks.
414+
type: string
409415
type:
410416
description: Cloudstack Network Type the cluster is
411417
built in.
@@ -422,6 +428,10 @@ spec:
422428
name:
423429
description: Cloudstack VPC Name of the network.
424430
type: string
431+
offering:
432+
description: Cloudstack VPC Offering for the network.
433+
Default is "Default VPC offering"
434+
type: string
425435
type: object
426436
required:
427437
- name

config/crd/bases/infrastructure.cluster.x-k8s.io_cloudstackfailuredomains.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,12 @@ spec:
183183
description: Cloudstack Network Netmask the cluster is built
184184
in.
185185
type: string
186+
offering:
187+
description: Cloudstack Network Offering the cluster is built
188+
in. Default is "DefaultIsolatedNetworkOfferingWithSourceNatService"
189+
for isolated networks and "DefaultIsolatedNetworkOfferingForVpcNetworks"
190+
for VPC networks.
191+
type: string
186192
type:
187193
description: Cloudstack Network Type the cluster is built
188194
in.
@@ -199,6 +205,10 @@ spec:
199205
name:
200206
description: Cloudstack VPC Name of the network.
201207
type: string
208+
offering:
209+
description: Cloudstack VPC Offering for the network.
210+
Default is "Default VPC offering"
211+
type: string
202212
type: object
203213
required:
204214
- name

config/crd/bases/infrastructure.cluster.x-k8s.io_cloudstackisolatednetworks.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,11 @@ spec:
203203
netmask:
204204
description: Netmask for the network.
205205
type: string
206+
offering:
207+
description: Offering for the network. Default is "DefaultIsolatedNetworkOfferingWithSourceNatService"
208+
for isolated networks and "DefaultIsolatedNetworkOfferingForVpcNetworks"
209+
for VPC networks.
210+
type: string
206211
vpc:
207212
description: VPC the network belongs to.
208213
properties:
@@ -215,6 +220,10 @@ spec:
215220
name:
216221
description: Cloudstack VPC Name of the network.
217222
type: string
223+
offering:
224+
description: Cloudstack VPC Offering for the network. Default
225+
is "Default VPC offering"
226+
type: string
218227
type: object
219228
required:
220229
- controlPlaneEndpoint

controllers/utils/isolated_network.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ func (r *ReconciliationRunner) GenerateIsolatedNetwork(name string, fdNameFunc f
4545
csIsoNet.Spec.ControlPlaneEndpoint.Port = r.CSCluster.Spec.ControlPlaneEndpoint.Port
4646
csIsoNet.Spec.Gateway = network.Gateway
4747
csIsoNet.Spec.Netmask = network.Netmask
48+
csIsoNet.Spec.Offering = network.Offering
4849

4950
if network.VPC != nil {
5051
csIsoNet.Spec.VPC = network.VPC

pkg/cloud/isolated_network.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,10 @@ func (c *client) CreateIsolatedNetwork(fd *infrav1.CloudStackFailureDomain, isoN
112112
offeringName = NetVPCOffering
113113
}
114114

115+
if isoNet.Spec.Offering != "" {
116+
offeringName = isoNet.Spec.Offering
117+
}
118+
115119
// Get network offering ID.
116120
offeringID, err := c.getOfferingID(offeringName)
117121
if err != nil {
@@ -153,6 +157,19 @@ func (c *client) OpenFirewallRules(isoNet *infrav1.CloudStackIsolatedNetwork) (r
153157
if isoNet.Spec.VPC != nil && isoNet.Spec.VPC.ID != "" {
154158
return nil
155159
}
160+
161+
// If network's egress policy is true, then we don't need to open the firewall rules for all protocols
162+
network, count, err := c.cs.Network.GetNetworkByID(isoNet.Spec.ID, cloudstack.WithProject(c.user.Project.ID))
163+
if err != nil {
164+
return errors.Wrapf(err, "failed to get network by ID %s", isoNet.Spec.ID)
165+
}
166+
if count == 0 {
167+
return errors.Errorf("no network found with ID %s", isoNet.Spec.ID)
168+
}
169+
if network.Egressdefaultpolicy {
170+
return nil
171+
}
172+
156173
protocols := []string{NetworkProtocolTCP, NetworkProtocolUDP, NetworkProtocolICMP}
157174
for _, proto := range protocols {
158175
p := c.cs.Firewall.NewCreateEgressFirewallRuleParams(isoNet.Spec.ID, proto)

pkg/cloud/isolated_network_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ var _ = ginkgo.Describe("Network", func() {
8484
PublicIpAddresses: []*csapi.PublicIpAddress{{Id: dummies.PublicIPID, Ipaddress: "fakeIP"}}}, nil)
8585
as.EXPECT().NewAssociateIpAddressParams().Return(&csapi.AssociateIpAddressParams{})
8686
as.EXPECT().AssociateIpAddress(gomock.Any())
87+
ns.EXPECT().GetNetworkByID(dummies.ISONet1.ID, gomock.Any()).Return(&csapi.Network{Egressdefaultpolicy: false}, 1, nil)
8788
fs.EXPECT().NewCreateEgressFirewallRuleParams(dummies.ISONet1.ID, gomock.Any()).
8889
DoAndReturn(func(_ string, protocol string) *csapi.CreateEgressFirewallRuleParams {
8990
p := &csapi.CreateEgressFirewallRuleParams{}
@@ -138,6 +139,7 @@ var _ = ginkgo.Describe("Network", func() {
138139
ginkgo.Context("for a closed firewall", func() {
139140
ginkgo.It("OpenFirewallRule asks CloudStack to open the firewall", func() {
140141
dummies.Zone1.Network = dummies.ISONet1
142+
ns.EXPECT().GetNetworkByID(dummies.ISONet1.ID, gomock.Any()).Return(&csapi.Network{Egressdefaultpolicy: false}, 1, nil)
141143
fs.EXPECT().NewCreateEgressFirewallRuleParams(dummies.ISONet1.ID, gomock.Any()).
142144
DoAndReturn(func(_ string, protocol string) *csapi.CreateEgressFirewallRuleParams {
143145
p := &csapi.CreateEgressFirewallRuleParams{}
@@ -165,6 +167,7 @@ var _ = ginkgo.Describe("Network", func() {
165167
ginkgo.It("OpenFirewallRule asks CloudStack to open the firewall anyway, but doesn't fail", func() {
166168
dummies.Zone1.Network = dummies.ISONet1
167169

170+
ns.EXPECT().GetNetworkByID(dummies.ISONet1.ID, gomock.Any()).Return(&csapi.Network{Egressdefaultpolicy: false}, 1, nil)
168171
fs.EXPECT().NewCreateEgressFirewallRuleParams(dummies.ISONet1.ID, gomock.Any()).
169172
DoAndReturn(func(_ string, protocol string) *csapi.CreateEgressFirewallRuleParams {
170173
p := &csapi.CreateEgressFirewallRuleParams{}

pkg/cloud/network.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ func (c *client) ResolveNetwork(net *infrav1.Network) (retErr error) {
6565
net.Type = netDetails.Type
6666
net.Gateway = netDetails.Gateway
6767
net.Netmask = netDetails.Netmask
68+
net.Offering = netDetails.Networkofferingname
6869
if netDetails.Vpcid != "" {
6970
if net.VPC == nil {
7071
net.VPC = &infrav1.VPC{}
@@ -88,6 +89,7 @@ func (c *client) ResolveNetwork(net *infrav1.Network) (retErr error) {
8889
net.Type = netDetails.Type
8990
net.Gateway = netDetails.Gateway
9091
net.Netmask = netDetails.Netmask
92+
net.Offering = netDetails.Networkofferingname
9193
if netDetails.Vpcid != "" {
9294
if net.VPC == nil {
9395
net.VPC = &infrav1.VPC{}

pkg/cloud/vpc.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ type VPCIface interface {
4040
}
4141

4242
// getVPCOfferingID fetches a vpc offering id.
43-
func (c *client) getVPCOfferingID() (string, error) {
44-
offeringID, count, retErr := c.cs.VPC.GetVPCOfferingID(VPCOffering)
43+
func (c *client) getVPCOfferingID(offeringName string) (string, error) {
44+
offeringID, count, retErr := c.cs.VPC.GetVPCOfferingID(offeringName)
4545
if retErr != nil {
4646
c.customMetrics.EvaluateErrorAndIncrementAcsReconciliationErrorCounter(retErr)
4747
return "", retErr
@@ -70,6 +70,7 @@ func (c *client) ResolveVPC(vpc *infrav1.VPC) error {
7070
}
7171
vpc.Name = resp.Name
7272
vpc.CIDR = resp.Cidr
73+
vpc.Offering = resp.Vpcofferingname
7374
return nil
7475
}
7576

@@ -84,6 +85,7 @@ func (c *client) ResolveVPC(vpc *infrav1.VPC) error {
8485
}
8586
vpc.ID = resp.Id
8687
vpc.CIDR = resp.Cidr
88+
vpc.Offering = resp.Vpcofferingname
8789
return nil
8890
}
8991

@@ -93,7 +95,12 @@ func (c *client) CreateVPC(fd *infrav1.CloudStackFailureDomain, vpc *infrav1.VPC
9395
return errors.New("VPC name must be specified")
9496
}
9597

96-
offeringID, err := c.getVPCOfferingID()
98+
offeringName := VPCOffering
99+
if vpc.Offering != "" {
100+
offeringName = vpc.Offering
101+
}
102+
103+
offeringID, err := c.getVPCOfferingID(offeringName)
97104
if err != nil {
98105
return err
99106
}

test/e2e/common.go

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,25 @@ const (
6262
InvalidDomainName = "CLOUDSTACK_INVALID_DOMAIN_NAME"
6363
InvalidTemplateName = "CLOUDSTACK_INVALID_TEMPLATE_NAME"
6464
InvalidCPOfferingName = "CLOUDSTACK_INVALID_CONTROL_PLANE_MACHINE_OFFERING"
65+
66+
CustomNetworkOfferingWithEgressPolicyName = "CLOUDSTACK_NETWORK_CUSTOM_OFFERING_EGRESS_POLICY_TRUE_NAME"
67+
NetworkNameWithCustomOffering = "CLOUDSTACK_NETWORK_NAME_WITH_CUSTOM_OFFERING"
68+
69+
VPCName = "CLOUDSTACK_VPC_NAME"
70+
VPCNetworkName = "CLOUDSTACK_VPC_NETWORK_NAME"
71+
CustomVPCOfferingName = "CLOUDSTACK_CUSTOM_VPC_OFFERING_NAME"
72+
CustomVPCNetworkOfferingName = "CLOUDSTACK_CUSTOM_VPC_NETWORK_OFFERING_NAME"
73+
VPCWithCustomOfferingName = "CLOUDSTACK_VPC_NAME_WITH_CUSTOM_OFFERING"
74+
VPCNetworkWithCustomOfferingName = "CLOUDSTACK_VPC_NETWORK_NAME_WITH_CUSTOM_OFFERING"
6575
)
6676

6777
const (
6878
ControlPlaneIndicator = "-control-plane-"
6979
MachineDeploymentIndicator = "-md-"
7080
DataVolumePrefix = "DATA-"
81+
DefaultVPCOffering = "Default VPC offering"
82+
DefaultVPCNetworkOffering = "DefaultIsolatedNetworkOfferingForVpcNetworks"
83+
DefaultNetworkOffering = "DefaultIsolatedNetworkOfferingWithSourceNatService"
7184
)
7285

7386
type CommonSpecInput struct {
@@ -391,15 +404,11 @@ func CheckNetworkExists(client *cloudstack.CloudStackClient, networkName string)
391404
}
392405
return false, err
393406
} else if count > 1 {
394-
return false, fmt.Errorf("Expected 0-1 Network with name %s, but got %d.", networkName, count)
407+
return false, fmt.Errorf("expected 0-1 network with name %s, but got %d", networkName, count)
395408
}
396409
return count == 1, nil
397410
}
398411

399-
func CheckVPCExists(client *cloudstack.CloudStackClient, vpcName string) (bool, error) {
400-
return CheckVPCExistsInProject(client, vpcName, "")
401-
}
402-
403412
func CheckVPCExistsInProject(client *cloudstack.CloudStackClient, vpcName string, project string) (bool, error) {
404413
p := client.VPC.NewListVPCsParams()
405414
p.SetName(vpcName)
@@ -419,7 +428,7 @@ func CheckVPCExistsInProject(client *cloudstack.CloudStackClient, vpcName string
419428
}
420429
return false, err
421430
} else if listResp.Count > 1 {
422-
return false, fmt.Errorf("Expected 0-1 VPC with name %s, but got %d.", vpcName, listResp.Count)
431+
return false, fmt.Errorf("expected 0-1 vpc with name %s, but got %d", vpcName, listResp.Count)
423432
}
424433
return listResp.Count == 1, nil
425434
}

test/e2e/config/cloudstack.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ providers:
8989
- sourcePath: "../data/infrastructure-cloudstack/v1beta3/cluster-template-second-cluster.yaml"
9090
- sourcePath: "../data/infrastructure-cloudstack/v1beta3/cluster-template-shared-network-kubevip.yaml"
9191
- sourcePath: "../data/infrastructure-cloudstack/v1beta3/cluster-template-vpc-network.yaml"
92+
- sourcePath: "../data/infrastructure-cloudstack/v1beta3/cluster-template-custom-vpc-offering.yaml"
93+
- sourcePath: "../data/infrastructure-cloudstack/v1beta3/cluster-template-network-with-custom-offering.yaml"
9294
- sourcePath: "../data/infrastructure-cloudstack/v1beta3/cluster-template-invalid-disk-offering.yaml"
9395
- sourcePath: "../data/infrastructure-cloudstack/v1beta3/cluster-template-invalid-disk-offering-size-for-non-customized.yaml"
9496
- sourcePath: "../data/infrastructure-cloudstack/v1beta3/cluster-template-invalid-disk-offering-size-for-customized.yaml"
@@ -129,10 +131,20 @@ variables:
129131
CLOUDSTACK_INVALID_ACCOUNT_NAME: accountXXXX
130132
CLOUDSTACK_DOMAIN_NAME: ROOT
131133
CLOUDSTACK_INVALID_DOMAIN_NAME: domainXXXX
134+
132135
CLOUDSTACK_NETWORK_NAME: isolated-for-e2e-1
136+
CLOUDSTACK_NETWORK_NAME_WITH_CUSTOM_OFFERING: isolated-for-e2e-1-with-custom-offering
137+
CLOUDSTACK_NETWORK_CUSTOM_OFFERING_EGRESS_POLICY_TRUE_NAME: CustomNetworkOfferingWithEgressPolicyTrue
138+
133139
CLOUDSTACK_VPC_NETWORK_NAME: vpc-isolated-for-e2e-1
134140
CLOUDSTACK_VPC_NAME: vpc-for-e2e-1
135141
CLOUDSTACK_VPC_CIDR: 10.10.0.0/16
142+
143+
CLOUDSTACK_VPC_NAME_WITH_CUSTOM_OFFERING: vpc-for-e2e-1-with-custom-offering
144+
CLOUDSTACK_VPC_NETWORK_NAME_WITH_CUSTOM_OFFERING: vpc-isolated-for-e2e-1-with-custom-offering
145+
CLOUDSTACK_CUSTOM_VPC_OFFERING_NAME: "CustomVPCOffering"
146+
CLOUDSTACK_CUSTOM_VPC_NETWORK_OFFERING_NAME: "CustomVPCNetworkOffering"
147+
136148
CLOUDSTACK_GATEWAY: 10.10.0.1
137149
CLOUDSTACK_NETMASK: 255.255.255.0
138150
CLOUDSTACK_NEW_NETWORK_NAME: isolated-for-e2e-new
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
---
2+
apiVersion: infrastructure.cluster.x-k8s.io/v1beta3
3+
kind: CloudStackCluster
4+
metadata:
5+
name: ${CLUSTER_NAME}
6+
spec:
7+
failureDomains:
8+
- name: ${CLOUDSTACK_FD1_NAME}
9+
acsEndpoint:
10+
name: ${CLOUDSTACK_FD1_SECRET_NAME}
11+
namespace: default
12+
zone:
13+
name: ${CLOUDSTACK_ZONE_NAME}
14+
network:
15+
name: ${CLOUDSTACK_VPC_NETWORK_NAME_WITH_CUSTOM_OFFERING}
16+
gateway: ${CLOUDSTACK_GATEWAY}
17+
netmask: ${CLOUDSTACK_NETMASK}
18+
offering: ${CLOUDSTACK_CUSTOM_VPC_NETWORK_OFFERING_NAME}
19+
vpc:
20+
name: ${CLOUDSTACK_VPC_NAME_WITH_CUSTOM_OFFERING}
21+
cidr: ${CLOUDSTACK_VPC_CIDR}
22+
offering: ${CLOUDSTACK_CUSTOM_VPC_OFFERING_NAME}
23+
controlPlaneEndpoint:
24+
host: ""
25+
port: 6443
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
bases:
2+
- ../bases/cluster-with-kcp.yaml
3+
- ../bases/md.yaml
4+
5+
patchesStrategicMerge:
6+
- ./cluster-with-custom-vpc-offering.yaml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
---
2+
apiVersion: infrastructure.cluster.x-k8s.io/v1beta3
3+
kind: CloudStackCluster
4+
metadata:
5+
name: ${CLUSTER_NAME}
6+
spec:
7+
failureDomains:
8+
- name: ${CLOUDSTACK_FD1_NAME}
9+
acsEndpoint:
10+
name: ${CLOUDSTACK_FD1_SECRET_NAME}
11+
namespace: default
12+
zone:
13+
name: ${CLOUDSTACK_ZONE_NAME}
14+
network:
15+
name: ${CLOUDSTACK_NETWORK_NAME_WITH_CUSTOM_OFFERING}
16+
gateway: ${CLOUDSTACK_GATEWAY}
17+
netmask: ${CLOUDSTACK_NETMASK}
18+
offering: ${CLOUDSTACK_NETWORK_CUSTOM_OFFERING_EGRESS_POLICY_TRUE_NAME}
19+
controlPlaneEndpoint:
20+
host: ""
21+
port: 6443
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
bases:
2+
- ../bases/cluster-with-kcp.yaml
3+
- ../bases/md.yaml
4+
5+
patchesStrategicMerge:
6+
- ./cluster-with-network-with-custom-offering.yaml

0 commit comments

Comments
 (0)