Skip to content

Commit ed57264

Browse files
author
Joshua Reed
committed
Updated cloud tests commit to reflect file move.
1 parent 6dc377e commit ed57264

18 files changed

+1542
-41
lines changed

pkg/cloud/client.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,11 @@ type Config struct {
5454
func NewClient(ccPath string) (Client, error) {
5555
c := &client{config: Config{VerifySSL: true}}
5656
if rawCfg, err := ini.Load(ccPath); err != nil {
57-
return nil, errors.Wrapf(err, "reading config at path %s:", ccPath)
57+
return nil, errors.Wrapf(err, "reading config at path %s", ccPath)
5858
} else if g := rawCfg.Section("Global"); len(g.Keys()) == 0 {
5959
return nil, errors.New("section Global not found")
6060
} else if err = rawCfg.Section("Global").StrictMapTo(&c.config); err != nil {
61-
return nil, errors.Wrapf(err, "parsing [Global] section from config at path %s:", ccPath)
61+
return nil, errors.Wrapf(err, "parsing [Global] section from config at path %s", ccPath)
6262
}
6363

6464
// The client returned from NewAsyncClient works in a synchronous way. On the other hand,
@@ -71,7 +71,7 @@ func NewClient(ccPath string) (Client, error) {
7171
if err != nil && strings.Contains(strings.ToLower(err.Error()), "i/o timeout") {
7272
return c, errors.Wrap(err, "timeout while checking CloudStack API Client connectivity")
7373
}
74-
return c, errors.Wrap(err, "checking CloudStack API Client connectivity:")
74+
return c, errors.Wrap(err, "checking CloudStack API Client connectivity")
7575
}
7676

7777
// NewClientFromSpec generates a new client from an existing client.
@@ -94,7 +94,7 @@ func (origC *client) NewClientFromSpec(cfg Config) (Client, error) {
9494
if err != nil && strings.Contains(strings.ToLower(err.Error()), "i/o timeout") {
9595
return newC, errors.Wrap(err, "timeout while checking CloudStack API Client connectivity")
9696
}
97-
return newC, errors.Wrap(err, "checking CloudStack API Client connectivity:")
97+
return newC, errors.Wrap(err, "checking CloudStack API Client connectivity")
9898
}
9999

100100
func NewClientFromCSAPIClient(cs *cloudstack.CloudStackClient) Client {

pkg/cloud/helpers.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424

2525
type set func(string)
2626
type setArray func([]string)
27+
type setInt func(int64)
2728

2829
func setIfNotEmpty(str string, setFn set) {
2930
if str != "" {
@@ -37,6 +38,12 @@ func setArrayIfNotEmpty(strArray []string, setFn setArray) {
3738
}
3839
}
3940

41+
func setIntIfPositive(num int64, setFn setInt) {
42+
if num > 0 {
43+
setFn(num)
44+
}
45+
}
46+
4047
func CompressAndEncodeString(str string) (string, error) {
4148
buf := &bytes.Buffer{}
4249
gzipWriter := gzip.NewWriter(buf)

pkg/cloud/instance.go

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -139,35 +139,55 @@ func (c *client) ResolveTemplate(
139139
// disk offering name matches name provided in spec.
140140
// If disk offering ID is not provided, the disk offering name is used to retrieve disk offering ID.
141141
func (c *client) ResolveDiskOffering(csMachine *infrav1.CloudStackMachine) (diskOfferingID string, retErr error) {
142-
if len(csMachine.Spec.DiskOffering.ID) > 0 {
143-
csDiskOffering, count, err := c.cs.DiskOffering.GetDiskOfferingByID(csMachine.Spec.DiskOffering.ID)
142+
diskOfferingID = csMachine.Spec.DiskOffering.ID
143+
if len(csMachine.Spec.DiskOffering.Name) > 0 {
144+
diskID, count, err := c.cs.DiskOffering.GetDiskOfferingID(csMachine.Spec.DiskOffering.Name)
144145
if err != nil {
145146
return "", multierror.Append(retErr, errors.Wrapf(
146-
err, "could not get DiskOffering by ID %s", csMachine.Spec.DiskOffering.ID))
147+
err, "could not get DiskOffering ID from %s", csMachine.Spec.DiskOffering.Name))
147148
} else if count != 1 {
148149
return "", multierror.Append(retErr, errors.Errorf(
149-
"expected 1 DiskOffering with UUID %s, but got %d", csMachine.Spec.DiskOffering.ID, count))
150-
}
151-
152-
if len(csMachine.Spec.DiskOffering.Name) > 0 && csMachine.Spec.DiskOffering.Name != csDiskOffering.Name {
150+
"expected 1 DiskOffering with name %s, but got %d", csMachine.Spec.DiskOffering.Name, count))
151+
} else if len(csMachine.Spec.DiskOffering.ID) > 0 && diskID != csMachine.Spec.DiskOffering.ID {
152+
return "", multierror.Append(retErr, errors.Errorf(
153+
"diskOffering ID %s does not match ID %s returned using name %s",
154+
csMachine.Spec.DiskOffering.ID, diskID, csMachine.Spec.DiskOffering.Name))
155+
} else if len(diskID) == 0 {
153156
return "", multierror.Append(retErr, errors.Errorf(
154-
"diskOffering name %s does not match name %s returned using UUID %s",
155-
csMachine.Spec.DiskOffering.Name, csDiskOffering.Name, csMachine.Spec.DiskOffering.ID))
157+
"empty diskOffering ID %s returned using name %s",
158+
diskID, csMachine.Spec.DiskOffering.Name))
156159
}
157-
return csMachine.Spec.DiskOffering.ID, nil
160+
diskOfferingID = diskID
158161
}
159-
if len(csMachine.Spec.DiskOffering.Name) == 0 {
162+
if len(diskOfferingID) == 0 {
160163
return "", nil
161164
}
162-
diskID, count, err := c.cs.DiskOffering.GetDiskOfferingID(csMachine.Spec.DiskOffering.Name)
165+
166+
return verifyDiskoffering(csMachine, c, diskOfferingID, retErr)
167+
}
168+
169+
func verifyDiskoffering(csMachine *infrav1.CloudStackMachine, c *client, diskOfferingID string, retErr error) (string, error) {
170+
csDiskOffering, count, err := c.cs.DiskOffering.GetDiskOfferingByID(diskOfferingID)
163171
if err != nil {
164172
return "", multierror.Append(retErr, errors.Wrapf(
165-
err, "could not get DiskOffering ID from %s", csMachine.Spec.DiskOffering.Name))
173+
err, "could not get DiskOffering by ID %s", diskOfferingID))
166174
} else if count != 1 {
167175
return "", multierror.Append(retErr, errors.Errorf(
168-
"expected 1 DiskOffering with name %s, but got %d", csMachine.Spec.DiskOffering.Name, count))
176+
"expected 1 DiskOffering with UUID %s, but got %d", diskOfferingID, count))
177+
}
178+
179+
if csDiskOffering.Iscustomized && csMachine.Spec.DiskOffering.CustomSize == 0 {
180+
return "", multierror.Append(retErr, errors.Errorf(
181+
"diskOffering with UUID %s is customized, disk size can not be 0 GB",
182+
diskOfferingID))
183+
}
184+
185+
if !csDiskOffering.Iscustomized && csMachine.Spec.DiskOffering.CustomSize > 0 {
186+
return "", multierror.Append(retErr, errors.Errorf(
187+
"diskOffering with UUID %s is not customized, disk size can not be specified",
188+
diskOfferingID))
169189
}
170-
return diskID, nil
190+
return diskOfferingID, nil
171191
}
172192

