Skip to content

Commit

Permalink
feat: sss add zone deployment strategies for AUTO, zone_1 zone_2 zone_3
Browse files Browse the repository at this point in the history
  • Loading branch information
cristiGuranIonos committed Nov 28, 2024
1 parent 1d20bd4 commit 06b85c5
Show file tree
Hide file tree
Showing 11 changed files with 118 additions and 32 deletions.
4 changes: 4 additions & 0 deletions apis/compute/v1alpha1/serverset_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ type ServerSetParameters struct {
// +kubebuilder:validation:Required
// +kubebuilder:validation:Minimum=1
Replicas int `json:"replicas"`
// +kubebuilder:validation:Optional
DeploymentStrategy DeploymentStrategy `json:"deploymentStrategy"`
// DatacenterConfig contains information about the datacenter resource
// on which the server will be created.
//
Expand Down Expand Up @@ -263,6 +265,8 @@ const (
CreateBeforeDestroyBootVolume = "createBeforeDestroyBootVolume"
)

const ()

// +kubebuilder:object:root=true

// ServerSet represents a stateful set of servers in the Ionos Cloud.
Expand Down
2 changes: 1 addition & 1 deletion apis/compute/v1alpha1/statefulserverset_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import (

// DeploymentStrategy describes what strategy should be used to deploy the servers.
type DeploymentStrategy struct {
// +kubebuilder:validation:Enum=ZONES
// +kubebuilder:validation:Enum=ZONES;AUTO;ZONE_1;ZONE_2;ZONE_3
Type string `json:"type"`
}

Expand Down
1 change: 1 addition & 0 deletions apis/compute/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -149,13 +149,17 @@ func fromSSSetToVolume(cr *v1alpha1.StatefulServerSet, name string, replicaIndex
DeletionPolicy: cr.GetDeletionPolicy(),
},
ForProvider: v1alpha1.VolumeParameters{
DatacenterCfg: cr.Spec.ForProvider.DatacenterCfg,
Name: generateProviderNameFromIndex(cr.Spec.ForProvider.Volumes[volumeIndex].Metadata.Name, volumeIndex),
AvailabilityZone: serverset.GetZoneFromIndex(replicaIndex),
Size: cr.Spec.ForProvider.Volumes[volumeIndex].Spec.Size,
Type: cr.Spec.ForProvider.Volumes[volumeIndex].Spec.Type,
DatacenterCfg: cr.Spec.ForProvider.DatacenterCfg,
Name: generateProviderNameFromIndex(cr.Spec.ForProvider.Volumes[volumeIndex].Metadata.Name, volumeIndex),
Size: cr.Spec.ForProvider.Volumes[volumeIndex].Spec.Size,
Type: cr.Spec.ForProvider.Volumes[volumeIndex].Spec.Type,
},
}}
options := serverset.ZoneDeploymentOptions{
Zone: cr.Spec.ForProvider.DeploymentStrategy.Type,
Index: replicaIndex,
}
vol.Spec.ForProvider.AvailabilityZone = serverset.NewZoneDeploymentByType(cr.Spec.ForProvider.DeploymentStrategy.Type).GetZone(options)
if cr.Spec.ForProvider.Volumes[volumeIndex].Spec.Image != "" {
vol.Spec.ForProvider.Image = cr.Spec.ForProvider.Volumes[volumeIndex].Spec.Image
// todo - this will not work without a password
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ func extractSSetFromSSSet(sSSet *v1alpha1.StatefulServerSet) *v1alpha1.ServerSet
},
ForProvider: v1alpha1.ServerSetParameters{
Replicas: sSSet.Spec.ForProvider.Replicas,
DeploymentStrategy: sSSet.Spec.ForProvider.DeploymentStrategy,
DatacenterCfg: sSSet.Spec.ForProvider.DatacenterCfg,
Template: sSSet.Spec.ForProvider.Template,
BootVolumeTemplate: sSSet.Spec.ForProvider.BootVolumeTemplate,
Expand Down
18 changes: 11 additions & 7 deletions internal/controller/serverset/bootvolume_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,15 +216,19 @@ func fromServerSetToVolume(cr *v1alpha1.ServerSet, name string, replicaIndex, ve
DeletionPolicy: cr.GetDeletionPolicy(),
},
ForProvider: v1alpha1.VolumeParameters{
DatacenterCfg: cr.Spec.ForProvider.DatacenterCfg,
Name: name,
AvailabilityZone: GetZoneFromIndex(replicaIndex),
Size: cr.Spec.ForProvider.BootVolumeTemplate.Spec.Size,
Type: cr.Spec.ForProvider.BootVolumeTemplate.Spec.Type,
Image: cr.Spec.ForProvider.BootVolumeTemplate.Spec.Image,
UserData: cr.Spec.ForProvider.BootVolumeTemplate.Spec.UserData,
DatacenterCfg: cr.Spec.ForProvider.DatacenterCfg,
Name: name,
Size: cr.Spec.ForProvider.BootVolumeTemplate.Spec.Size,
Type: cr.Spec.ForProvider.BootVolumeTemplate.Spec.Type,
Image: cr.Spec.ForProvider.BootVolumeTemplate.Spec.Image,
UserData: cr.Spec.ForProvider.BootVolumeTemplate.Spec.UserData,
},
}}
options := ZoneDeploymentOptions{
Zone: cr.Spec.ForProvider.DeploymentStrategy.Type,
Index: replicaIndex,
}
vol.Spec.ForProvider.AvailabilityZone = NewZoneDeploymentByType(cr.Spec.ForProvider.DeploymentStrategy.Type).GetZone(options)
if cr.Spec.ForProvider.BootVolumeTemplate.Spec.ImagePassword != "" {
vol.Spec.ForProvider.ImagePassword = cr.Spec.ForProvider.BootVolumeTemplate.Spec.ImagePassword
}
Expand Down
24 changes: 12 additions & 12 deletions internal/controller/serverset/server_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ func (k *kubeServerController) isServerDeleted(ctx context.Context, name, namesp
// fromServerSetToServer is a conversion function that converts a ServerSet resource to a Server resource
// attaches a bootvolume to the server based on replicaIndex
func fromServerSetToServer(cr *v1alpha1.ServerSet, replicaIndex, version int) v1alpha1.Server {
return v1alpha1.Server{
srv := v1alpha1.Server{
ObjectMeta: metav1.ObjectMeta{
Name: getNameFrom(cr.Spec.ForProvider.Template.Metadata.Name, replicaIndex, version),
Namespace: cr.Namespace,
Expand All @@ -135,12 +135,11 @@ func fromServerSetToServer(cr *v1alpha1.ServerSet, replicaIndex, version int) v1
DeletionPolicy: cr.GetDeletionPolicy(),
},
ForProvider: v1alpha1.ServerParameters{
DatacenterCfg: cr.Spec.ForProvider.DatacenterCfg,
Name: getNameFrom(cr.Spec.ForProvider.Template.Metadata.Name, replicaIndex, version),
Cores: cr.Spec.ForProvider.Template.Spec.Cores,
RAM: cr.Spec.ForProvider.Template.Spec.RAM,
AvailabilityZone: GetZoneFromIndex(replicaIndex),
CPUFamily: cr.Spec.ForProvider.Template.Spec.CPUFamily,
DatacenterCfg: cr.Spec.ForProvider.DatacenterCfg,
Name: getNameFrom(cr.Spec.ForProvider.Template.Metadata.Name, replicaIndex, version),
Cores: cr.Spec.ForProvider.Template.Spec.Cores,
RAM: cr.Spec.ForProvider.Template.Spec.RAM,
CPUFamily: cr.Spec.ForProvider.Template.Spec.CPUFamily,
// todo revert if we go back to attaching volume on server creation
// VolumeCfg: v1alpha1.VolumeConfig{
// VolumeIDRef: &xpv1.Reference{
Expand All @@ -149,11 +148,12 @@ func fromServerSetToServer(cr *v1alpha1.ServerSet, replicaIndex, version int) v1
// },
},
}}
}

// GetZoneFromIndex returns ZONE_2 for odd and ZONE_1 for even index
func GetZoneFromIndex(index int) string {
return fmt.Sprintf("ZONE_%d", index%2+1)
options := ZoneDeploymentOptions{
Zone: cr.Spec.ForProvider.DeploymentStrategy.Type,
Index: replicaIndex,
}
srv.Spec.ForProvider.AvailabilityZone = NewZoneDeploymentByType(cr.Spec.ForProvider.DeploymentStrategy.Type).GetZone(options)
return srv
}

func (k *kubeServerController) Ensure(ctx context.Context, cr *v1alpha1.ServerSet, replicaIndex, version, volumeVersion int) error {
Expand Down
25 changes: 18 additions & 7 deletions internal/controller/serverset/server_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import "testing"

func TestGetZoneFromIndex(t *testing.T) {
type args struct {
index int
deplOptions ZoneDeploymentOptions
}
tests := []struct {
name string
Expand All @@ -14,42 +14,53 @@ func TestGetZoneFromIndex(t *testing.T) {
{
name: "index1ExpectedZone_1",
args: args{
index: 0,
deplOptions: ZoneDeploymentOptions{
Index: 0,
},
},
want: "ZONE_1",
},
{
name: "index1ExpectedZone_2",
args: args{
index: 1,
deplOptions: ZoneDeploymentOptions{
Index: 1,
},
},
want: "ZONE_2",
},
{
name: "index2ExpectedZone_1",
args: args{
index: 2,
deplOptions: ZoneDeploymentOptions{
Index: 2,
},
},
want: "ZONE_1",
},
{
name: "index10ExpectedZone_1",
args: args{
index: 10,
deplOptions: ZoneDeploymentOptions{
Index: 10,
},
},
want: "ZONE_1",
},
{
name: "index111ExpectedZone_2",
args: args{
index: 111,
deplOptions: ZoneDeploymentOptions{
Index: 111,
},
},
want: "ZONE_2",
},
}
depl := NewZoneDeploymentByType("ZONES")
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := GetZoneFromIndex(tt.args.index); got != tt.want {
if got := depl.GetZone(tt.args.deplOptions); got != tt.want {
t.Errorf("GetZoneFromIndex() = %v, want %v", got, tt.want)
}
})
Expand Down
42 changes: 42 additions & 0 deletions internal/controller/serverset/zone_deployment_strategy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package serverset

import "fmt"

// ZoneDeploymentOptions is used to pass the zone and index to the ZoneStrategy
type ZoneDeploymentOptions struct {
// Zone needed for whateverIsSet
Zone string
// Index is needed for eachServerInAZone
Index int
}

// ZoneStrategy is an interface that returns the zone for a server based on the ZoneDeploymentOptions
type ZoneStrategy interface {
GetZone(ZoneDeploymentOptions) string
}

// eachServerInAZone is a ZoneStrategy that returns ZONE_2 for odd and ZONE_1 for even index
type eachServerInAZone struct {
}

// GetZone returns ZONE_2 for odd and ZONE_1 for even index
func (e eachServerInAZone) GetZone(so ZoneDeploymentOptions) string {
return fmt.Sprintf("ZONE_%d", so.Index%2+1)
}

// whateverIsSet is a ZoneStrategy that returns the zone set in the ZoneDeploymentOptions
type whateverIsSet struct {
}

// GetZone returns the zone set in the ZoneDeploymentOptions
func (w whateverIsSet) GetZone(so ZoneDeploymentOptions) string {
return so.Zone
}

// NewZoneDeploymentByType returns a ZoneStrategy based on the zone string
func NewZoneDeploymentByType(zone string) ZoneStrategy {
if zone == "" || zone == "ZONES" {
return eachServerInAZone{}
}
return whateverIsSet{}
}
15 changes: 15 additions & 0 deletions package/crds/compute.ionoscloud.crossplane.io_serversets.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,21 @@ spec:
type: object
type: object
type: object
deploymentStrategy:
description: DeploymentStrategy describes what strategy should
be used to deploy the servers.
properties:
type:
enum:
- ZONES
- AUTO
- ZONE_1
- ZONE_2
- ZONE_3
type: string
required:
- type
type: object
identityConfigMap:
description: "IdentityConfigMap is the configMap from which the
identity of the ACTIVE server in the ServerSet is read. The
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,10 @@ spec:
type:
enum:
- ZONES
- AUTO
- ZONE_1
- ZONE_2
- ZONE_3
type: string
required:
- type
Expand Down

0 comments on commit 06b85c5

Please sign in to comment.