Skip to content

Commit ca74261

Browse files
committed
fix with eks-a upgrade to multiple-endpoints
1 parent a6e9659 commit ca74261

File tree

5 files changed

+97
-114
lines changed

5 files changed

+97
-114
lines changed

api/v1beta1/cloudstackmachine_conversion.go

Lines changed: 2 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -21,42 +21,12 @@ import (
2121
"sigs.k8s.io/controller-runtime/pkg/conversion"
2222
)
2323

24-
const CloudstackMachineAnnotationPrefix string = "cloudstackmachine.infrastructure.cluster.x-k8s.io/"
25-
2624
func (src *CloudStackMachine) ConvertTo(dstRaw conversion.Hub) error { // nolint
2725
dst := dstRaw.(*v1beta2.CloudStackMachine)
28-
err := Convert_v1beta1_CloudStackMachine_To_v1beta2_CloudStackMachine(src, dst, nil)
29-
if err != nil {
30-
return err
31-
}
32-
// need to save zoneId and zoneName to v1beta2s annotation in metadata
33-
dst.ObjectMeta.Annotations[CloudstackMachineAnnotationPrefix+"zoneid"] = src.Spec.ZoneID
34-
dst.ObjectMeta.Annotations[CloudstackMachineAnnotationPrefix+"zonename"] = src.Spec.ZoneName
35-
36-
// need to save failuredomainname in v1beta1's annotation to v1beta2's spec
37-
if len(src.ObjectMeta.Annotations[CloudstackMachineAnnotationPrefix+"failuredomainname"]) > 0 {
38-
dst.Spec.FailureDomainName = src.ObjectMeta.Annotations[CloudstackMachineAnnotationPrefix+"failuredomainname"]
39-
} else {
40-
defaultDomainName, err := GetDefaultFailureDomainName(src.ObjectMeta.Labels["cluster.x-k8s.io/cluster-name"], src.Spec.ZoneID, src.Spec.ZoneName)
41-
if err != nil {
42-
return err
43-
}
44-
dst.Spec.FailureDomainName = defaultDomainName
45-
}
46-
return nil
26+
return Convert_v1beta1_CloudStackMachine_To_v1beta2_CloudStackMachine(src, dst, nil)
4727
}
4828

4929
func (dst *CloudStackMachine) ConvertFrom(srcRaw conversion.Hub) error { // nolint
5030
src := srcRaw.(*v1beta2.CloudStackMachine)
51-
err := Convert_v1beta2_CloudStackMachine_To_v1beta1_CloudStackMachine(src, dst, nil)
52-
if err != nil {
53-
return err
54-
}
55-
// need to restore zoneid and zonename from v1beta2's annotation in metadata
56-
dst.Spec.ZoneID = src.ObjectMeta.Annotations[CloudstackMachineAnnotationPrefix+"zoneid"]
57-
dst.Spec.ZoneName = src.ObjectMeta.Annotations[CloudstackMachineAnnotationPrefix+"zonename"]
58-
59-
// need to save failuredomainname in v1beta1's annotation
60-
dst.ObjectMeta.Annotations[CloudstackMachineAnnotationPrefix+"failuredomainname"] = src.Spec.FailureDomainName
61-
return nil
31+
return Convert_v1beta2_CloudStackMachine_To_v1beta1_CloudStackMachine(src, dst, nil)
6232
}

api/v1beta1/conversion.go

Lines changed: 88 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,19 @@ limitations under the License.
1717
package v1beta1
1818

1919
import (
20+
"context"
2021
"fmt"
22+
"github.com/apache/cloudstack-go/v2/cloudstack"
2123
"github.com/pkg/errors"
2224
corev1 "k8s.io/api/core/v1"
2325
conv "k8s.io/apimachinery/pkg/conversion"
2426
"sigs.k8s.io/cluster-api-provider-cloudstack/api/v1beta2"
25-
"strings"
27+
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
28+
"sigs.k8s.io/controller-runtime/pkg/client"
2629
)
2730

