Skip to content

Commit a0b0203

Browse files
Add openstack plugin for csctl
Signed-off-by: michal.gubricky <michal.gubricky@dnation.cloud>
1 parent 6c66209 commit a0b0203

File tree

7 files changed

+167
-7
lines changed

7 files changed

+167
-7
lines changed

.builder-image-version.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.2.4
1+
0.2.0

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,6 @@ temp
1717
# build and release
1818
dist
1919
csctl
20+
csctl-openstack
2021
tmp/
2122
releases/

Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ clean: ## cleans the csmctl binary
5858
##########
5959
.PHONY: build
6060
build: # build the csmctl binary
61-
go build -ldflags "$(LDFLAGS)" -o csmctl main.go
61+
go build -ldflags "$(LDFLAGS)" -o csctl main.go
62+
go build -o csctl-openstack csctlopenstack/csctlopenstack_main.go
6263

6364
.PHONY: lint-golang
6465
lint-golang: ## Lint Golang codebase
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
Copyright 2024 The Kubernetes Authors.
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
http://www.apache.org/licenses/LICENSE-2.0
7+
Unless required by applicable law or agreed to in writing, software
8+
distributed under the License is distributed on an "AS IS" BASIS,
9+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
See the License for the specific language governing permissions and
11+
limitations under the License.
12+
*/
13+
14+
// Package main provides a dummy plugin for csctl. You can use that code
15+
// to create a real csctl plugin.
16+
// You can implement the "create-node-images" command to create node images during
17+
// a `csclt create` call.
18+
package main
19+
20+
import (
21+
"fmt"
22+
"os"
23+
"path/filepath"
24+
25+
csctlclusterstack "github.com/SovereignCloudStack/csctl/pkg/clusterstack"
26+
)
27+
28+
const provider = "openstack"
29+
30+
func usage() {
31+
fmt.Printf(`%s create-node-images cluster-stack-directory cluster-stack-release-directory
32+
This command is a csctl plugin.
33+
https://github.com/SovereignCloudStack/csctl
34+
`, os.Args[0])
35+
}
36+
37+
func main() {
38+
if len(os.Args) != 4 {
39+
usage()
40+
os.Exit(1)
41+
}
42+
if os.Args[1] != "create-node-images" {
43+
usage()
44+
os.Exit(1)
45+
}
46+
clusterStackPath := os.Args[2]
47+
config, err := csctlclusterstack.GetCsctlConfig(clusterStackPath)
48+
if err != nil {
49+
fmt.Println(err.Error())
50+
os.Exit(1)
51+
}
52+
if config.Config.Provider.Type != provider {
53+
fmt.Printf("Wrong provider in %s. Expected %s\n", clusterStackPath, provider)
54+
os.Exit(1)
55+
}
56+
releaseDir := os.Args[3]
57+
_, err = os.Stat(releaseDir)
58+
if err != nil {
59+
fmt.Println(err.Error())
60+
os.Exit(1)
61+
}
62+
if config.Config.Provider.Config.Method == "get" {
63+
nodeImageData, err := os.ReadFile(filepath.Join(clusterStackPath, "node-images", "config.yaml"))
64+
if err != nil {
65+
fmt.Println("failed to read config.yaml: %w", err)
66+
os.Exit(1)
67+
}
68+
69+
if err := os.WriteFile(filepath.Join(releaseDir, "node-images.yaml"), nodeImageData, os.FileMode(0o644)); err != nil {
70+
fmt.Println("failed to write config.yaml: %w", err)
71+
os.Exit(1)
72+
}
73+
}
74+
if config.Config.Provider.Config.Method == "build" {
75+
fmt.Println(".... pretending to do heavy work (creating node images) ...")
76+
}
77+
}

pkg/clusterstack/config.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,11 @@ type CsctlConfig struct {
3737
KubernetesVersion string `yaml:"kubernetesVersion"`
3838
ClusterStackName string `yaml:"clusterStackName"`
3939
Provider struct {
40-
Type string `yaml:"type"`
41-
APIVersion string `yaml:"apiVersion"`
42-
Config struct{} `yaml:"config"`
40+
Type string `yaml:"type"`
41+
APIVersion string `yaml:"apiVersion"`
42+
Config struct {
43+
Method string `yaml:"method"`
44+
} `yaml:"config"`
4345
} `yaml:"provider"`
4446
} `yaml:"config"`
4547
}

