Skip to content

Commit 7c5bfa7

Browse files
authored
Merge pull request #53 from SovereignCloudStack/ani-syself/add-hash-mode
✨ Add hash mode compatibility
2 parents 8d168d7 + f36a4f7 commit 7c5bfa7

File tree

12 files changed

+221
-59
lines changed

12 files changed

+221
-59
lines changed

api/v1alpha1/clusterstack_types.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ type ClusterStackSpec struct {
3939

4040
// Channel specifies the release channel of the cluster stack. Defaults to 'stable'.
4141
// +kubebuilder:default:=stable
42-
// +kubebuilder:validation:enum=stable;alpha;beta;rc
42+
// +kubebuilder:validation:Enum=stable;custom
4343
Channel version.Channel `json:"channel,omitempty"`
4444

4545
// Versions is a list of version of the cluster stack that should be available in the management cluster.

config/crd/bases/clusterstack.x-k8s.io_clusterstacks.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ spec:
7575
default: stable
7676
description: Channel specifies the release channel of the cluster
7777
stack. Defaults to 'stable'.
78+
enum:
79+
- stable
80+
- custom
7881
type: string
7982
kubernetesVersion:
8083
description: KubernetesVersion is the Kubernetes version in the format

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ require (
9696
google.golang.org/protobuf v1.31.0 // indirect
9797
gopkg.in/inf.v0 v0.9.1 // indirect
9898
gopkg.in/yaml.v2 v2.4.0
99-
gopkg.in/yaml.v3 v3.0.1 // indirect
99+
gopkg.in/yaml.v3 v3.0.1
100100
k8s.io/apiextensions-apiserver v0.27.2
101101
k8s.io/apiserver v0.27.2 // indirect
102102
k8s.io/component-base v0.27.2 // indirect

hack/kind-dev.sh

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,29 +24,26 @@ REPO_ROOT=$(git rev-parse --show-toplevel)
2424
cd "${REPO_ROOT}" || exit 1
2525

2626
# Creates a kind cluster with the ctlptl tool https://github.com/tilt-dev/ctlptl
27-
ctlptl_kind-cluster-with-registry () {
28-
29-
local CLUSTER_NAME=$1
30-
local CLUSTER_VERSION=$2
27+
ctlptl_kind-cluster-with-registry() {
3128

32-
cat <<EOF | ctlptl apply -f -
29+
local CLUSTER_NAME=$1
30+
local CLUSTER_VERSION=$2
31+
32+
cat <<EOF | ctlptl apply -f -
3333
apiVersion: ctlptl.dev/v1alpha1
3434
kind: Registry
35-
name: ${CLUSTER_NAME}-registry
35+
name: kind-registry
3636
port: 5000
3737
---
3838
apiVersion: ctlptl.dev/v1alpha1
3939
kind: Cluster
4040
product: kind
41-
registry: ${CLUSTER_NAME}-registry
41+
registry: kind-registry
4242
kindV1Alpha4Cluster:
4343
name: ${CLUSTER_NAME}
4444
nodes:
4545
- role: control-plane
4646
image: kindest/node:${CLUSTER_VERSION}
47-
extraMounts:
48-
- hostPath: /var/run/docker.sock
49-
containerPath: /var/run/docker.sock
5047
networking:
5148
podSubnet: "10.244.0.0/16"
5249
serviceSubnet: "10.96.0.0/12"
@@ -64,4 +61,4 @@ ctlptl_kind-cluster-with-registry cso ${K8S_VERSION}
6461
echo ""
6562
echo ""
6663
echo ""
67-
echo "Cluster is ready - you can now tilt up!"
64+
echo "Cluster is ready - you can now tilt up!"

internal/clusterstackrelease/util.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import (
2727

2828
// Summary returns a ClusterStackReleaseSummary object from a clusterStackRelease.
2929
func Summary(csr *csov1alpha1.ClusterStackRelease) (csov1alpha1.ClusterStackReleaseSummary, error) {
30-
clusterStack, err := clusterstack.NewFromString(csr.Name)
30+
clusterStack, err := clusterstack.NewFromClusterStackReleaseProperties(csr.Name)
3131
if err != nil {
3232
return csov1alpha1.ClusterStackReleaseSummary{}, fmt.Errorf("failed to create clusterStack from string %s: %w", csr.Name, err)
3333
}

internal/controller/clusteraddon_controller.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ func (r *ClusterAddonReconciler) Reconcile(ctx context.Context, req reconcile.Re
152152
// cluster is ready, so we set a condition and can continue as well
153153
conditions.MarkTrue(clusterAddon, csov1alpha1.ClusterReadyCondition)
154154

155-
releaseAsset, download, err := release.New(cluster.Spec.Topology.Class, r.ReleaseDirectory)
155+
releaseAsset, download, err := release.New(release.ConvertFromClusterClassToClusterStackFormat(cluster.Spec.Topology.Class), r.ReleaseDirectory)
156156
if err != nil {
157157
conditions.MarkFalse(clusterAddon, csov1alpha1.ClusterStackReleaseAssetsReadyCondition, csov1alpha1.IssueWithReleaseAssetsReason, clusterv1.ConditionSeverityError, err.Error())
158158
return ctrl.Result{RequeueAfter: 10 * time.Second}, nil

internal/controller/clusterstack_controller.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -509,7 +509,7 @@ func getLatestReadyClusterStackRelease(clusterStackReleases []*csov1alpha1.Clust
509509
// filter the ones that are ready
510510
for _, csr := range clusterStackReleases {
511511
if csr.Status.Ready {
512-
cs, err := clusterstack.NewFromString(csr.Name)
512+
cs, err := clusterstack.NewFromClusterStackReleaseProperties(csr.Name)
513513
if err != nil {
514514
return nil, "", fmt.Errorf("failed to get clusterstack from ClusterStackRelease.Name %q: %w", csr.Name, err)
515515
}
@@ -624,7 +624,7 @@ func matchesOwnerRef(a *metav1.OwnerReference, clusterStack *csov1alpha1.Cluster
624624
}
625625

626626
func matchesSpec(str string, spec *csov1alpha1.ClusterStackSpec) (clusterstack.ClusterStack, bool, error) {
627-
csObject, err := clusterstack.NewFromString(str)
627+
csObject, err := clusterstack.NewFromClusterStackReleaseProperties(str)
628628
if err != nil {
629629
return clusterstack.ClusterStack{}, false, fmt.Errorf("failed to get clusterstack object from string %q: %w", str, err)
630630
}

internal/controller/clusterstack_controller_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,7 @@ func TestGetClusterStackReleasesInSpec(t *testing.T) {
357357
Provider: "docker",
358358
Name: "ferrol",
359359
KubernetesVersion: "1.21",
360-
Versions: []string{"v1", "v2", "v3-alpha-0"},
360+
Versions: []string{"v1", "v2", "v3-alpha.0"},
361361
}
362362

363363
result, err := getClusterStackReleasesInSpec(spec)

pkg/clusterstack/clusterstack.go

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,57 @@ var (
5555
ErrInvalidName = fmt.Errorf("invalid name")
5656
)
5757

58-
// NewFromString returns a ClusterStack based on a cluster stack string.
59-
func NewFromString(str string) (ClusterStack, error) {
58+
// NewFromClusterClassProperties returns a ClusterStack based on a cluster stack string.
59+
// e.g. - "docker-ferrol-1-27-v1", "docker-ferrol-1-27-v1-alpha.1", etc.
60+
func NewFromClusterClassProperties(str string) (ClusterStack, error) {
61+
splitted := strings.Split(str, Separator)
62+
if len(splitted) != 5 && len(splitted) != 6 {
63+
return ClusterStack{}, ErrInvalidFormat
64+
}
65+
66+
clusterStack := ClusterStack{
67+
Provider: splitted[0],
68+
Name: splitted[1],
69+
}
70+
71+
if clusterStack.Provider == "" {
72+
return ClusterStack{}, ErrInvalidProvider
73+
}
74+
75+
if clusterStack.Name == "" {
76+
return ClusterStack{}, ErrInvalidName
77+
}
78+
79+
var err error
80+
81+
clusterStack.KubernetesVersion, err = kubernetesversion.New(splitted[2], splitted[3])
82+
if err != nil {
83+
return ClusterStack{}, fmt.Errorf("failed to create Kubernetes version from %s-%s: %w", splitted[2], splitted[3], err)
84+
}
85+
86+
var versionString string
87+
if len(splitted) == 5 {
88+
// e.g. myprovider-myclusterstack-1-26-v1
89+
versionString = splitted[4]
90+
} else if len(splitted) == 6 {
91+
// e.g. myprovider-myclusterstack-1-26-v1-alpha.0
92+
versionString = strings.Join(splitted[4:6], Separator)
93+
}
94+
95+
// version string like v1-alpha.0
96+
v, err := version.New(versionString)
97+
if err != nil {
98+
return ClusterStack{}, fmt.Errorf("failed to create version from %s: %w", versionString, err)
99+
}
100+
101+
clusterStack.Version = v
102+
103+
return clusterStack, nil
104+
}
105+
106+
// NewFromClusterStackReleaseProperties returns a ClusterStack based on a cluster stack string.
107+
// e.g. - "docker-ferrol-1-27-v1", "docker-ferrol-1-27-v1-alpha-1", etc.
108+
func NewFromClusterStackReleaseProperties(str string) (ClusterStack, error) {
60109
splitted := strings.Split(str, Separator)
61110
if len(splitted) != 5 && len(splitted) != 7 {
62111
return ClusterStack{}, ErrInvalidFormat
@@ -91,7 +140,8 @@ func NewFromString(str string) (ClusterStack, error) {
91140
versionString = strings.Join(splitted[4:7], Separator)
92141
}
93142

94-
v, err := version.New(versionString)
143+
// version string like v1-alpha-0
144+
v, err := version.ParseVersionString(versionString)
95145
if err != nil {
96146
return ClusterStack{}, fmt.Errorf("failed to create version from %s: %w", versionString, err)
97147
}
@@ -101,7 +151,8 @@ func NewFromString(str string) (ClusterStack, error) {
101151
return clusterStack, nil
102152
}
103153

104-
// New returns a ClusterStack based on a cluster stack string.
154+
// New returns a ClusterStack based on a cluster stack properties and the version is in the form of -
155+
// "v1", "v1-alpha.1", etc.
105156
func New(provider, name, kubernetesVersion, csVersion string) (ClusterStack, error) {
106157
k8sVersion, err := kubernetesversion.NewFromString(kubernetesVersion)
107158
if err != nil {

pkg/release/release.go

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ import (
2424
"strings"
2525

2626
"github.com/SovereignCloudStack/cluster-stack-operator/pkg/clusterstack"
27-
"gopkg.in/yaml.v2"
27+
"github.com/SovereignCloudStack/cluster-stack-operator/pkg/version"
28+
"gopkg.in/yaml.v3"
2829
)
2930

3031
// Release contains information for ClusterStack release.
@@ -57,8 +58,9 @@ const (
5758
func New(tag, downloadPath string) (Release, bool, error) {
5859
// downloadPath is the path where the release is downloaded.
5960
// The path is of the form: <downloadPath>/<clusterStackSuffix>/<tag>/
61+
// For example: /tmp/downloads/cluster-stacks/docker-ferrol-1-26-v2/
6062
downloadPath = filepath.Join(downloadPath, clusterStackSuffix, tag)
61-
cs, err := clusterstack.NewFromString(tag)
63+
cs, err := clusterstack.NewFromClusterStackReleaseProperties(tag)
6264
if err != nil {
6365
return Release{}, false, fmt.Errorf("failed to parse cluster stack release: %w", err)
6466
}
@@ -92,6 +94,18 @@ func New(tag, downloadPath string) (Release, bool, error) {
9294
return rel, false, nil
9395
}
9496

97+
// ConvertFromClusterClassToClusterStackFormat converts `docker-ferrol-1-27-v0-sha.3960147` way to
98+
// `docker-ferrol-1-27-v0-sha-3960147`.
99+
func ConvertFromClusterClassToClusterStackFormat(input string) string {
100+
parts := strings.Split(input, ".")
101+
102+
if len(parts) == 2 {
103+
return fmt.Sprintf("%s-%s", parts[0], parts[1])
104+
}
105+
106+
return input
107+
}
108+
95109
func ensureMetadata(downloadPath, metadataFileName string) (Metadata, error) {
96110
// Read the metadata.yaml file from the release.
97111
metadataPath := filepath.Join(downloadPath, metadataFileName)
@@ -107,6 +121,25 @@ func ensureMetadata(downloadPath, metadataFileName string) (Metadata, error) {
107121
return Metadata{}, fmt.Errorf("failed to unmarshal metadata: %w", err)
108122
}
109123

124+
// Normalize the versions of metadata from v1-alpha.1 to v1-alpha-1 format.
125+
metaClusterStackVersion, err := version.New(metadata.Versions.ClusterStack)
126+
if err != nil {
127+
return Metadata{}, fmt.Errorf("failed to parse ClusterStack version from metadata: %w", err)
128+
}
129+
metadata.Versions.ClusterStack = metaClusterStackVersion.String()
130+
131+
metaClusterAddonVersion, err := version.New(metadata.Versions.Components.ClusterAddon)
132+
if err != nil {
133+
return Metadata{}, fmt.Errorf("failed to parse ClusterAddon version from metadata: %w", err)
134+
}
135+
metadata.Versions.Components.ClusterAddon = metaClusterAddonVersion.String()
136+
137+
metaNodeImageVersion, err := version.New(metadata.Versions.Components.NodeImage)
138+
if err != nil {
139+
return Metadata{}, fmt.Errorf("failed to parse NodeImage version from metadata: %w", err)
140+
}
141+
metadata.Versions.Components.NodeImage = metaNodeImageVersion.String()
142+
110143
return metadata, nil
111144
}
112145

@@ -165,13 +198,15 @@ func (r *Release) Validate() error {
165198

166199
// clusterAddonChartName returns the helm chart name for cluster addon.
167200
func (r *Release) clusterAddonChartName() string {
168-
return fmt.Sprintf("%s-%s-%s-cluster-addon-%s", r.ClusterStack.Provider, r.ClusterStack.Name, r.ClusterStack.KubernetesVersion, r.Meta.Versions.Components.ClusterAddon)
201+
clusterAddonVersion, _ := version.ParseVersionString(r.Meta.Versions.Components.ClusterAddon)
202+
return fmt.Sprintf("%s-%s-%s-cluster-addon-%s", r.ClusterStack.Provider, r.ClusterStack.Name, r.ClusterStack.KubernetesVersion, clusterAddonVersion.StringWithDot())
169203
}
170204

171205
// ClusterAddonChartPath returns the helm chart name from the given path.
172206
func (r *Release) ClusterAddonChartPath() string {
173207
// we ignore the error here, since we already checked for the presence of the chart.
174-
path, _ := r.helmChartNamePath(r.clusterAddonChartName())
208+
name := r.clusterAddonChartName()
209+
path, _ := r.helmChartNamePath(name)
175210
return path
176211
}
177212

@@ -182,7 +217,7 @@ func (r *Release) ClusterAddonValuesPath() string {
182217

183218
// clusterClassChartName returns the helm chart name for cluster class.
184219
func (r *Release) clusterClassChartName() string {
185-
return fmt.Sprintf("%s-%s-%s-cluster-class-%s", r.ClusterStack.Provider, r.ClusterStack.Name, r.ClusterStack.KubernetesVersion, r.ClusterStack.Version.String())
220+
return fmt.Sprintf("%s-%s-%s-cluster-class-%s", r.ClusterStack.Provider, r.ClusterStack.Name, r.ClusterStack.KubernetesVersion, r.ClusterStack.Version.StringWithDot())
186221
}
187222

188223
// ClusterClassChartPath returns the absolute helm chart path for cluster class.

0 commit comments

Comments
 (0)