Skip to content

Commit 9391fc9

Browse files
committed
fixup! fixup! fixup! fix: Make dry-run=server optional
1 parent 520e96e commit 9391fc9

File tree

5 files changed

+66
-33
lines changed

5 files changed

+66
-33
lines changed

cmd/helm3.go

Lines changed: 42 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@ import (
1414
)
1515

1616
var (
17-
helmVersionRE = regexp.MustCompile(`Version:\s*"([^"]+)"`)
18-
minHelmVersion = semver.MustParse("v3.1.0-rc.1")
17+
helmVersionRE = regexp.MustCompile(`Version:\s*"([^"]+)"`)
18+
minHelmVersion = semver.MustParse("v3.1.0-rc.1")
19+
// See https://github.com/helm/helm/pull/9426
1920
minHelmVersionWithDryRunLookupSupport = semver.MustParse("v3.13.0")
2021
)
2122

@@ -131,7 +132,7 @@ func (d *diffCmd) template(isUpgrade bool) ([]byte, error) {
131132
// Let's simulate that in helm-diff.
132133
// See https://medium.com/@kcatstack/understand-helm-upgrade-flags-reset-values-reuse-values-6e58ac8f127e
133134
shouldDefaultReusingValues := isUpgrade && len(d.values) == 0 && len(d.stringValues) == 0 && len(d.valueFiles) == 0 && len(d.fileValues) == 0
134-
if (d.reuseValues || shouldDefaultReusingValues) && !d.resetValues && d.isRemoteAccessAllowed() {
135+
if (d.reuseValues || shouldDefaultReusingValues) && !d.resetValues && d.clusterAccessAllowed() {
135136
tmpfile, err := os.CreateTemp("", "existing-values")
136137
if err != nil {
137138
return nil, err
@@ -192,36 +193,28 @@ func (d *diffCmd) template(isUpgrade bool) ([]byte, error) {
192193
filter func([]byte) []byte
193194
)
194195

196+
// `--dry-run=client` or `--dry-run=server`?
197+
//
198+
// Or what's the relationoship between helm-diff's --dry-run flag,
199+
// HELM_DIFF_UPGRADE_DRY_RUN env var and the helm upgrade --dry-run flag?
200+
//
201+
// Read on to find out.
195202
if d.useUpgradeDryRun {
196-
//
197-
// # `--dry-run=client` or `--dry-run=server`?
198-
//
199-
// Or what's the relationoship between helm-diff's --dry-run flag,
200-
// HELM_DIFF_UPGRADE_DRY_RUN env var and the helm upgrade --dry-run flag?
201-
//
202-
// If the program reaches here,
203-
// we are sure that the user wants to user the `helm upgrade --dry-run` command
204-
// for generating the manifests to be diffed.
205-
//
206-
// However, which dry-run mode to use is still not clear.
207-
//
208-
// For compatibility with the old and new helm-diff options,
209-
// old and new helm, we assume that the user wants to use the `--dry-run=client` mode
210-
// if helm-diff has been invoked with any of the following flags:
211-
//
212-
// * --dry-run
213-
// * --dry-run=""
214-
// * --dry-run=client
215-
//
216-
// Otherwise, we assume that the user wants to use the `--dry-run=server` mode.
217-
//
218-
219203
if d.isAllowUnreleased() {
220204
// Otherwise you get the following error when this is a diff for a new install
221205
// Error: UPGRADE FAILED: "$RELEASE_NAME" has no deployed releases
222206
flags = append(flags, "--install")
223207
}
224208

209+
// If the program reaches here,
210+
// we are sure that the user wants to user the `helm upgrade --dry-run` command
211+
// for generating the manifests to be diffed.
212+
//
213+
// So the question is only whether to use `--dry-run=client` or `--dry-run=server`.
214+
//
215+
// As HELM_DIFF_UPGRADE_DRY_RUN is there for producing more complete and correct diff results,
216+
// we use --dry-run=server if the version of helm supports it.
217+
// Otherwise, we use --dry-run=client, as that's the best we can do.
225218
if useDryRunService, err := isHelmVersionAtLeast(minHelmVersionWithDryRunLookupSupport); err == nil && useDryRunService {
226219
flags = append(flags, "--dry-run=server")
227220
} else {
@@ -232,7 +225,7 @@ func (d *diffCmd) template(isUpgrade bool) ([]byte, error) {
232225
return extractManifestFromHelmUpgradeDryRunOutput(s, d.noHooks)
233226
}
234227
} else {
235-
if !d.disableValidation && d.isRemoteAccessAllowed() {
228+
if !d.disableValidation && d.clusterAccessAllowed() {
236229
flags = append(flags, "--validate")
237230
}
238231

@@ -251,12 +244,28 @@ func (d *diffCmd) template(isUpgrade bool) ([]byte, error) {
251244
// To keep the full compatibility with older helm-diff versions,
252245
// we pass --dry-run to `helm template` only if Helm is greater than v3.13.0.
253246
if useDryRunService, err := isHelmVersionAtLeast(minHelmVersionWithDryRunLookupSupport); err == nil && useDryRunService {
247+
// However, which dry-run mode to use is still not clear.
248+
//
249+
// For compatibility with the old and new helm-diff options,
250+
// old and new helm, we assume that the user wants to use the older `helm template --dry-run=client` mode
251+
// if helm-diff has been invoked with any of the following flags:
252+
//
253+
// * no dry-run flags (to be consistent with helm-template)
254+
// * --dry-run
255+
// * --dry-run=""
256+
// * --dry-run=client
257+
//
258+
// and the newer `helm template --dry-run=server` mode when invoked with:
259+
//
260+
// * --dry-run=server
261+
//
262+
// Any other values should result in errors.
263+
//
254264
// See the fllowing link for more details:
255265
// - https://github.com/databus23/helm-diff/pull/458
256266
// - https://github.com/helm/helm/pull/9426#issuecomment-1501005666
257267
if d.dryRunMode == "server" {
258-
//
259-
// # This is for security reasons!
268+
// This is for security reasons!
260269
//
261270
// We give helm-template the additional cluster access for the helm `lookup` function
262271
// only if the user has explicitly requested it by --dry-run=server,
@@ -266,6 +275,10 @@ func (d *diffCmd) template(isUpgrade bool) ([]byte, error) {
266275
// full cluster-access via helm-template --dry-run=server!
267276
flags = append(flags, "--dry-run=server")
268277
} else {
278+
// Since helm-diff 3.9.0 and helm 3.13.0, we pass --dry-run=client to `helm template` by default.
279+
// This doesn't make any difference for helm-diff itself,
280+
// because helm-template w/o flags is equivalent to helm-template --dry-run=client.
281+
// See https://github.com/helm/helm/pull/9426#discussion_r1181397259
269282
flags = append(flags, "--dry-run=client")
270283
}
271284
}

cmd/upgrade.go

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,24 @@ func (d *diffCmd) isAllowUnreleased() bool {
6969
return d.allowUnreleased || d.install
7070
}
7171

72-
func (d *diffCmd) isRemoteAccessAllowed() bool {
72+
// clusterAccessAllowed returns true if the diff command is allowed to access the cluster at some degree.
73+
//
74+
// helm-diff basically have 3 modes of operation:
75+
// 1. no cluster access at all when --dry-run, --dry-run=client, or --dry-run=true is specified.
76+
// 2. basic cluster access when --dry-run is not specified.
77+
// 3. extra cluster access when --dry-run=server is specified.
78+
//
79+
// clusterAccessAllowed returns true when the mode is either 2 or 3.
80+
//
81+
// If false, helm-diff should not access the cluster at all.
82+
// More concretely:
83+
// - It shouldn't pass --validate to helm-template because it requires cluster access.
84+
// - It shouldn't get the current release manifest using helm-get-manifest because it requires cluster access.
85+
// - It shouldn't get the current release hooks using helm-get-hooks because it requires cluster access.
86+
// - It shouldn't get the current release values using helm-get-values because it requires cluster access.
87+
//
88+
// See also https://github.com/helm/helm/pull/9426#discussion_r1181397259
89+
func (d *diffCmd) clusterAccessAllowed() bool {
7390
clientOnly := (d.dryRunModeSpecified && d.dryRunMode == "") || d.dryRunMode == "true" || d.dryRunMode == "client"
7491
return !clientOnly
7592
}
@@ -279,7 +296,7 @@ func (d *diffCmd) runHelm3() error {
279296

280297
var err error
281298

282-
if d.isRemoteAccessAllowed() {
299+
if d.clusterAccessAllowed() {
283300
releaseManifest, err = getRelease(d.release, d.namespace)
284301
}
285302

@@ -326,7 +343,7 @@ func (d *diffCmd) runHelm3() error {
326343
}
327344

328345
currentSpecs := make(map[string]*manifest.MappingResult)
329-
if !newInstall && d.isRemoteAccessAllowed() {
346+
if !newInstall && d.clusterAccessAllowed() {
330347
if !d.noHooks && !d.threeWayMerge {
331348
hooks, err := getHooks(d.release, d.namespace)
332349
if err != nil {

cmd/upgrade_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ func TestIsRemoteAccessAllowed(t *testing.T) {
4949

5050
for _, tc := range cases {
5151
t.Run(tc.name, func(t *testing.T) {
52-
actual := tc.cmd.isRemoteAccessAllowed()
52+
actual := tc.cmd.clusterAccessAllowed()
5353
if actual != tc.expected {
5454
t.Errorf("Expected %v, got %v", tc.expected, actual)
5555
}

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ require (
135135
go.opentelemetry.io/otel v1.14.0 // indirect
136136
go.opentelemetry.io/otel/trace v1.14.0 // indirect
137137
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect
138+
golang.org/dl v0.0.0-20231010164639-b8ab22880620 // indirect
138139
golang.org/x/net v0.17.0 // indirect
139140
golang.org/x/oauth2 v0.4.0 // indirect
140141
golang.org/x/sync v0.1.0 // indirect

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -715,6 +715,8 @@ go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/
715715
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
716716
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
717717
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
718+
golang.org/dl v0.0.0-20231010164639-b8ab22880620 h1:Ouctod3TwJPqrchQF9XERIziHPu5m6FLvxSNNOc70vQ=
719+
golang.org/dl v0.0.0-20231010164639-b8ab22880620/go.mod h1:IUMfjQLJQd4UTqG1Z90tenwKoCX93Gn3MAQJMOSBsDQ=
718720
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
719721
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
720722
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=

0 commit comments

Comments
 (0)