Skip to content

Commit 5d1b64a

Browse files
author
Aniruddha Basak
authored
Support new Cluster stack convention (#104)
New cluster stack has multi stage cluster addon which has clusteraddon.yaml in their release assets Signed-off-by: Aniruddha Basak <[email protected]>
1 parent 8549aad commit 5d1b64a

31 files changed

+852
-46
lines changed

pkg/clusterstack/config.go

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -45,45 +45,45 @@ type CsctlConfig struct {
4545
}
4646

4747
// GetCsctlConfig returns CsctlConfig.
48-
func GetCsctlConfig(path string) (CsctlConfig, error) {
48+
func GetCsctlConfig(path string) (*CsctlConfig, error) {
4949
configPath := filepath.Join(path, "csctl.yaml")
5050
configFileData, err := os.ReadFile(filepath.Clean(configPath))
5151
if err != nil {
52-
return CsctlConfig{}, fmt.Errorf("failed to read csctl config: %w", err)
52+
return nil, fmt.Errorf("failed to read csctl config: %w", err)
5353
}
5454

55-
cs := CsctlConfig{}
55+
cs := &CsctlConfig{}
5656
if err := yaml.Unmarshal(configFileData, &cs); err != nil {
57-
return CsctlConfig{}, fmt.Errorf("failed to unmarshal csctl yaml: %w", err)
57+
return nil, fmt.Errorf("failed to unmarshal csctl yaml: %w", err)
5858
}
5959

6060
if cs.Config.Provider.Type == "" {
61-
return CsctlConfig{}, fmt.Errorf("provider type must not be empty")
61+
return nil, fmt.Errorf("provider type must not be empty")
6262
}
6363

6464
if len(cs.Config.Provider.Type) > 253 {
65-
return CsctlConfig{}, fmt.Errorf("provider name must not be greater than 253")
65+
return nil, fmt.Errorf("provider name must not be greater than 253")
6666
}
6767

6868
match, err := regexp.MatchString(`^[a-z0-9]([-a-z0-9]*[a-z0-9])?$`, cs.Config.Provider.Type)
6969
if err != nil {
70-
return CsctlConfig{}, fmt.Errorf("failed to provider name match regex: %w", err)
70+
return nil, fmt.Errorf("failed to provider name match regex: %w", err)
7171
}
7272
if !match {
73-
return CsctlConfig{}, fmt.Errorf("invalid provider type: %q", cs.Config.Provider.Type)
73+
return nil, fmt.Errorf("invalid provider type: %q", cs.Config.Provider.Type)
7474
}
7575

7676
if cs.Config.ClusterStackName == "" {
77-
return CsctlConfig{}, fmt.Errorf("cluster stack name must not be empty")
77+
return nil, fmt.Errorf("cluster stack name must not be empty")
7878
}
7979

8080
// Validate kubernetes version
8181
matched, err := regexp.MatchString(`^v\d+\.\d+\.\d+$`, cs.Config.KubernetesVersion)
8282
if err != nil {
83-
return CsctlConfig{}, fmt.Errorf("failed to kubernetes match regex: %w", err)
83+
return nil, fmt.Errorf("failed to kubernetes match regex: %w", err)
8484
}
8585
if !matched {
86-
return CsctlConfig{}, fmt.Errorf("invalid kubernetes version: %q", cs.Config.KubernetesVersion)
86+
return nil, fmt.Errorf("invalid kubernetes version: %q", cs.Config.KubernetesVersion)
8787
}
8888

8989
return cs, nil

pkg/clusterstack/metadata.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,17 +44,17 @@ type MetaData struct {
4444
}
4545

4646
// ParseMetaData parse the metadata file.
47-
func ParseMetaData(path string) (MetaData, error) {
47+
func ParseMetaData(path string) (*MetaData, error) {
4848
metadataPath := filepath.Join(path, "metadata.yaml")
4949
fileInfo, err := os.ReadFile(filepath.Clean(metadataPath))
5050
if err != nil {
51-
return MetaData{}, fmt.Errorf("failed to read metadata file: %w", err)
51+
return nil, fmt.Errorf("failed to read metadata file: %w", err)
5252
}
5353

54-
metaData := MetaData{}
54+
metaData := &MetaData{}
5555

5656
if err := yaml.Unmarshal(fileInfo, &metaData); err != nil {
57-
return MetaData{}, fmt.Errorf("failed to unmarshal metadata yaml: %w", err)
57+
return nil, fmt.Errorf("failed to unmarshal metadata yaml: %w", err)
5858
}
5959

6060
return metaData, nil

pkg/clusterstack/mode.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,22 +24,22 @@ import (
2424
)
2525

2626
// HandleStableMode returns metadata for the stable mode.
27-
func HandleStableMode(gitHubReleasePath string, currentReleaseHash, latestReleaseHash hash.ReleaseHash) (MetaData, error) {
27+
func HandleStableMode(gitHubReleasePath string, currentReleaseHash, latestReleaseHash hash.ReleaseHash) (*MetaData, error) {
2828
metadata, err := ParseMetaData(gitHubReleasePath)
2929
if err != nil {
30-
return MetaData{}, fmt.Errorf("failed to parse metadata: %w", err)
30+
return nil, fmt.Errorf("failed to parse metadata: %w", err)
3131
}
3232

3333
metadata.Versions.ClusterStack, err = BumpVersion(metadata.Versions.ClusterStack)
3434
if err != nil {
35-
return MetaData{}, fmt.Errorf("failed to bump cluster stack: %w", err)
35+
return nil, fmt.Errorf("failed to bump cluster stack: %w", err)
3636
}
3737
fmt.Printf("Bumped ClusterStack Version: %s\n", metadata.Versions.ClusterStack)
3838

3939
if currentReleaseHash.ClusterAddonDir != latestReleaseHash.ClusterAddonDir || currentReleaseHash.ClusterAddonValues != latestReleaseHash.ClusterAddonValues {
4040
metadata.Versions.Components.ClusterAddon, err = BumpVersion(metadata.Versions.Components.ClusterAddon)
4141
if err != nil {
42-
return MetaData{}, fmt.Errorf("failed to bump cluster addon: %w", err)
42+
return nil, fmt.Errorf("failed to bump cluster addon: %w", err)
4343
}
4444
fmt.Printf("Bumped ClusterAddon Version: %s\n", metadata.Versions.Components.ClusterAddon)
4545
} else {
@@ -49,7 +49,7 @@ func HandleStableMode(gitHubReleasePath string, currentReleaseHash, latestReleas
4949
if currentReleaseHash.NodeImageDir != latestReleaseHash.NodeImageDir {
5050
metadata.Versions.Components.NodeImage, err = BumpVersion(metadata.Versions.Components.NodeImage)
5151
if err != nil {
52-
return MetaData{}, fmt.Errorf("failed to bump node image: %w", err)
52+
return nil, fmt.Errorf("failed to bump node image: %w", err)
5353
}
5454
fmt.Printf("Bumped NodeImage Version: %s\n", metadata.Versions.Components.NodeImage)
5555
} else {
@@ -64,15 +64,15 @@ func HandleStableMode(gitHubReleasePath string, currentReleaseHash, latestReleas
6464
}
6565

6666
// HandleHashMode returns metadata of Hash mode.
67-
func HandleHashMode(kubernetesVersion string) (MetaData, error) {
67+
func HandleHashMode(kubernetesVersion string) (*MetaData, error) {
6868
commitHash, err := git.GetLatestGitCommit("./")
6969
if err != nil {
70-
return MetaData{}, fmt.Errorf("failed to get latest commit hash: %w", err)
70+
return nil, fmt.Errorf("failed to get latest commit hash: %w", err)
7171
}
7272

7373
commitHash = fmt.Sprintf("v0-sha.%s", commitHash)
7474

75-
return MetaData{
75+
return &MetaData{
7676
APIVersion: "metadata.clusterstack.x-k8s.io/v1alpha1",
7777
Versions: Versions{
7878
Kubernetes: kubernetesVersion,

pkg/cmd/create.go

Lines changed: 43 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,14 @@ var (
5858

5959
// CreateOptions contains config for creating a release.
6060
type CreateOptions struct {
61-
ClusterStackPath string
62-
ClusterStackReleaseDir string
63-
Config clusterstack.CsctlConfig
64-
Metadata clusterstack.MetaData
65-
CurrentReleaseHash hash.ReleaseHash
66-
LatestReleaseHash hash.ReleaseHash
67-
NodeImageRegistry string
61+
newClusterStackConvention bool
62+
ClusterStackPath string
63+
ClusterStackReleaseDir string
64+
Config *clusterstack.CsctlConfig
65+
Metadata *clusterstack.MetaData
66+
CurrentReleaseHash hash.ReleaseHash
67+
LatestReleaseHash hash.ReleaseHash
68+
NodeImageRegistry string
6869
}
6970

7071
// createCmd represents the create command.
@@ -95,7 +96,17 @@ func GetCreateOptions(ctx context.Context, clusterStackPath string) (*CreateOpti
9596
createOption.ClusterStackPath = clusterStackPath
9697
createOption.Config = config
9798

98-
_, _, err = providerplugin.GetProviderExecutable(&config)
99+
if _, err := os.Stat(filepath.Join(clusterStackPath, "clusteraddon.yaml")); err != nil {
100+
// old if clusteraddon.yaml is not present.
101+
if !os.IsNotExist(err) {
102+
return nil, fmt.Errorf("failed to find clusteraddon.yaml: %w", err)
103+
}
104+
} else {
105+
// new if clusteraddon.yaml is present.
106+
createOption.newClusterStackConvention = true
107+
}
108+
109+
_, _, err = providerplugin.GetProviderExecutable(config)
99110
if err != nil {
100111
return createOption, fmt.Errorf("providerplugin.GetProviderExecutable(&config) failed: %w", err)
101112
}
@@ -121,7 +132,7 @@ func GetCreateOptions(ctx context.Context, clusterStackPath string) (*CreateOpti
121132
// update the metadata kubernetes version with the csctl.yaml config
122133
createOption.Metadata.Versions.Kubernetes = config.Config.KubernetesVersion
123134

124-
latestRepoRelease, err := github.GetLatestReleaseFromRemoteRepository(ctx, mode, &config, gc)
135+
latestRepoRelease, err := github.GetLatestReleaseFromRemoteRepository(ctx, mode, config, gc)
125136
if err != nil {
126137
return nil, fmt.Errorf("failed to get latest release form remote repository: %w", err)
127138
}
@@ -144,7 +155,7 @@ func GetCreateOptions(ctx context.Context, clusterStackPath string) (*CreateOpti
144155
}
145156
}
146157

147-
releaseDirName, err := clusterstack.GetClusterStackReleaseDirectoryName(&createOption.Metadata, &createOption.Config)
158+
releaseDirName, err := clusterstack.GetClusterStackReleaseDirectoryName(createOption.Metadata, createOption.Config)
148159
if err != nil {
149160
return nil, fmt.Errorf("failed to get cluster stack release directory name: %w", err)
150161
}
@@ -222,7 +233,7 @@ func (c *CreateOptions) generateRelease() error {
222233
}
223234

224235
// Build all the templated output and put it in a tmp directory
225-
if err := template.GenerateOutputFromTemplate(c.ClusterStackPath, "./.tmp/", &c.Metadata); err != nil {
236+
if err := template.GenerateOutputFromTemplate(c.ClusterStackPath, "./.tmp/", c.Metadata); err != nil {
226237
return fmt.Errorf("failed to generate tmp output: %w", err)
227238
}
228239

@@ -238,18 +249,30 @@ func (c *CreateOptions) generateRelease() error {
238249
}
239250

240251
// Package Helm from the tmp directory to the release directory
241-
if err := template.CreatePackage("./.tmp/", c.ClusterStackReleaseDir); err != nil {
252+
if err := template.CreatePackage("./.tmp/", c.ClusterStackReleaseDir, c.newClusterStackConvention, c.Config, c.Metadata); err != nil {
242253
return fmt.Errorf("failed to create template package: %w", err)
243254
}
244255

245-
// Copy the cluster-addon-values.yaml config to release if old way
246-
clusterAddonData, err := os.ReadFile(filepath.Join(c.ClusterStackPath, "cluster-addon-values.yaml"))
247-
if err != nil {
248-
return fmt.Errorf("failed to read cluster-addon-values.yaml: %w", err)
249-
}
256+
if c.newClusterStackConvention {
257+
// Copy the clusteraddon.yaml config to release if new way
258+
clusterAddonData, err := os.ReadFile(filepath.Join(c.ClusterStackPath, "clusteraddon.yaml"))
259+
if err != nil {
260+
return fmt.Errorf("failed to read clusteraddon.yaml: %w", err)
261+
}
262+
263+
if err := os.WriteFile(filepath.Join(c.ClusterStackReleaseDir, "clusteraddon.yaml"), clusterAddonData, os.FileMode(0o644)); err != nil {
264+
return fmt.Errorf("failed to write clusteraddon.yaml: %w", err)
265+
}
266+
} else {
267+
// Copy the cluster-addon-values.yaml config to release if old way
268+
clusterAddonData, err := os.ReadFile(filepath.Join(c.ClusterStackPath, "cluster-addon-values.yaml"))
269+
if err != nil {
270+
return fmt.Errorf("failed to read cluster-addon-values.yaml: %w", err)
271+
}
250272

251-
if err := os.WriteFile(filepath.Join(c.ClusterStackReleaseDir, "cluster-addon-values.yaml"), clusterAddonData, os.FileMode(0o644)); err != nil {
252-
return fmt.Errorf("failed to write cluster-addon-values.yaml: %w", err)
273+
if err := os.WriteFile(filepath.Join(c.ClusterStackReleaseDir, "cluster-addon-values.yaml"), clusterAddonData, os.FileMode(0o644)); err != nil {
274+
return fmt.Errorf("failed to write cluster-addon-values.yaml: %w", err)
275+
}
253276
}
254277

255278
// Put the final metadata file into the output directory.
@@ -268,7 +291,7 @@ func (c *CreateOptions) generateRelease() error {
268291
return fmt.Errorf("failed to write metadata: %w", err)
269292
}
270293

271-
err = providerplugin.CreateNodeImages(&c.Config,
294+
err = providerplugin.CreateNodeImages(c.Config,
272295
c.ClusterStackPath,
273296
c.ClusterStackReleaseDir,
274297
c.NodeImageRegistry)

pkg/template/package.go

Lines changed: 84 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,40 @@ limitations under the License.
1717
package template
1818

1919
import (
20+
"archive/tar"
21+
"compress/gzip"
2022
"fmt"
23+
"io"
24+
"io/fs"
25+
"os"
2126
"path/filepath"
2227

28+
"github.com/SovereignCloudStack/csctl/pkg/clusterstack"
2329
"helm.sh/helm/v3/pkg/action"
2430
)
2531

2632
// CreatePackage creates the package for release.
27-
func CreatePackage(src, dst string) error {
33+
func CreatePackage(src, dst string, newType bool, config *clusterstack.CsctlConfig, metadata *clusterstack.MetaData) error {
34+
fmt.Printf("path now: %q\n", filepath.Join(src, "cluster-class"))
2835
if err := createHelmPackage(filepath.Join(src, "cluster-class"), dst); err != nil {
2936
return fmt.Errorf("failed to create package for ClusterClass: %w", err)
3037
}
3138

32-
if err := createHelmPackage(filepath.Join(src, "cluster-addon"), dst); err != nil {
33-
return fmt.Errorf("failed to create package for ClusterAddon: %w", err)
39+
kubernetesVerion, err := config.ParseKubernetesVersion()
40+
if err != nil {
41+
return fmt.Errorf("failed to parse kubernetes version: %w", err)
42+
}
43+
44+
if newType {
45+
clusterAddonDst := filepath.Join(dst, fmt.Sprintf("%s-%s-%s-cluster-addon-%s.tgz", config.Config.Provider.Type, config.Config.ClusterStackName, kubernetesVerion.String(), metadata.Versions.Components.ClusterAddon))
46+
if err := createTarPackage(filepath.Join(src, "cluster-addon"), clusterAddonDst); err != nil {
47+
return fmt.Errorf("failed to create package for ClusterAddon: %w", err)
48+
}
49+
} else {
50+
fmt.Printf("path now: %q\n", filepath.Join(src, "cluster-addon"))
51+
if err := createHelmPackage(filepath.Join(src, "cluster-addon"), dst); err != nil {
52+
return fmt.Errorf("failed to create helm package for ClusterAddon: %w", err)
53+
}
3454
}
3555

3656
return nil
@@ -47,3 +67,64 @@ func createHelmPackage(src, dst string) error {
4767

4868
return nil
4969
}
70+
71+
func createTarPackage(src, dst string) error {
72+
outFile, err := os.Create(filepath.Clean(dst))
73+
if err != nil {
74+
return fmt.Errorf("failed to create tar output destination directory: %w", err)
75+
}
76+
defer outFile.Close()
77+
78+
gw := gzip.NewWriter(outFile)
79+
defer gw.Close()
80+
81+
tw := tar.NewWriter(gw)
82+
defer tw.Close()
83+
84+
if err := filepath.Walk(src, func(path string, info fs.FileInfo, err error) error {
85+
if err != nil {
86+
return err
87+
}
88+
89+
// Ignore the root folder itself
90+
if path == src {
91+
return nil
92+
}
93+
94+
relPath, err := filepath.Rel(src, path)
95+
if err != nil {
96+
return fmt.Errorf("failed to calculate relative path of source: %q and destination: %q directory: %w", src, dst, err)
97+
}
98+
99+
// Use filepath.ToSlash to convert path separators to '/'
100+
relPath = filepath.ToSlash(relPath)
101+
102+
header, err := tar.FileInfoHeader(info, relPath)
103+
if err != nil {
104+
return fmt.Errorf("failed to get the tar info header: %w", err)
105+
}
106+
header.Name = relPath
107+
108+
if err := tw.WriteHeader(header); err != nil {
109+
return fmt.Errorf("failed to set the write header: %w", err)
110+
}
111+
112+
if !info.IsDir() {
113+
file, err := os.Open(filepath.Clean(path))
114+
if err != nil {
115+
return fmt.Errorf("failed to open path: %w", err)
116+
}
117+
defer file.Close()
118+
119+
if _, err := io.Copy(tw, file); err != nil {
120+
return fmt.Errorf("failed to copy file: %w", err)
121+
}
122+
}
123+
124+
return nil
125+
}); err != nil {
126+
return fmt.Errorf("failed to walk on the source directory: %w", err)
127+
}
128+
129+
return nil
130+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
apiVersion: v2
2+
type: application
3+
description: CNI chart for kind
4+
name: CNI
5+
version: '0'
6+
maintainers:
7+
- name: Syself
8+
9+
url: https://github.com/syself

0 commit comments

Comments
 (0)