2016-06-22 14:28:45 -04:00
/ *
2018-08-24 15:03:55 -04:00
Copyright The Helm Authors .
2016-06-22 14:28:45 -04:00
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 .
* /
2025-02-24 10:11:54 -05:00
package cmd
2016-04-20 21:05:12 -04:00
import (
2021-07-25 20:04:58 -04:00
"context"
2024-11-15 22:07:40 -05:00
"errors"
2021-07-25 20:04:58 -04:00
"fmt"
2016-07-15 19:13:32 -04:00
"io"
2020-06-12 08:24:55 -04:00
"log"
2025-04-10 09:06:03 -04:00
"log/slog"
2021-07-25 20:04:58 -04:00
"os"
"os/signal"
2025-05-01 21:43:25 -04:00
"slices"
2021-07-25 20:04:58 -04:00
"syscall"
2019-05-09 22:53:52 -04:00
"time"
2019-02-08 19:02:57 -05:00
2016-04-20 21:05:12 -04:00
"github.com/spf13/cobra"
2019-03-13 11:58:35 -04:00
"github.com/spf13/pflag"
2016-04-20 21:05:12 -04:00
2024-12-26 16:33:51 -05:00
"helm.sh/helm/v4/pkg/action"
2025-02-25 15:20:44 -05:00
chart "helm.sh/helm/v4/pkg/chart/v2"
"helm.sh/helm/v4/pkg/chart/v2/loader"
2024-12-26 16:33:51 -05:00
"helm.sh/helm/v4/pkg/cli/output"
"helm.sh/helm/v4/pkg/cli/values"
2025-02-24 10:11:54 -05:00
"helm.sh/helm/v4/pkg/cmd/require"
2024-12-26 16:33:51 -05:00
"helm.sh/helm/v4/pkg/downloader"
"helm.sh/helm/v4/pkg/getter"
2025-02-26 09:04:32 -05:00
release "helm.sh/helm/v4/pkg/release/v1"
2016-04-20 21:05:12 -04:00
)
const installDesc = `
This command installs a chart archive .
2016-04-28 19:24:08 -04:00
2017-09-26 04:03:00 -04:00
The install argument must be a chart reference , a path to a packaged chart ,
2017-09-26 04:13:54 -04:00
a path to an unpacked chart directory or a URL .
2016-07-22 19:19:06 -04:00
To override values in a chart , use either the ' -- values ' flag and pass in a file
2018-03-14 18:33:02 -04:00
or use the ' -- set ' flag and pass configuration from the command line , to force
2021-12-02 16:03:03 -05:00
a string value use ' -- set - string ' . You can use ' -- set - file ' to set individual
values from a file when the value itself is too long for the command line
2022-02-21 18:48:41 -05:00
or is dynamically generated . You can also use ' -- set - json ' to set json values
2025-02-07 21:04:14 -05:00
( scalars / objects / arrays ) from the command line . Additionally , you can use ' -- set - json ' and passing json object as a string .
2016-07-22 19:19:06 -04:00
2019-10-28 16:28:36 -04:00
$ helm install - f myvalues . yaml myredis . / redis
2016-07-22 19:19:06 -04:00
or
2019-10-28 16:28:36 -04:00
$ helm install -- set name = prod myredis . / redis
2016-07-22 19:19:06 -04:00
2018-03-14 18:33:02 -04:00
or
2019-10-28 16:28:36 -04:00
$ helm install -- set - string long_int = 1234567890 myredis . / redis
2018-03-14 18:33:02 -04:00
2019-09-24 14:42:56 -04:00
or
2020-05-15 09:38:55 -04:00
2019-10-28 16:28:36 -04:00
$ helm install -- set - file my_script = dothings . sh myredis . / redis
2019-09-24 14:42:56 -04:00
2022-02-21 18:48:41 -05:00
or
$ helm install -- set - json ' master . sidecars = [ { "name" : "sidecar" , "image" : "myImage" , "imagePullPolicy" : "Always" , "ports" : [ { "name" : "portname" , "containerPort" : 1234 } ] } ] ' myredis . / redis
2025-02-07 21:04:14 -05:00
or
$ helm install -- set - json ' { "master" : { "sidecars" : [ { "name" : "sidecar" , "image" : "myImage" , "imagePullPolicy" : "Always" , "ports" : [ { "name" : "portname" , "containerPort" : 1234 } ] } ] } } ' myredis . / redis
2022-02-21 18:48:41 -05:00
2016-12-07 17:50:49 -05:00
You can specify the ' -- values '/' - f ' flag multiple times . The priority will be given to the
2016-12-20 01:07:09 -05:00
last ( right - most ) file specified . For example , if both myvalues . yaml and override . yaml
2016-12-07 17:50:49 -05:00
contained a key called ' Test ' , the value set in override . yaml would take precedence :
2019-10-28 16:28:36 -04:00
$ helm install - f myvalues . yaml - f override . yaml myredis . / redis
2016-12-07 17:50:49 -05:00
2017-01-11 18:51:06 -05:00
You can specify the ' -- set ' flag multiple times . The priority will be given to the
last ( right - most ) set specified . For example , if both ' bar ' and ' newbar ' values are
set for a key called ' foo ' , the ' newbar ' value would take precedence :
2019-10-28 16:28:36 -04:00
$ helm install -- set foo = bar -- set foo = newbar myredis . / redis
2017-01-11 18:51:06 -05:00
2022-12-05 00:44:33 -05:00
Similarly , in the following example ' foo ' is set to ' [ "four" ] ' :
2022-02-21 18:48:41 -05:00
$ helm install -- set - json = ' foo = [ "one" , "two" , "three" ] ' -- set - json = ' foo = [ "four" ] ' myredis . / redis
And in the following example , ' foo ' is set to ' { "key1" : "value1" , "key2" : "bar" } ' :
$ helm install -- set - json = ' foo = { "key1" : "value1" , "key2" : "value2" } ' -- set - json = ' foo . key2 = "bar" ' myredis . / redis
2017-01-11 18:51:06 -05:00
2016-07-22 19:19:06 -04:00
To check the generated manifests of a release without installing the chart ,
2024-03-10 14:05:50 -04:00
the -- debug and -- dry - run flags can be combined .
The -- dry - run flag will output all generated chart manifests , including Secrets
2024-03-12 13:56:10 -04:00
which can contain sensitive values . To hide Kubernetes Secrets use the
-- hide - secret flag . Please carefully consider how and when these flags are used .
2016-08-09 18:36:00 -04:00
2017-11-23 13:06:37 -05:00
If -- verify is set , the chart MUST have a provenance file , and the provenance
file MUST pass all verification steps .
2016-10-05 14:43:06 -04:00
2022-08-04 23:02:00 -04:00
There are six different ways you can express the chart you want to install :
2016-10-05 14:43:06 -04:00
2019-10-18 03:52:59 -04:00
1. By chart reference : helm install mymaria example / mariadb
2. By path to a packaged chart : helm install mynginx . / nginx - 1.2 .3 . tgz
3. By path to an unpacked chart directory : helm install mynginx . / nginx
4. By absolute URL : helm install mynginx https : //example.com/charts/nginx-1.2.3.tgz
5. By chart reference and repo url : helm install -- repo https : //example.com/charts/ mynginx nginx
2022-08-04 23:02:00 -04:00
6. By OCI registries : helm install mynginx -- version 1.2 .3 oci : //example.com/charts/nginx
2016-10-05 14:43:06 -04:00
CHART REFERENCES
2019-10-18 03:52:59 -04:00
A chart reference is a convenient way of referencing a chart in a chart repository .
2016-10-05 14:43:06 -04:00
2019-07-26 12:27:18 -04:00
When you use a chart reference with a repo prefix ( ' example / mariadb ' ) , Helm will look in the local
configuration for a chart repository named ' example ' , and will then look for a
2019-10-28 16:28:36 -04:00
chart in that repository whose name is ' mariadb ' . It will install the latest stable version of that chart
until you specify ' -- devel ' flag to also include development version ( alpha , beta , and release candidate releases ) , or
2019-10-24 10:10:47 -04:00
supply a version number with the ' -- version ' flag .
2016-10-05 14:43:06 -04:00
To see the list of chart repositories , use ' helm repo list ' . To search for
charts in a repository , use ' helm search ' .
2016-04-20 21:05:12 -04:00
`
2019-01-07 19:45:14 -05:00
func newInstallCmd ( cfg * action . Configuration , out io . Writer ) * cobra . Command {
2019-02-08 19:02:57 -05:00
client := action . NewInstall ( cfg )
2019-08-01 17:40:52 -04:00
valueOpts := & values . Options { }
2019-10-07 13:17:22 -04:00
var outfmt output . Format
2016-07-15 19:13:32 -04:00
cmd := & cobra . Command {
2018-10-31 18:15:08 -04:00
Use : "install [NAME] [CHART]" ,
Short : "install a chart" ,
2018-04-14 16:31:31 -04:00
Long : installDesc ,
2018-10-31 18:15:08 -04:00
Args : require . MinimumNArgs ( 1 ) ,
2024-03-11 17:13:34 -04:00
ValidArgsFunction : func ( _ * cobra . Command , args [ ] string , toComplete string ) ( [ ] string , cobra . ShellCompDirective ) {
2020-04-11 14:06:56 -04:00
return compInstall ( args , toComplete , client )
} ,
2019-02-08 19:02:57 -05:00
RunE : func ( _ * cobra . Command , args [ ] string ) error {
2023-06-07 02:24:02 -04:00
registryClient , err := newRegistryClient ( client . CertFile , client . KeyFile , client . CaFile ,
2024-02-05 08:54:21 -05:00
client . InsecureSkipTLSverify , client . PlainHTTP , client . Username , client . Password )
2022-12-19 16:52:20 -05:00
if err != nil {
return fmt . Errorf ( "missing registry client: %w" , err )
}
client . SetRegistryClient ( registryClient )
2023-07-20 14:26:46 -04:00
// This is for the case where "" is specifically passed in as a
// value. When there is no value passed in NoOptDefVal will be used
// and it is set to client. See addInstallFlags.
2023-05-01 01:04:04 -04:00
if client . DryRunOption == "" {
2023-04-08 19:43:01 -04:00
client . DryRunOption = "none"
}
2019-08-01 11:04:36 -04:00
rel , err := runInstall ( args , client , valueOpts , out )
2016-07-15 19:13:32 -04:00
if err != nil {
2024-11-15 22:07:40 -05:00
return fmt . Errorf ( "INSTALLATION FAILED: %w" , err )
2016-07-15 19:13:32 -04:00
}
2019-09-25 14:20:47 -04:00
2024-11-15 13:27:28 -05:00
return outfmt . Write ( out , & statusPrinter {
release : rel ,
debug : settings . Debug ,
showMetadata : false ,
hideNotes : client . HideNotes ,
} )
2016-07-15 19:13:32 -04:00
} ,
2016-05-19 18:49:45 -04:00
}
2016-07-15 19:13:32 -04:00
2020-06-12 08:24:55 -04:00
addInstallFlags ( cmd , cmd . Flags ( ) , client , valueOpts )
2024-03-12 13:56:10 -04:00
// hide-secret is not available in all places the install flags are used so
// it is added separately
f := cmd . Flags ( )
f . BoolVar ( & client . HideSecret , "hide-secret" , false , "hide Kubernetes Secrets when also using the --dry-run flag" )
2019-10-07 13:17:22 -04:00
bindOutputFlag ( cmd , & outfmt )
2019-09-23 13:29:24 -04:00
bindPostRenderFlag ( cmd , & client . PostRenderer )
2016-10-14 23:05:04 -04:00
2016-07-15 19:13:32 -04:00
return cmd
}
2020-06-12 08:24:55 -04:00
func addInstallFlags ( cmd * cobra . Command , f * pflag . FlagSet , client * action . Install , valueOpts * values . Options ) {
2020-02-20 14:56:03 -05:00
f . BoolVar ( & client . CreateNamespace , "create-namespace" , false , "create the release namespace if not present" )
2023-07-20 14:26:46 -04:00
// --dry-run options with expected outcome:
// - Not set means no dry run and server is contacted.
// - Set with no value, a value of client, or a value of true and the server is not contacted
// - Set with a value of false, none, or false and the server is contacted
// The true/false part is meant to reflect some legacy behavior while none is equal to "".
2023-05-01 01:04:04 -04:00
f . StringVar ( & client . DryRunOption , "dry-run" , "" , "simulate an install. If --dry-run is set with no option being specified or as '--dry-run=client', it will not attempt cluster connections. Setting '--dry-run=server' allows attempting cluster connections." )
2023-01-23 15:28:29 -05:00
f . Lookup ( "dry-run" ) . NoOptDefVal = "client"
2022-12-23 13:28:01 -05:00
f . BoolVar ( & client . Force , "force" , false , "force resource updates through a replacement strategy" )
2019-03-13 11:58:35 -04:00
f . BoolVar ( & client . DisableHooks , "no-hooks" , false , "prevent hooks from running during install" )
2024-11-07 06:30:34 -05:00
f . BoolVar ( & client . Replace , "replace" , false , "reuse the given name, only if that name is a deleted release which remains in the history. This is unsafe in production" )
2019-05-09 22:53:52 -04:00
f . DurationVar ( & client . Timeout , "timeout" , 300 * time . Second , "time to wait for any individual Kubernetes operation (like Jobs for hooks)" )
2020-11-03 06:48:29 -05:00
f . BoolVar ( & client . WaitForJobs , "wait-for-jobs" , false , "if set and --wait enabled, will wait until all Jobs have been completed before marking the release as successful. It will wait for as long as --timeout" )
2019-03-13 11:58:35 -04:00
f . BoolVarP ( & client . GenerateName , "generate-name" , "g" , false , "generate the name (and omit the NAME parameter)" )
f . StringVar ( & client . NameTemplate , "name-template" , "" , "specify template used to name the release" )
2019-12-09 11:48:31 -05:00
f . StringVar ( & client . Description , "description" , "" , "add a custom description" )
2019-09-30 11:40:33 -04:00
f . BoolVar ( & client . Devel , "devel" , false , "use development versions, too. Equivalent to version '>0.0.0-0'. If --version is set, this is ignored" )
2021-04-28 16:21:02 -04:00
f . BoolVar ( & client . DependencyUpdate , "dependency-update" , false , "update dependencies if they are missing before installing the chart" )
2019-10-29 14:17:54 -04:00
f . BoolVar ( & client . DisableOpenAPIValidation , "disable-openapi-validation" , false , "if set, the installation process will not validate rendered templates against the Kubernetes OpenAPI Schema" )
2025-02-16 16:10:06 -05:00
f . BoolVar ( & client . Atomic , "atomic" , false , "if set, the installation process deletes the installation on failure. The --wait flag will be set automatically to \"watcher\" if --atomic is used" )
2019-09-30 11:40:33 -04:00
f . BoolVar ( & client . SkipCRDs , "skip-crds" , false , "if set, no CRDs will be installed. By default, CRDs are installed if not already present" )
f . BoolVar ( & client . SubNotes , "render-subchart-notes" , false , "if set, render subchart notes along with the parent" )
2024-01-23 10:32:03 -05:00
f . BoolVar ( & client . SkipSchemaValidation , "skip-schema-validation" , false , "if set, disables JSON schema validation" )
2023-02-16 18:56:59 -05:00
f . StringToStringVarP ( & client . Labels , "labels" , "l" , nil , "Labels that would be added to release metadata. Should be divided by comma." )
2023-02-01 11:35:19 -05:00
f . BoolVar ( & client . EnableDNS , "enable-dns" , false , "enable DNS lookups when rendering templates" )
2022-12-05 00:44:33 -05:00
f . BoolVar ( & client . HideNotes , "hide-notes" , false , "if set, do not show notes in install output. Does not affect presence in chart metadata" )
2024-11-18 23:33:03 -05:00
f . BoolVar ( & client . TakeOwnership , "take-ownership" , false , "if set, install will ignore the check for helm annotations and take ownership of the existing resources" )
2019-08-01 11:04:36 -04:00
addValueOptionsFlags ( f , valueOpts )
2019-03-13 11:58:35 -04:00
addChartPathOptionsFlags ( f , & client . ChartPathOptions )
2025-03-25 09:55:39 -04:00
AddWaitFlag ( cmd , & client . WaitStrategy )
2020-06-12 08:24:55 -04:00
2024-03-11 17:13:34 -04:00
err := cmd . RegisterFlagCompletionFunc ( "version" , func ( _ * cobra . Command , args [ ] string , toComplete string ) ( [ ] string , cobra . ShellCompDirective ) {
2020-06-12 08:24:55 -04:00
requiredArgs := 2
if client . GenerateName {
requiredArgs = 1
}
if len ( args ) != requiredArgs {
return nil , cobra . ShellCompDirectiveNoFileComp
}
return compVersionFlag ( args [ requiredArgs - 1 ] , toComplete )
} )
if err != nil {
log . Fatal ( err )
}
2019-03-13 11:58:35 -04:00
}
2019-08-01 17:40:52 -04:00
func runInstall ( args [ ] string , client * action . Install , valueOpts * values . Options , out io . Writer ) ( * release . Release , error ) {
2025-04-10 09:06:03 -04:00
slog . Debug ( "Original chart version" , "version" , client . Version )
2019-02-08 19:02:57 -05:00
if client . Version == "" && client . Devel {
2025-04-10 09:06:03 -04:00
slog . Debug ( "setting version to >0.0.0-0" )
2019-02-08 19:02:57 -05:00
client . Version = ">0.0.0-0"
2018-10-31 18:15:08 -04:00
}
2019-02-08 19:02:57 -05:00
name , chart , err := client . NameAndChart ( args )
if err != nil {
return nil , err
2018-10-31 18:15:08 -04:00
}
2019-02-08 19:02:57 -05:00
client . ReleaseName = name
2018-10-31 18:15:08 -04:00
2025-04-14 04:39:09 -04:00
cp , err := client . LocateChart ( chart , settings )
2016-05-18 15:58:10 -04:00
if err != nil {
2019-02-08 19:02:57 -05:00
return nil , err
2016-05-18 15:58:10 -04:00
}
2025-04-10 09:06:03 -04:00
slog . Debug ( "Chart path" , "path" , cp )
2019-02-08 19:02:57 -05:00
2019-08-23 02:31:50 -04:00
p := getter . All ( settings )
vals , err := valueOpts . MergeValues ( p )
2019-08-01 11:04:36 -04:00
if err != nil {
2019-02-08 19:02:57 -05:00
return nil , err
2016-08-01 22:19:27 -04:00
}
2018-11-28 13:20:33 -05:00
// Check chart dependencies to make sure all are present in /charts
2019-02-08 19:02:57 -05:00
chartRequested , err := loader . Load ( cp )
2017-04-07 17:42:15 -04:00
if err != nil {
2019-02-08 19:02:57 -05:00
return nil , err
2017-04-07 17:42:15 -04:00
}
2019-11-19 02:41:15 -05:00
if err := checkIfInstallable ( chartRequested ) ; err != nil {
2019-02-08 19:02:57 -05:00
return nil , err
2019-02-12 10:25:28 -05:00
}
2019-12-13 11:50:25 -05:00
if chartRequested . Metadata . Deprecated {
2025-04-10 09:06:03 -04:00
slog . Warn ( "this chart is deprecated" )
2019-12-13 11:50:25 -05:00
}
2018-11-28 13:20:33 -05:00
if req := chartRequested . Metadata . Dependencies ; req != nil {
2019-02-08 19:02:57 -05:00
// If CheckDependencies returns an error, we have unfulfilled dependencies.
2017-04-27 18:34:18 -04:00
// As of Helm 2.4.0, this is treated as a stopping condition:
2018-11-28 13:08:38 -05:00
// https://github.com/helm/helm/issues/2209
2019-02-08 19:02:57 -05:00
if err := action . CheckDependencies ( chartRequested , req ) ; err != nil {
if client . DependencyUpdate {
2017-08-31 02:19:59 -04:00
man := & downloader . Manager {
2019-08-23 02:31:50 -04:00
Out : out ,
ChartPath : cp ,
2025-04-14 04:39:09 -04:00
Keyring : client . Keyring ,
2019-08-23 02:31:50 -04:00
SkipUpdate : false ,
Getters : p ,
RepositoryConfig : settings . RepositoryConfig ,
RepositoryCache : settings . RepositoryCache ,
2020-04-15 18:17:57 -04:00
Debug : settings . Debug ,
2023-03-28 02:52:16 -04:00
RegistryClient : client . GetRegistryClient ( ) ,
2017-08-31 02:19:59 -04:00
}
if err := man . Update ( ) ; err != nil {
2019-02-08 19:02:57 -05:00
return nil , err
2017-08-31 02:19:59 -04:00
}
2020-04-15 18:17:57 -04:00
// Reload the chart with the updated Chart.lock file.
if chartRequested , err = loader . Load ( cp ) ; err != nil {
2024-11-15 22:07:40 -05:00
return nil , fmt . Errorf ( "failed reloading chart after repo update: %w" , err )
2020-04-15 18:17:57 -04:00
}
2017-08-31 02:19:59 -04:00
} else {
2025-04-21 12:44:40 -04:00
return nil , fmt . Errorf ( "an error occurred while checking for chart dependencies. You may need to run `helm dependency build` to fetch missing dependencies: %w" , err )
2017-02-10 14:16:44 -05:00
}
}
}
2017-04-27 18:34:18 -04:00
2019-10-10 14:35:46 -04:00
client . Namespace = settings . Namespace ( )
2021-07-25 20:04:58 -04:00
2023-01-30 18:04:10 -05:00
// Validate DryRunOption member is one of the allowed values
2023-01-23 14:18:59 -05:00
if err := validateDryRunOptionFlag ( client . DryRunOption ) ; err != nil {
2023-01-16 03:29:19 -05:00
return nil , err
}
2021-07-25 20:04:58 -04:00
// Create context and prepare the handle of SIGTERM
ctx := context . Background ( )
ctx , cancel := context . WithCancel ( ctx )
2021-11-16 06:21:36 -05:00
// Set up channel on which to send signal notifications.
// We must use a buffered channel or risk missing the signal
// if we're not ready to receive when the signal is sent.
cSignal := make ( chan os . Signal , 2 )
2021-07-25 20:04:58 -04:00
signal . Notify ( cSignal , os . Interrupt , syscall . SIGTERM )
go func ( ) {
<- cSignal
2021-08-06 12:54:00 -04:00
fmt . Fprintf ( out , "Release %s has been cancelled.\n" , args [ 0 ] )
2021-07-25 20:04:58 -04:00
cancel ( )
} ( )
return client . RunWithContext ( ctx , chartRequested , vals )
2017-02-10 14:16:44 -05:00
}
2019-05-22 13:38:11 -04:00
2019-11-19 02:41:15 -05:00
// checkIfInstallable validates if a chart can be installed
2019-05-22 13:38:11 -04:00
//
// Application chart type is only installable
2019-11-19 02:41:15 -05:00
func checkIfInstallable ( ch * chart . Chart ) error {
2019-05-22 13:38:11 -04:00
switch ch . Metadata . Type {
case "" , "application" :
2019-11-19 02:41:15 -05:00
return nil
2019-05-22 13:38:11 -04:00
}
2024-11-15 22:07:40 -05:00
return fmt . Errorf ( "%s charts are not installable" , ch . Metadata . Type )
2019-05-22 13:38:11 -04:00
}
2019-12-31 08:42:12 -05:00
// Provide dynamic auto-completion for the install and template commands
2020-04-11 14:06:56 -04:00
func compInstall ( args [ ] string , toComplete string , client * action . Install ) ( [ ] string , cobra . ShellCompDirective ) {
2019-12-31 08:59:10 -05:00
requiredArgs := 1
if client . GenerateName {
requiredArgs = 0
}
if len ( args ) == requiredArgs {
2019-12-31 08:42:12 -05:00
return compListCharts ( toComplete , true )
}
2020-04-11 14:06:56 -04:00
return nil , cobra . ShellCompDirectiveNoFileComp
2019-12-31 08:42:12 -05:00
}
2023-01-16 03:29:19 -05:00
2023-01-23 14:18:59 -05:00
func validateDryRunOptionFlag ( dryRunOptionFlagValue string ) error {
2023-01-30 18:04:10 -05:00
// Validate dry-run flag value with a set of allowed value
2023-01-16 03:29:19 -05:00
allowedDryRunValues := [ ] string { "false" , "true" , "none" , "client" , "server" }
2025-05-01 21:43:25 -04:00
isAllowed := slices . Contains ( allowedDryRunValues , dryRunOptionFlagValue )
2023-01-16 03:29:19 -05:00
if ! isAllowed {
2025-04-21 12:44:40 -04:00
return errors . New ( "invalid dry-run flag. Flag must one of the following: false, true, none, client, server" )
2023-01-16 13:34:01 -05:00
}
2023-01-16 03:29:19 -05:00
return nil
}