openstack-helm-plugin/main.go
Vladimir Kozhukalov 5b1bcd99ab Improve get-values-overrides help
Change-Id: I59b763b6109ad7af63c3d5484a03773915b23493
2024-05-09 11:55:28 -05:00

189 lines
6.3 KiB
Go

/*
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"fmt"
"io"
"math"
"net/http"
"os"
"path/filepath"
"sort"
"strings"
"github.com/spf13/cobra"
)
const DefaultBaseUrl string = "https://opendev.org/openstack/openstack-helm/raw/branch/master"
func newRootCommand() *cobra.Command {
var cwd string
var download bool
var baseUrl string
var basePath string
var subchart string
var chart string
cwd, _ = os.Getwd()
rootCmd := &cobra.Command{
Use: "get-values-overrides <feature1> <feature2> ...",
Long: `Get Helm values overrides for a set of features.
If 3 features are passed, then the overrides will be looked
up in the following order:
<overrides_path>/<chart>/values_overrides/<feature-3>.yaml
<overrides_path>/<chart>/values_overrides/<feature-2>.yaml
<overrides_path>/<chart>/values_overrides/<feature-2>-<feature-3>.yaml
<overrides_path>/<chart>/values_overrides/<feature-1>.yaml
<overrides_path>/<chart>/values_overrides/<feature-1>-<feature-3>.yaml
<overrides_path>/<chart>/values_overrides/<feature-1>-<feature-2>.yaml
<overrides_path>/<chart>/values_overrides/<feature-1>-<feature-2>-<feature-3>.yaml
If you think of the features as bits of a binary number where <feature3> is
the least significant bit, then the order corresponds to all numbers from 001
to 111 in binary representation.`,
Run: func(cmd *cobra.Command, args []string) {
features := args[0:]
if len(features) == 0 {
fmt.Fprintln(os.Stderr, "No features provided")
os.Exit(0)
}
fmt.Fprintf(os.Stderr, "Base URL: %s\nBase path: %s\n", baseUrl, basePath)
fmt.Fprintf(os.Stderr, "Chart: %s\n", chart)
if subchart != "" {
fmt.Fprintf(os.Stderr, "Subchart: %s\n", subchart)
}
fmt.Fprintf(os.Stderr, "Features: %s\n", strings.Join(features, " "))
overrideCandidates := generateOverrideCandidates(features)
overrideArgs := getOverrideArgs(baseUrl, basePath, chart, subchart, overrideCandidates, download)
fmt.Fprintf(os.Stderr, "Resulting override args: %s\n", strings.Join(overrideArgs, " "))
fmt.Println(strings.Join(overrideArgs, " "))
},
}
rootCmd.Flags().BoolVarP(&download, "download", "d", false, "Download the overrides from the internet if not found in the path (default: false)")
rootCmd.Flags().StringVarP(&baseUrl, "url", "u", DefaultBaseUrl, "Base url to download overrides")
rootCmd.Flags().StringVarP(&basePath, "path", "p", cwd, "Path to the overrides")
rootCmd.Flags().StringVarP(&subchart, "subchart", "s", "", "Subchart to get the overrides for")
rootCmd.Flags().StringVarP(&chart, "chart", "c", "", "Chart to get the overrides for")
rootCmd.MarkFlagRequired("chart")
return rootCmd
}
func sliceReverse[T comparable](s []T) {
sort.SliceStable(s, func(i, j int) bool {
return i > j
})
}
func num2items(num uint32, power int) []int {
featureNums := make([]int, 0)
for i := 0; i < power; i++ {
if uint32(math.Pow(2, float64(i)))&num != 0 {
featureNums = append(featureNums, i)
}
}
sliceReverse(featureNums)
return featureNums
}
func overrideFile(basePath, chart, subchart, overrideName string) string {
if subchart != "" {
return filepath.Join(basePath, chart, "values_overrides", subchart, overrideName)
}
return filepath.Join(basePath, chart, "values_overrides", overrideName)
}
func overrideUrl(baseUrl, chart, subchart, overrideName string) string {
if subchart != "" {
return fmt.Sprintf("%s/%s/values_overrides/%s/%s", baseUrl, chart, subchart, overrideName)
}
return fmt.Sprintf("%s/%s/values_overrides/%s", baseUrl, chart, overrideName)
}
func downloadOverride(baseUrl, basePath, chart, subchart, overrideName string) error {
fullUrl := overrideUrl(baseUrl, chart, subchart, overrideName)
filename := overrideFile(basePath, chart, subchart, overrideName)
fmt.Fprintf(os.Stderr, "Trying to download %s\n", fullUrl)
resp, err := http.Get(fullUrl)
if err != nil {
return err
}
if resp.StatusCode != 200 {
return fmt.Errorf("failed to download %s: %s", fullUrl, resp.Status)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return err
}
err = os.MkdirAll(filepath.Dir(filename), 0755)
if err != nil {
return err
}
err = os.WriteFile(filename, body, 0644)
if err != nil {
return err
}
return nil
}
func generateOverrideCandidates(features []string) []string {
sliceReverse(features)
overrideCandidates := make([]string, 0)
for num := uint32(1); num < uint32(math.Pow(2, float64(len(features)))); num++ {
words := make([]string, 0)
items := num2items(num, len(features))
for _, item := range items {
words = append(words, features[item])
}
overrideCandidates = append(overrideCandidates, fmt.Sprintf("%s.yaml", strings.Join(words, "-")))
}
return overrideCandidates
}
func getOverrideArgs(baseUrl, basePath, chart, subchart string, overrideCandidates []string, download bool) []string {
overrideArgs := make([]string, 0)
for _, overrideCandidate := range overrideCandidates {
overrideCandidateFile := overrideFile(basePath, chart, subchart, overrideCandidate)
fmt.Fprintf(os.Stderr, "Override candidate: %s\n", overrideCandidateFile)
_, err := os.Stat(overrideCandidateFile)
if err == nil {
fmt.Fprintf(os.Stderr, "File found: %s\n", overrideCandidateFile)
overrideArgs = append(overrideArgs, fmt.Sprintf("--values %s", overrideCandidateFile))
} else {
fmt.Fprintf(os.Stderr, "File not found: %s\n", overrideCandidateFile)
if download {
err = downloadOverride(baseUrl, basePath, chart, subchart, overrideCandidate)
if err != nil {
fmt.Fprintln(os.Stderr, err)
} else {
fmt.Fprintf(os.Stderr, "Successfully downloaded %s\n", overrideCandidate)
overrideArgs = append(overrideArgs, fmt.Sprintf("--values %s", overrideCandidateFile))
}
}
}
}
return overrideArgs
}
func main() {
if err := newRootCommand().Execute(); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}