173193
// GetOrCreateVMInstance CreateVMInstance will fetch or create a VM instance, and
@@ -205,6 +225,7 @@ func (c *client) GetOrCreateVMInstance(
205225
setIfNotEmpty(csMachine.Name, p.SetName)
206226
setIfNotEmpty(csMachine.Name, p.SetDisplayname)
207227
setIfNotEmpty(diskOfferingID, p.SetDiskofferingid)
228+
setIntIfPositive(csMachine.Spec.DiskOffering.CustomSize, p.SetSize)
208229

209230
setIfNotEmpty(csMachine.Spec.SSHKey, p.SetKeypair)
210231

pkg/cloud/isolated_network.go

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import (
2222

2323
"github.com/apache/cloudstack-go/v2/cloudstack"
2424
capcv1 "github.com/aws/cluster-api-provider-cloudstack/api/v1beta1"
25-
infrav1 "github.com/aws/cluster-api-provider-cloudstack/api/v1beta1"
2625
"github.com/hashicorp/go-multierror"
2726
"github.com/pkg/errors"
2827
)
@@ -38,7 +37,7 @@ type IsoNetworkIface interface {
3837

3938
AssignVMToLoadBalancerRule(isoNet *capcv1.CloudStackIsolatedNetwork, instanceID string) error
4039
DeleteNetwork(capcv1.Network) error
41-
DisposeIsoNetResources(*capcv1.CloudStackZone, *infrav1.CloudStackIsolatedNetwork, *infrav1.CloudStackCluster) error
40+
DisposeIsoNetResources(*capcv1.CloudStackZone, *capcv1.CloudStackIsolatedNetwork, *capcv1.CloudStackCluster) error
4241
}
4342

4443
// getOfferingID fetches an offering id.
@@ -61,7 +60,7 @@ func (c *client) AssociatePublicIPAddress(
6160
// Check specified IP address is available or get an unused one if not specified.
6261
publicAddress, err := c.GetPublicIP(zone, isoNet, csCluster)
6362
if err != nil {
64-
return errors.Wrapf(err, "fetching a public IP address:")
63+
return errors.Wrapf(err, "fetching a public IP address")
6564
}
6665
isoNet.Spec.ControlPlaneEndpoint.Host = publicAddress.Ipaddress
6766
csCluster.Spec.ControlPlaneEndpoint.Host = publicAddress.Ipaddress
@@ -78,14 +77,14 @@ func (c *client) AssociatePublicIPAddress(
7877
p.SetNetworkid(isoNet.Spec.ID)
7978
if _, err := c.cs.Address.AssociateIpAddress(p); err != nil {
8079
return errors.Wrapf(err,
81-
"associating public IP address with ID %s to netowrk with ID %s:",
80+
"associating public IP address with ID %s to network with ID %s",
8281
publicAddress.Id, isoNet.Spec.ID)
8382
} else if err := c.AddClusterTag(ResourceTypeIPAddress, publicAddress.Id, csCluster); err != nil {
8483
return errors.Wrapf(err,
85-
"adding tag to public IP address with ID %s:", publicAddress.Id)
84+
"adding tag to public IP address with ID %s", publicAddress.Id)
8685
} else if err := c.AddCreatedByCAPCTag(ResourceTypeIPAddress, isoNet.Status.PublicIPID); err != nil {
8786
return errors.Wrapf(err,
88-
"adding tag to public IP address with ID %s:", publicAddress.Id)
87+
"adding tag to public IP address with ID %s", publicAddress.Id)
8988
}
9089
return nil
9190
}
@@ -102,7 +101,7 @@ func (c *client) CreateIsolatedNetwork(zone *capcv1.CloudStackZone, isoNet *capc
102101
p := c.cs.Network.NewCreateNetworkParams(isoNet.Spec.Name, isoNet.Spec.Name, offeringID, zone.Spec.ID)
103102
resp, err := c.cs.Network.CreateNetwork(p)
104103
if err != nil {
105-
return errors.Wrapf(err, "creating network with name %s:", isoNet.Spec.Name)
104+
return errors.Wrapf(err, "creating network with name %s", isoNet.Spec.Name)
106105
}
107106
isoNet.Spec.ID = resp.Id
108107
return c.AddCreatedByCAPCTag(ResourceTypeNetwork, isoNet.Spec.ID)
@@ -186,7 +185,7 @@ func (c *client) ResolveLoadBalancerRuleDetails(
186185
p.SetPublicipid(isoNet.Status.PublicIPID)
187186
loadBalancerRules, err := c.cs.LoadBalancer.ListLoadBalancerRules(p)
188187
if err != nil {
189-
return errors.Wrap(err, "listing load balancer rules:")
188+
return errors.Wrap(err, "listing load balancer rules")
190189
}
191190
for _, rule := range loadBalancerRules.LoadBalancerRules {
192191
if rule.Publicport == strconv.Itoa(int(isoNet.Spec.ControlPlaneEndpoint.Port)) {
@@ -218,7 +217,7 @@ func (c *client) GetOrCreateLoadBalancerRule(
218217
// Check if rule exists.
219218
if err := c.ResolveLoadBalancerRuleDetails(zone, isoNet, csCluster); err == nil ||
220219
!strings.Contains(strings.ToLower(err.Error()), "no load balancer rule found") {
221-
return errors.Wrap(err, "resolving load balancer rule details:")
220+
return errors.Wrap(err, "resolving load balancer rule details")
222221
}
223222

224223
p := c.cs.LoadBalancer.NewCreateLoadBalancerRuleParams(
@@ -240,35 +239,35 @@ func (c *client) GetOrCreateLoadBalancerRule(
240239
func (c *client) GetOrCreateIsolatedNetwork(
241240
zone *capcv1.CloudStackZone,
242241
isoNet *capcv1.CloudStackIsolatedNetwork,
243-
csCluster *infrav1.CloudStackCluster,
242+
csCluster *capcv1.CloudStackCluster,
244243
) error {
245244
// Get or create the isolated network itself and resolve details into passed custom resources.
246245
net := isoNet.Network()
247246
if err := c.ResolveNetwork(net); err != nil { // Doesn't exist, create isolated network.
248247
if err = c.CreateIsolatedNetwork(zone, isoNet); err != nil {
249-
return errors.Wrap(err, "creating a new isolated network:")
248+
return errors.Wrap(err, "creating a new isolated network")
250249
}
251250
}
252251
isoNet.Spec.ID = net.ID
253252

254253
// Tag the created network.
255254
networkID := isoNet.Spec.ID
256255
if err := c.AddClusterTag(ResourceTypeNetwork, networkID, csCluster); err != nil {
257-
return errors.Wrapf(err, "tagging network with id %s:", networkID)
256+
return errors.Wrapf(err, "tagging network with id %s", networkID)
258257
}
259258

260259
// Associate Public IP with CloudStackIsolatedNetwork
261260
if err := c.AssociatePublicIPAddress(zone, isoNet, csCluster); err != nil {
262-
return errors.Wrapf(err, "associating public IP address to csCluster:")
261+
return errors.Wrapf(err, "associating public IP address to csCluster")
263262
}
264263

265264
// Setup a load balancing rule to map VMs to Public IP.
266265
if err := c.GetOrCreateLoadBalancerRule(zone, isoNet, csCluster); err != nil {
267-
return errors.Wrap(err, "getting or creating load balancing rule:")
266+
return errors.Wrap(err, "getting or creating load balancing rule")
268267
}
269268

270269
// Open the Isolated Network on endopint port.
271-
return errors.Wrap(c.OpenFirewallRules(isoNet), "opening the isolated network's firewall:")
270+
return errors.Wrap(c.OpenFirewallRules(isoNet), "opening the isolated network's firewall")
272271
}
273272

274273
// AssignVMToLoadBalancerRule assigns a VM instance to a load balancing rule (specifying lb membership).
@@ -296,14 +295,14 @@ func (c *client) AssignVMToLoadBalancerRule(isoNet *capcv1.CloudStackIsolatedNet
296295
// DeleteNetwork deletes an isolated network.
297296
func (c *client) DeleteNetwork(net capcv1.Network) error {
298297
_, err := c.cs.Network.DeleteNetwork(c.cs.Network.NewDeleteNetworkParams(net.ID))
299-
return errors.Wrapf(err, "deleting network with id %s:", net.ID)
298+
return errors.Wrapf(err, "deleting network with id %s", net.ID)
300299
}
301300

302301
// DisposeIsoNetResources cleans up isolated network resources.
303302
func (c *client) DisposeIsoNetResources(
304-
zone *infrav1.CloudStackZone,
305-
isoNet *infrav1.CloudStackIsolatedNetwork,
306-
csCluster *infrav1.CloudStackCluster,
303+
zone *capcv1.CloudStackZone,
304+
isoNet *capcv1.CloudStackIsolatedNetwork,
305+
csCluster *capcv1.CloudStackCluster,
307306
) (retError error) {
308307
if isoNet.Status.PublicIPID != "" {
309308
if err := c.DeleteClusterTag(ResourceTypeIPAddress, csCluster.Status.PublicIPID, csCluster); err != nil {

pkg/cloud/tags.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ func (c *client) IsCapcManaged(resourceType ResourceType, resourceID string) (bo
5858
tags, err := c.GetTags(resourceType, resourceID)
5959
if err != nil {
6060
return false, errors.Wrapf(err,
61-
"checking if %s with ID: %s is tagged as CAPC managed:", resourceType, resourceID)
61+
"checking if %s with ID: %s is tagged as CAPC managed", resourceType, resourceID)
6262
}
6363
_, CreatedByCAPC := tags[CreatedByCAPCTagName]
6464
return CreatedByCAPC, nil

pkg/cloud/user_credentials.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,8 @@ func (c *client) ResolveDomain(domain *Domain) error {
7474
tokens = append([]string{rootDomain}, tokens...)
7575
} else {
7676
tokens[0] = rootDomain
77-
domain.Path = strings.Join(tokens, domainDelimiter)
7877
}
78+
domain.Path = strings.Join(tokens, domainDelimiter)
7979
}
8080

8181
// Set present search/list parameters.
@@ -130,7 +130,7 @@ func (c *client) ResolveDomain(domain *Domain) error {
130130
func (c *client) ResolveAccount(account *Account) error {
131131
// Resolve domain prior to any account resolution activity.
132132
if err := c.ResolveDomain(&account.Domain); err != nil {
133-
return errors.Wrapf(err, "resolving domain %s details:", account.Domain.Name)
133+
return errors.Wrapf(err, "resolving domain %s details", account.Domain.Name)
134134
}
135135

136136
p := c.cs.Account.NewListAccountsParams()
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/*
2+
Copyright 2022 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package cloud_test
18+
19+
import (
20+
"errors"
21+
22+
"github.com/apache/cloudstack-go/v2/cloudstack"
23+
"github.com/aws/cluster-api-provider-cloudstack/pkg/cloud"
24+
"github.com/aws/cluster-api-provider-cloudstack/test/dummies"
25+
"github.com/golang/mock/gomock"
26+
. "github.com/onsi/ginkgo/v2"
27+
. "github.com/onsi/gomega"
28+
)
29+
30+
var _ = Describe("AffinityGroup Unit Tests", func() {
31+
var ( // Declare shared vars.
32+
mockCtrl *gomock.Controller
33+
mockClient *cloudstack.CloudStackClient
34+
ags *cloudstack.MockAffinityGroupServiceIface
35+
client cloud.Client
36+
)
37+
38+
BeforeEach(func() {
39+
// Setup new mock services.
40+
mockCtrl = gomock.NewController(GinkgoT())
41+
mockClient = cloudstack.NewMockClient(mockCtrl)
42+
ags = mockClient.AffinityGroup.(*cloudstack.MockAffinityGroupServiceIface)
43+
client = cloud.NewClientFromCSAPIClient(mockClient)
44+
dummies.SetDummyVars()
45+
})
46+
47+
AfterEach(func() {
48+
mockCtrl.Finish()
49+
})
50+
51+
It("fetches an affinity group", func() {
52+
dummies.AffinityGroup.ID = "" // Force name fetching.
53+
ags.EXPECT().GetAffinityGroupByName(dummies.AffinityGroup.Name).Return(&cloudstack.AffinityGroup{}, 1, nil)
54+
55+
Ω(client.GetOrCreateAffinityGroup(dummies.AffinityGroup)).Should(Succeed())
56+
})
57+
It("creates an affinity group", func() {
58+
dummies.SetDummyDomainAndAccount()
59+
dummies.SetDummyDomainID()
60+
ags.EXPECT().GetAffinityGroupByID(dummies.AffinityGroup.ID).Return(nil, -1, errors.New("FakeError"))
61+
ags.EXPECT().NewCreateAffinityGroupParams(dummies.AffinityGroup.Name, dummies.AffinityGroup.Type).
62+
Return(&cloudstack.CreateAffinityGroupParams{})
63+
ags.EXPECT().CreateAffinityGroup(ParamMatch(And(NameEquals(dummies.AffinityGroup.Name)))).
64+
Return(&cloudstack.CreateAffinityGroupResponse{}, nil)
65+
66+
Ω(client.GetOrCreateAffinityGroup(dummies.AffinityGroup)).Should(Succeed())
67+
})
68+
69+
Context("AffinityGroup Integ Tests", func() {
70+
client, connectionErr := cloud.NewClient("../../cloud-config")
71+
72+
BeforeEach(func() {
73+
if connectionErr != nil { // Only do these tests if an actual ACS instance is available via cloud-config.
74+
Skip("Could not connect to ACS instance.")
75+
}
76+
dummies.AffinityGroup.ID = "" // Force name fetching.
77+
})
78+
AfterEach(func() {
79+
mockCtrl.Finish()
80+
})
81+
82+
It("Creates an affinity group.", func() {
83+
Ω(client.GetOrCreateAffinityGroup(dummies.AffinityGroup)).Should(Succeed())
84+
})
85+
It("Associates an affinity group.", func() {
86+
if err := client.GetOrCreateVMInstance(
87+
dummies.CSMachine1, dummies.CAPIMachine, dummies.CSCluster, dummies.CSZone1, dummies.CSAffinityGroup, "",
88+
); err != nil {
89+
Skip("Could not create VM." + err.Error())
90+
}
91+
Ω(client.GetOrCreateAffinityGroup(dummies.AffinityGroup)).Should(Succeed())
92+
Ω(client.AssociateAffinityGroup(dummies.CSMachine1, *dummies.AffinityGroup)).Should(Succeed())
93+
})
94+
It("Deletes an affinity group.", func() {
95+
Ω(client.DeleteAffinityGroup(dummies.AffinityGroup)).Should(Succeed())
96+
Ω(client.FetchAffinityGroup(dummies.AffinityGroup)).ShouldNot(Succeed())
97+
})
98+
})
99+
})

0 commit comments

Comments
 (0)