Skip to content

Commit 76d13fc

Browse files
authored
pkg/scaffold/role,pkg/operator-sdk/new.go: generate role rules from helm chart (#1188)
* pkg/scaffold/role.go: support adding custom rules * pkg/scaffold/,commands/operator-sdk/new.go: generate role rules from helm chart * internal/pkg/scaffold/helm/chart.go: fetch chart dependencies * CHANGELOG.md,doc/helm/user-guide.md: include note about RBAC rule generation
1 parent 52ad33a commit 76d13fc

File tree

11 files changed

+559
-37
lines changed

11 files changed

+559
-37
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
### Changed
66

7+
- When Helm operator projects are created, the SDK now generates RBAC rules in `deploy/role.yaml` based on the chart's default manifest. ([#1188](https://github.com/operator-framework/operator-sdk/pull/1188))
8+
79
### Deprecated
810

911
### Removed

Gopkg.lock

+5-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cmd/operator-sdk/new/cmd.go

+11-1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030
"github.com/pkg/errors"
3131
log "github.com/sirupsen/logrus"
3232
"github.com/spf13/cobra"
33+
"sigs.k8s.io/controller-runtime/pkg/client/config"
3334
)
3435

3536
func NewCmd() *cobra.Command {
@@ -281,6 +282,15 @@ func doHelmScaffold() error {
281282
valuesPath := filepath.Join("<project_dir>", helm.HelmChartsDir, chart.GetMetadata().GetName(), "values.yaml")
282283
crSpec := fmt.Sprintf("# Default values copied from %s\n\n%s", valuesPath, chart.GetValues().GetRaw())
283284

285+
k8sCfg, err := config.GetConfig()
286+
if err != nil {
287+
return fmt.Errorf("failed to get kubernetes config: %s", err)
288+
}
289+
roleScaffold, err := helm.CreateRoleScaffold(k8sCfg, chart, isClusterScoped)
290+
if err != nil {
291+
return fmt.Errorf("failed to generate role scaffold: %s", err)
292+
}
293+
284294
s := &scaffold.Scaffold{}
285295
err = s.Execute(cfg,
286296
&helm.Dockerfile{},
@@ -289,7 +299,7 @@ func doHelmScaffold() error {
289299
ChartName: chart.GetMetadata().GetName(),
290300
},
291301
&scaffold.ServiceAccount{},
292-
&scaffold.Role{IsClusterScoped: isClusterScoped},
302+
roleScaffold,
293303
&scaffold.RoleBinding{IsClusterScoped: isClusterScoped},
294304
&helm.Operator{IsClusterScoped: isClusterScoped},
295305
&scaffold.CRD{Resource: resource},

doc/helm/user-guide.md

+6-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ powered by Helm using tools and libraries provided by the Operator SDK.
1010
- [kubectl][kubectl_tool] version v1.11.3+.
1111
- [dep][dep_tool] version v0.5.0+. (Optional if you aren't installing from source)
1212
- [go][go_tool] version v1.10+. (Optional if you aren't installing from source)
13-
- Access to a Kubernetes v.1.11.3+ cluster.
13+
- Access to a Kubernetes v1.11.3+ cluster.
1414

1515
**Note**: This guide uses [minikube][minikube_tool] version v0.25.0+ as the
1616
local Kubernetes cluster and [quay.io][quay_link] for the public registry.
@@ -53,6 +53,11 @@ This creates the nginx-operator project specifically for watching the
5353
Nginx resource with APIVersion `example.com/v1alpha1` and Kind
5454
`Nginx`.
5555

56+
For Helm-based projects, `operator-sdk new` also generates the RBAC rules
57+
in `deploy/role.yaml` based on the resources that would be deployed by the
58+
chart's default manifest. Be sure to double check that the rules generated
59+
in `deploy/role.yaml` meet the operator's permission requirements.
60+
5661
To learn more about the project directory structure, see the
5762
[project layout][layout_doc] doc.
5863

internal/pkg/scaffold/helm/chart.go

+43-15
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
package helm
1616

1717
import (
18+
"bytes"
1819
"fmt"
1920
"io/ioutil"
2021
"os"
@@ -116,7 +117,7 @@ func CreateChart(projectDir string, opts CreateChartOptions) (*scaffold.Resource
116117
chartsDir := filepath.Join(projectDir, HelmChartsDir)
117118
err := os.MkdirAll(chartsDir, 0755)
118119
if err != nil {
119-
return nil, nil, err
120+
return nil, nil, fmt.Errorf("failed to create helm-charts directory: %s", err)
120121
}
121122

122123
var (
@@ -128,13 +129,29 @@ func CreateChart(projectDir string, opts CreateChartOptions) (*scaffold.Resource
128129
// from Helm's default template. Otherwise, fetch it.
129130
if len(opts.Chart) == 0 {
130131
r, c, err = scaffoldChart(chartsDir, opts.ResourceAPIVersion, opts.ResourceKind)
132+
if err != nil {
133+
return nil, nil, fmt.Errorf("failed to scaffold default chart: %s", err)
134+
}
131135
} else {
132136
r, c, err = fetchChart(chartsDir, opts)
137+
if err != nil {
138+
return nil, nil, fmt.Errorf("failed to fetch chart: %s", err)
139+
}
140+
}
141+
142+
relChartPath := filepath.Join(HelmChartsDir, c.GetMetadata().GetName())
143+
absChartPath := filepath.Join(projectDir, relChartPath)
144+
if err := fetchChartDependencies(absChartPath); err != nil {
145+
return nil, nil, fmt.Errorf("failed to fetch chart dependencies: %s", err)
133146
}
147+
148+
// Reload chart in case dependencies changed
149+
c, err = chartutil.Load(absChartPath)
134150
if err != nil {
135-
return nil, nil, err
151+
return nil, nil, fmt.Errorf("failed to load chart: %s", err)
136152
}
137-
log.Infof("Created %s/%s/", HelmChartsDir, c.GetMetadata().GetName())
153+
154+
log.Infof("Created %s", relChartPath)
138155
return r, c, nil
139156
}
140157

@@ -159,7 +176,7 @@ func scaffoldChart(destDir, apiVersion, kind string) (*scaffold.Resource, *chart
159176
return nil, nil, err
160177
}
161178

162-
chart, err := chartutil.LoadDir(chartPath)
179+
chart, err := chartutil.Load(chartPath)
163180
if err != nil {
164181
return nil, nil, err
165182
}
@@ -198,17 +215,7 @@ func fetchChart(destDir string, opts CreateChartOptions) (*scaffold.Resource, *c
198215
}
199216

200217
func createChartFromDisk(destDir, source string, isDir bool) (*chart.Chart, error) {
201-
var (
202-
chart *chart.Chart
203-
err error
204-
)
205-
206-
// If source is a file or directory, attempt to load it
207-
if isDir {
208-
chart, err = chartutil.LoadDir(source)
209-
} else {
210-
chart, err = chartutil.LoadFile(source)
211-
}
218+
chart, err := chartutil.Load(source)
212219
if err != nil {
213220
return nil, err
214221
}
@@ -265,3 +272,24 @@ func createChartFromRemote(destDir string, opts CreateChartOptions) (*chart.Char
265272

266273
return createChartFromDisk(destDir, chartArchive, false)
267274
}
275+
276+
func fetchChartDependencies(chartPath string) error {
277+
helmHome, ok := os.LookupEnv(environment.HomeEnvVar)
278+
if !ok {
279+
helmHome = environment.DefaultHelmHome
280+
}
281+
getters := getter.All(environment.EnvSettings{})
282+
283+
out := &bytes.Buffer{}
284+
man := &downloader.Manager{
285+
Out: out,
286+
ChartPath: chartPath,
287+
HelmHome: helmpath.Home(helmHome),
288+
Getters: getters,
289+
}
290+
if err := man.Build(); err != nil {
291+
fmt.Println(out.String())
292+
return err
293+
}
294+
return nil
295+
}

0 commit comments

Comments
 (0)