31+
const DefaultEndpointCredential = "global"
32+
2833
//nolint:golint,revive,stylecheck
2934
func Convert_v1beta1_CloudStackCluster_To_v1beta2_CloudStackCluster(in *CloudStackCluster, out *v1beta2.CloudStackCluster, s conv.Scope) error {
3035
out.ObjectMeta = in.ObjectMeta
@@ -36,27 +41,30 @@ func Convert_v1beta1_CloudStackCluster_To_v1beta2_CloudStackCluster(in *CloudSta
3641
return err
3742
}
3843
}
44+
failureDomains, err := getFailureDomains(in)
45+
if err != nil {
46+
return err
47+
}
3948
out.Spec = v1beta2.CloudStackClusterSpec{
4049
ControlPlaneEndpoint: in.Spec.ControlPlaneEndpoint,
41-
FailureDomains: getFailureDomains(in),
50+
FailureDomains: failureDomains,
4251
Account: in.Spec.Account,
4352
Domain: in.Spec.Domain,
4453
IdentityRef: identifyRef,
4554
}
4655

4756
zoneStatusMap := v1beta2.ZoneStatusMap{}
4857
for zoneKey, zone := range in.Status.Zones {
49-
zone1 := zone
50-
zonev2 := &v1beta2.Zone{}
51-
err := Convert_v1beta1_Zone_To_v1beta2_Zone(&zone1, zonev2, nil)
58+
zoneV1 := zone
59+
zoneV2 := &v1beta2.Zone{}
60+
err := Convert_v1beta1_Zone_To_v1beta2_Zone(&zoneV1, zoneV2, nil)
5261
if err != nil {
5362
return err
5463
}
55-
zoneStatusMap[zoneKey] = *zonev2
64+
zoneStatusMap[zoneKey] = *zoneV2
5665
}
5766
out.Status = v1beta2.CloudStackClusterStatus{
5867
Zones: zoneStatusMap,
59-
//CloudStackFailureDomainStatusMap: getFailureDomainsStatusMap(in),
6068
FailureDomains: in.Status.FailureDomains,
6169
PublicIPID: in.Status.PublicIPID,
6270
PublicIPNetworkID: in.Status.PublicIPNetworkID,
@@ -125,57 +133,15 @@ func getZones(csCluster *v1beta2.CloudStackCluster) []Zone {
125133
return zones
126134
}
127135

128-
//func getZoneMap(csCluster *v1beta2.CloudStackCluster) (map[string]Zone, error) {
129-
// zoneMap := map[string]Zone{}
130-
// for key := range csCluster.Status.CloudStackFailureDomainStatusMap {
131-
// zone, err := getZoneByMetaName(csCluster, key)
132-
// if err != nil {
133-
// return nil, err
134-
// }
135-
// zoneMap[key] = zone
136-
// }
137-
// return zoneMap, nil
138-
//}
139-
//
140-
//func getDomainID(csCluster *v1beta2.CloudStackCluster) (string, error) {
141-
// var domainID string
142-
// for _, value := range csCluster.Status.CloudStackFailureDomainStatusMap {
143-
// if domainID == "" {
144-
// domainID = value.DomainID
145-
// } else if domainID != value.DomainID {
146-
// return "", errors.Errorf("multiple domainId found in cloudstack failure domain status")
147-
// }
148-
// }
149-
// return domainID, nil
150-
//}
151-
//
152-
//func getZoneByMetaName(csCluster *v1beta2.CloudStackCluster, metaName string) (Zone, error) {
153-
// var zone Zone
154-
// err := errors.Errorf("zone with meta %s not found", metaName)
155-
// for _, failureDomain := range csCluster.Spec.FailureDomains {
156-
// if failureDomain.Zone.MetaName() == metaName {
157-
// err = nil
158-
// zone = Zone{
159-
// ID: failureDomain.Zone.ID,
160-
// Name: failureDomain.Zone.Name,
161-
// Network: Network{
162-
// ID: failureDomain.Zone.Network.ID,
163-
// Name: failureDomain.Zone.Network.Name,
164-
// Type: failureDomain.Zone.Network.Type,
165-
// },
166-
// }
167-
// }
168-
// }
169-
// return zone, err
170-
//}
171-
172-
// getFailureDomains maps v1beta1 zones to v1beta2 failure domains
173-
func getFailureDomains(csCluster *CloudStackCluster) []v1beta2.CloudStackFailureDomainSpec {
136+
// getFailureDomains maps v1beta1 zones to v1beta2 failure domains.
137+
func getFailureDomains(csCluster *CloudStackCluster) ([]v1beta2.CloudStackFailureDomainSpec, error) {
174138
var failureDomains []v1beta2.CloudStackFailureDomainSpec
175-
index := 0
139+
namespace := csCluster.Namespace
176140
for _, zone := range csCluster.Spec.Zones {
177-
index = index + 1
178-
name := fmt.Sprintf("%s-%s-%d", csCluster.Name, "failuredomain", index)
141+
name, err := GetDefaultFailureDomainName(namespace, csCluster.Name, zone.ID, zone.Name)
142+
if err != nil {
143+
return nil, err
144+
}
179145
failureDomains = append(failureDomains, v1beta2.CloudStackFailureDomainSpec{
180146
Name: name,
181147
Zone: v1beta2.CloudStackZoneSpec{
@@ -191,39 +157,81 @@ func getFailureDomains(csCluster *CloudStackCluster) []v1beta2.CloudStackFailure
191157
Account: csCluster.Spec.Account,
192158
ACSEndpoint: corev1.SecretReference{
193159
Namespace: csCluster.ObjectMeta.Namespace,
194-
Name: name,
160+
Name: DefaultEndpointCredential,
195161
},
196162
})
197163
}
198-
return failureDomains
164+
return failureDomains, nil
199165
}
200166

201-
//
202-
//func getFailureDomainsStatusMap(csCluster *CloudStackCluster) map[string]v1beta2.CloudStackFailureDomainStatus {
203-
// failureDomainsStatusMap := map[string]v1beta2.CloudStackFailureDomainStatus{}
204-
// for _, zone := range csCluster.Spec.Zones {
205-
// failureDomainsStatusMap[zone.MetaName()] = v1beta2.CloudStackFailureDomainStatus{
206-
// DomainID: csCluster.Status.DomainID,
207-
// Ready: csCluster.Status.Ready,
208-
// }
209-
// }
210-
// return failureDomainsStatusMap
211-
//}
167+
// GetDefaultFailureDomainName return zoneID as failuredomain name.
168+
// Default failure domain name is used when migrating an old cluster to a multiple-endpoints supported cluster, that
169+
// requires to convert each zone to a failure domain.
170+
// When upgrading cluster using eks-a, a secret named global will be created by eks-a, and it is used by following
171+
// method to get zoneID by calling cloudstack API.
172+
// When upgrading cluster using clusterctl directly, zoneID is fetched directly from kubernetes cluster in cloudstackzones.
173+
func GetDefaultFailureDomainName(namespace string, clusterName string, zoneID string, zoneName string) (string, error) {
174+
if len(zoneID) > 0 {
175+
return zoneID, nil
176+
}
212177

213-
func GetDefaultFailureDomainName(clusterName string, zoneID string, zoneName string) (string, error) {
214-
zoneMetaName := ""
215-
if len(zoneName) > 0 {
216-
zoneMetaName = zoneName
217-
} else if len(zoneID) > 0 {
218-
zoneMetaName = zoneID
178+
// try fetch zoneID using zoneName through cloudstack client
179+
zoneID, err := fetchZoneIDUsingCloudStack(namespace, zoneName)
180+
if err == nil {
181+
return zoneID, nil
219182
}
220183

221-
if len(zoneMetaName) == 0 {
222-
return "", errors.Errorf("failed to generate default failureDomainName: zone id and name both empty")
184+
return fetchZoneIDUsingK8s(namespace, clusterName, zoneName)
185+
}
186+
187+
func fetchZoneIDUsingK8s(namespace string, clusterName string, zoneName string) (string, error) {
188+
zones := &v1beta2.CloudStackZoneList{}
189+
capiClusterLabel := map[string]string{clusterv1.ClusterLabelName: clusterName}
190+
if err := v1beta2.K8sClient.List(
191+
context.TODO(),
192+
zones,
193+
client.InNamespace(namespace),
194+
client.MatchingLabels(capiClusterLabel),
195+
); err != nil {
196+
return "", err
223197
}
224-
if len(clusterName) == 0 {
225-
return "", errors.Errorf("failed to generate default failureDomainName: clusterName empty")
198+
199+
for _, zone := range zones.Items {
200+
if zone.Spec.Name == zoneName {
201+
return zone.Spec.ID, nil
202+
}
226203
}
227204

228-
return strings.ToLower(fmt.Sprintf("%s-failuredomain-%s", clusterName, zoneMetaName)), nil
205+
return "", errors.Errorf("failed to generate default failureDomainName: zone id not found for zone name: %s", zoneName)
206+
}
207+
208+
func fetchZoneIDUsingCloudStack(namespace string, zoneName string) (string, error) {
209+
endpointCredentials := &corev1.Secret{}
210+
key := client.ObjectKey{Name: DefaultEndpointCredential, Namespace: namespace}
211+
if err := v1beta2.K8sClient.Get(context.TODO(), key, endpointCredentials); err != nil {
212+
return "", err
213+
}
214+
215+
config := map[string]interface{}{}
216+
for k, v := range endpointCredentials.Data {
217+
config[k] = string(v)
218+
}
219+
// TODO change secret parsing manner.
220+
if val, present := config["verify-ssl"]; present {
221+
if val == "true" {
222+
config["verify-ssl"] = true
223+
} else if val == "false" {
224+
config["verify-ssl"] = false
225+
}
226+
}
227+
228+
csClient := cloudstack.NewAsyncClient(fmt.Sprint(config["api-url"]), fmt.Sprint(config["api-key"]), fmt.Sprint(config["secret-key"]), fmt.Sprint(config["verify-ssl"]) == "true")
229+
230+
if zoneID, count, err := csClient.Zone.GetZoneID(zoneName); err != nil {
231+
return "", err
232+
} else if count != 1 {
233+
return "", errors.Errorf("%v zones found for zone name %s", count, zoneName)
234+
} else {
235+
return zoneID, nil
236+
}
229237
}

api/v1beta2/cloudstackcluster_types.go

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

2222
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2323
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
24+
"sigs.k8s.io/controller-runtime/pkg/client"
2425
)
2526

2627
const (
@@ -31,6 +32,8 @@ const (
3132
NetworkTypeShared = "Shared"
3233
)
3334

35+
var K8sClient client.Client
36+
3437
// CloudStackIdentityReference is a reference to an infrastructure
3538
// provider identity to be used to provision cluster resources.
3639
type CloudStackIdentityReference struct {

config/crd/kustomization.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ resources:
1313
- bases/infrastructure.cluster.x-k8s.io_cloudstackzones.yaml
1414
- bases/infrastructure.cluster.x-k8s.io_cloudstackaffinitygroups.yaml
1515
- bases/infrastructure.cluster.x-k8s.io_cloudstackmachinestatecheckers.yaml
16-
- bases/infrastructure.cluster.x-k8s.io_cloudstackfailuredomains.yaml
1716
#+kubebuilder:scaffold:crdkustomizeresource
1817

1918
patchesStrategicMerge:

main.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import (
4141

4242
controlplanev1 "sigs.k8s.io/cluster-api/controlplane/kubeadm/api/v1beta1"
4343

44+
infrav1b1 "sigs.k8s.io/cluster-api-provider-cloudstack/api/v1beta1"
4445
infrav1b2 "sigs.k8s.io/cluster-api-provider-cloudstack/api/v1beta2"
4546
"sigs.k8s.io/cluster-api-provider-cloudstack/controllers"
4647
"sigs.k8s.io/cluster-api-provider-cloudstack/controllers/utils"
@@ -55,8 +56,9 @@ var (
5556
func init() {
5657
utilruntime.Must(clientgoscheme.AddToScheme(scheme))
5758
utilruntime.Must(clusterv1.AddToScheme(scheme))
58-
utilruntime.Must(controlplanev1.AddToScheme(scheme))
59+
utilruntime.Must(infrav1b1.AddToScheme(scheme))
5960
utilruntime.Must(infrav1b2.AddToScheme(scheme))
61+
utilruntime.Must(controlplanev1.AddToScheme(scheme))
6062
//+kubebuilder:scaffold:scheme
6163
}
6264

@@ -149,6 +151,7 @@ func main() {
149151
Scheme: mgr.GetScheme()}
150152

151153
setupReconcilers(base, mgr)
154+
infrav1b2.K8sClient = base.K8sClient
152155

153156
// +kubebuilder:scaffold:builder
154157

0 commit comments

Comments
 (0)