-
Notifications
You must be signed in to change notification settings - Fork 1.7k
/
chart.go
199 lines (173 loc) · 5.9 KB
/
chart.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
// Copyright 2018 The Operator-SDK Authors
//
// 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
//
// http://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 chartutil
import (
"bytes"
"fmt"
"io/ioutil"
"os"
"path/filepath"
log "github.com/sirupsen/logrus"
"helm.sh/helm/v3/pkg/chart"
"helm.sh/helm/v3/pkg/chart/loader"
"helm.sh/helm/v3/pkg/chartutil"
"helm.sh/helm/v3/pkg/cli"
"helm.sh/helm/v3/pkg/downloader"
"helm.sh/helm/v3/pkg/getter"
"helm.sh/helm/v3/pkg/repo"
)
const (
// HelmChartsDir is the relative directory within a SDK project where Helm charts are stored.
HelmChartsDir = "helm-charts"
)
// Options is used to configure how a Helm chart is scaffolded
// for a new Helm operator project.
type Options struct {
// Chart is a chart reference for a local or remote chart.
Chart string
// Repo is a URL to a custom chart repository.
Repo string
// Version is the version of the chart to fetch.
Version string
}
// NewChart creates a new helm chart for the project from helm's default template.
// It returns a chart.Chart that references the newly created chart or an error.
func NewChart(name string) (*chart.Chart, error) {
tmpDir, err := ioutil.TempDir("", "osdk-helm-chart")
if err != nil {
return nil, err
}
defer func() {
if err := os.RemoveAll(tmpDir); err != nil {
log.Errorf("Failed to remove temporary directory %s: %v", tmpDir, err)
}
}()
// Create a new chart
chartPath, err := chartutil.Create(name, tmpDir)
if err != nil {
return nil, err
}
return loader.Load(chartPath)
}
// LoadChart creates a new helm chart for the project based on the passed opts.
// It returns a chart.Chart that references the newly created chart or an error.
//
// If opts.Chart is a local file, it verifies that it is a valid helm chart
// archive and returns its chart.Chart representation.
//
// If opts.Chart is a local directory, it verifies that it is a valid helm chart
// directory and returns its chart.Chart representation.
//
// For any other value of opts.Chart, it attempts to fetch the helm chart from a
// remote repository.
//
// If opts.Repo is not specified, the following chart reference formats are supported:
//
// - <repoName>/<chartName>: Fetch the helm chart named chartName from the helm
// chart repository named repoName, as specified in the
// $HELM_HOME/repositories/repositories.yaml file.
//
// - <url>: Fetch the helm chart archive at the specified URL.
//
// If opts.Repo is specified, only one chart reference format is supported:
//
// - <chartName>: Fetch the helm chart named chartName in the helm chart repository
// specified by opts.Repo
//
// If opts.Version is not set, it will fetch the latest available version of the helm
// chart. Otherwise, it will fetch the specified version.
// opts.Version is not used when opts.Chart itself refers to a specific version, for
// example when it is a local path or a URL.
func LoadChart(opts Options) (*chart.Chart, error) {
tmpDir, err := ioutil.TempDir("", "osdk-helm-chart")
if err != nil {
return nil, err
}
defer func() {
if err := os.RemoveAll(tmpDir); err != nil {
log.Errorf("Failed to remove temporary directory %s: %v", tmpDir, err)
}
}()
chartPath := opts.Chart
// If it is a remote chart, download it to a temp dir first
if _, err := os.Stat(opts.Chart); err != nil {
chartPath, err = downloadChart(tmpDir, opts)
if err != nil {
return nil, err
}
}
return loader.Load(chartPath)
}
func downloadChart(destDir string, opts Options) (string, error) {
settings := cli.New()
getters := getter.All(settings)
c := downloader.ChartDownloader{
Out: os.Stderr,
Getters: getters,
RepositoryConfig: settings.RepositoryConfig,
RepositoryCache: settings.RepositoryCache,
}
if opts.Repo != "" {
chartURL, err := repo.FindChartInRepoURL(opts.Repo, opts.Chart, opts.Version, "", "", "", getters)
if err != nil {
return "", err
}
opts.Chart = chartURL
}
chartArchive, _, err := c.DownloadTo(opts.Chart, opts.Version, destDir)
if err != nil {
return "", err
}
return chartArchive, nil
}
// ScaffoldChart scaffolds the provided chart.Chart to a known directory relative to projectDir
//
// It also fetches the dependencies and reloads the chart.Chart
//
// It returns the reloaded chart, the relative path, or an error.
func ScaffoldChart(chrt *chart.Chart, projectDir string) (*chart.Chart, string, error) {
chartsPath := filepath.Join(projectDir, HelmChartsDir)
// Save it into our project's helm-charts directory.
if err := chartutil.SaveDir(chrt, chartsPath); err != nil {
return chrt, "", err
}
chartPath := filepath.Join(chartsPath, chrt.Name())
// Fetch dependencies
if err := fetchChartDependencies(chartPath); err != nil {
return chrt, "", fmt.Errorf("failed to fetch chart dependencies: %w", err)
}
// Reload chart in case dependencies changed
chrt, err := loader.Load(chartPath)
if err != nil {
return chrt, "", fmt.Errorf("failed to reload chart: %w", err)
}
return chrt, filepath.Join(HelmChartsDir, chrt.Name()), nil
}
func fetchChartDependencies(chartPath string) error {
settings := cli.New()
getters := getter.All(settings)
out := &bytes.Buffer{}
man := &downloader.Manager{
Out: out,
ChartPath: chartPath,
Getters: getters,
RepositoryConfig: settings.RepositoryConfig,
RepositoryCache: settings.RepositoryCache,
}
if err := man.Build(); err != nil {
fmt.Println(out.String())
return err
}
return nil
}