pkg/cmd/create.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
"github.com/SovereignCloudStack/csctl/pkg/github"
2828
"github.com/SovereignCloudStack/csctl/pkg/github/client"
2929
"github.com/SovereignCloudStack/csctl/pkg/hash"
30+
"github.com/SovereignCloudStack/csctl/pkg/providerplugin"
3031
"github.com/SovereignCloudStack/csctl/pkg/template"
3132
"github.com/spf13/cobra"
3233
"gopkg.in/yaml.v3"
@@ -109,7 +110,7 @@ func GetCreateOptions(ctx context.Context, clusterStackPath string) (*CreateOpti
109110
return nil, fmt.Errorf("failed to create new github client: %w", err)
110111
}
111112

112-
// update the metadata kubernetes version with the csmctl.yaml config
113+
// update the metadata kubernetes version with the csctl.yaml config
113114
createOption.Metadata.Versions.Kubernetes = config.Config.KubernetesVersion
114115

115116
latestRepoRelease, err := github.GetLatestReleaseFromRemoteRepository(ctx, mode, &config, gc)
@@ -156,6 +157,16 @@ func createAction(cmd *cobra.Command, args []string) error {
156157
return fmt.Errorf("mode is not supported please choose from - stable, hash")
157158
}
158159

160+
// Get csctl config form cluster stacks.
161+
config, err := clusterstack.GetCsctlConfig(clusterStackPath)
162+
if err != nil {
163+
return fmt.Errorf("failed to get config: %w", err)
164+
}
165+
_, _, err = providerplugin.GetProviderExecutable(&config)
166+
if err != nil {
167+
return fmt.Errorf("failed to get provider executable: %w", err)
168+
}
169+
159170
createOpts, err := GetCreateOptions(cmd.Context(), clusterStackPath)
160171
if err != nil {
161172
return fmt.Errorf("failed to create create options: %w", err)
@@ -244,5 +255,5 @@ func (c *CreateOptions) generateRelease() error {
244255
return fmt.Errorf("failed to write metadata: %w", err)
245256
}
246257

247-
return nil
258+
return providerplugin.CreateNodeImages(&c.Config, c.ClusterStackPath, c.ClusterStackReleaseDir)
248259
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/*
2+
Copyright 2024 The Kubernetes Authors.
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
http://www.apache.org/licenses/LICENSE-2.0
7+
Unless required by applicable law or agreed to in writing, software
8+
distributed under the License is distributed on an "AS IS" BASIS,
9+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
See the License for the specific language governing permissions and
11+
limitations under the License.
12+
*/
13+
14+
// Package providerplugin implements calling the provider specific csctl plugin.
15+
package providerplugin
16+
17+
import (
18+
"fmt"
19+
"os"
20+
"os/exec"
21+
"path/filepath"
22+
23+
"github.com/SovereignCloudStack/csctl/pkg/clusterstack"
24+
)
25+
26+
// GetProviderExecutable returns the path to the provider plugin (like "csctl-docker").
27+
// If there is not "config" for the provider in csctl.yaml, then needed is false and path is the empty string.
28+
func GetProviderExecutable(config *clusterstack.CsctlConfig) (needed bool, path string, err error) {
29+
if config.Config.Provider.Config.Method == "" {
30+
return false, "", nil
31+
}
32+
pluginName := "csctl-" + config.Config.Provider.Type
33+
_, err = os.Stat(pluginName)
34+
if err == nil {
35+
path, err := filepath.Abs(pluginName)
36+
if err != nil {
37+
return false, "", fmt.Errorf("failed to find a path: %w", err)
38+
}
39+
return true, path, nil
40+
}
41+
path, err = exec.LookPath(pluginName)
42+
if err != nil {
43+
return false, "", fmt.Errorf("could not find plugin %s in $PATH or current working directory", pluginName)
44+
}
45+
return true, path, nil
46+
}
47+
48+
// CreateNodeImages calls the provider plugin command to create nodes images.
49+
func CreateNodeImages(config *clusterstack.CsctlConfig, clusterStackPath, clusterStackReleaseDir string) error {
50+
needed, path, err := GetProviderExecutable(config)
51+
if err != nil {
52+
return err
53+
}
54+
if !needed {
55+
fmt.Printf("No provider specific configuration in csctl.yaml. No need to call a plugin for provider %q\n", config.Config.Provider.Type)
56+
return nil
57+
}
58+
args := []string{"create-node-images", clusterStackPath, clusterStackReleaseDir}
59+
fmt.Printf("Calling Provider Plugin: %s\n", path)
60+
cmd := exec.Command(path, args...) // #nosec G204
61+
cmd.Stdout = os.Stdout
62+
cmd.Stderr = os.Stderr
63+
64+
if err := cmd.Run(); err != nil {
65+
return fmt.Errorf("error executing command: %w", err)
66+
}
67+
return nil
68+
}

0 commit comments

Comments
 (0)