github.com/olli-ai/jx/v2@v2.0.400-0.20210921045218-14731b4dd448/pkg/cmd/add/add_app.go (about) 1 package add 2 3 import ( 4 "fmt" 5 6 "github.com/olli-ai/jx/v2/pkg/cmd/helper" 7 8 "github.com/olli-ai/jx/v2/pkg/cmd/opts" 9 "github.com/olli-ai/jx/v2/pkg/cmd/templates" 10 11 "github.com/olli-ai/jx/v2/pkg/apps" 12 13 "github.com/olli-ai/jx/v2/pkg/io/secrets" 14 15 "github.com/olli-ai/jx/v2/pkg/util" 16 17 jenkinsv1 "github.com/jenkins-x/jx-api/pkg/apis/jenkins.io/v1" 18 19 "github.com/olli-ai/jx/v2/pkg/kube" 20 "github.com/pkg/errors" 21 "github.com/spf13/cobra" 22 ) 23 24 // AddAppOptions the options for the create spring command 25 type AddAppOptions struct { 26 AddOptions 27 28 GitOps bool 29 DevEnv *jenkinsv1.Environment 30 31 Repo string 32 Username string 33 Password string 34 Alias string 35 Prefixes []string 36 Namespace string 37 Version string 38 ReleaseName string 39 SetValues []string 40 ValuesFiles []string 41 HelmUpdate bool 42 AutoMerge bool 43 44 // Used for testing 45 CloneDir string 46 } 47 48 const ( 49 optionHelmUpdate = "helm-update" 50 optionValues = "values" 51 optionSet = "set" 52 optionAlias = "alias" 53 optionNamespace = "namespace" 54 ) 55 56 var ( 57 add_app_long = templates.LongDesc(` 58 Adds an App to Jenkins X (an app is similar to an addon), 59 `) 60 add_app_example = templates.Examples(` 61 # Add an app 62 jx add app jx-app-jacoco 63 64 # Add an app from a local path 65 jx add app . 66 67 # Add an app from git repository 68 jx add app https://github.com/jenkins-x-apps/jx-app-kubeless.git 69 `) 70 ) 71 72 // NewCmdAddApp creates a command object for the "create" command 73 func NewCmdAddApp(commonOpts *opts.CommonOptions) *cobra.Command { 74 options := &AddAppOptions{ 75 AddOptions: AddOptions{ 76 CommonOptions: commonOpts, 77 }, 78 } 79 80 cmd := &cobra.Command{ 81 Use: "app", 82 Short: "Adds an App (an app is similar to an addon)", 83 Long: add_app_long, 84 Example: add_app_example, 85 Run: func(cmd *cobra.Command, args []string) { 86 options.Cmd = cmd 87 options.Args = args 88 err := options.Run() 89 helper.CheckErr(err) 90 }, 91 } 92 93 options.addFlags(cmd, kube.DefaultNamespace) 94 return cmd 95 } 96 97 func (o *AddAppOptions) addFlags(cmd *cobra.Command, defaultNamespace string) { 98 99 // Common flags 100 101 cmd.Flags().StringVarP(&o.Version, "version", "v", "", 102 "The chart version to install") 103 cmd.Flags().StringVarP(&o.Repo, "repository", "", "", 104 "The repository from which the app should be installed (default specified in your dev environment)") 105 cmd.Flags().StringVarP(&o.Username, "username", "", "", 106 "The username for the repository") 107 cmd.Flags().StringVarP(&o.Password, "password", "", "", 108 "The password for the repository") 109 cmd.Flags().StringVarP(&o.Alias, optionAlias, "", "", 110 "An alias to use for the app if you wish to install multiple instances of the same app") 111 cmd.Flags().BoolVarP(&o.HelmUpdate, optionHelmUpdate, "", true, 112 "Should we run helm update first to ensure we use the latest version (available when NOT using GitOps for your dev environment)") 113 cmd.Flags().StringVarP(&o.Namespace, optionNamespace, "n", "", "The Namespace to install into (available when NOT using GitOps for your dev environment)") 114 cmd.Flags().StringArrayVarP(&o.ValuesFiles, optionValues, "f", []string{}, "List of locations for values files, "+ 115 "can be local files or URLs (available when NOT using GitOps for your dev environment)") 116 cmd.Flags().StringArrayVarP(&o.SetValues, optionSet, "s", []string{}, 117 "The chart set values (can specify multiple or separate values with commas: key1=val1,key2=val2) (available when NOT using GitOps for your dev environment)") 118 cmd.Flags().BoolVarP(&o.AutoMerge, "auto-merge", "", false, "Automatically merge GitOps pull requests that pass CI") 119 } 120 121 // Run implements this command 122 func (o *AddAppOptions) Run() error { 123 o.GitOps, o.DevEnv = o.GetDevEnv() 124 if o.DevEnv == nil { 125 return helper.ErrDevEnvNotFound 126 } 127 if o.Repo == "" { 128 o.Repo = o.DevEnv.Spec.TeamSettings.AppsRepository 129 } 130 if o.Repo == "" { 131 o.Repo = kube.DefaultChartMuseumURL 132 } 133 134 jxClient, ns, err := o.JXClientAndDevNamespace() 135 if err != nil { 136 return errors.Wrapf(err, "getting jx client") 137 } 138 kubeClient, _, err := o.KubeClientAndDevNamespace() 139 if err != nil { 140 return errors.Wrapf(err, "getting kubeClient") 141 } 142 if o.Namespace == "" { 143 o.Namespace = ns 144 } 145 installOpts := apps.InstallOptions{ 146 IOFileHandles: o.GetIOFileHandles(), 147 DevEnv: o.DevEnv, 148 Verbose: o.Verbose, 149 GitOps: o.GitOps, 150 BatchMode: o.BatchMode, 151 AutoMerge: o.AutoMerge, 152 SecretsScheme: "vault", 153 154 Helmer: o.Helm(), 155 Namespace: o.Namespace, 156 KubeClient: kubeClient, 157 JxClient: jxClient, 158 InstallTimeout: opts.DefaultInstallTimeout, 159 EnvironmentCloneDir: o.CloneDir, 160 } 161 162 if o.GitOps { 163 msg := "unable to specify --%s when using GitOps for your dev environment" 164 if !o.HelmUpdate { 165 return util.InvalidOptionf(optionHelmUpdate, o.HelmUpdate, msg, optionHelmUpdate) 166 } 167 if o.Namespace != "" && o.Namespace != kube.DefaultNamespace { 168 return util.InvalidOptionf(optionNamespace, o.Namespace, msg, optionNamespace) 169 } 170 if len(o.SetValues) > 0 { 171 return util.InvalidOptionf(optionSet, o.SetValues, msg, optionSet) 172 } 173 if len(o.ValuesFiles) > 1 { 174 return util.InvalidOptionf(optionValues, o.SetValues, 175 "no more than one --%s can be specified when using GitOps for your dev environment", optionValues) 176 } 177 178 gitProvider, _, err := o.CreateGitProviderForURLWithoutKind(o.DevEnv.Spec.Source.URL) 179 if err != nil { 180 return errors.Wrapf(err, "creating git provider for %s", o.DevEnv.Spec.Source.URL) 181 } 182 installOpts.GitProvider = gitProvider 183 installOpts.Gitter = o.Git() 184 } 185 if !o.GitOps { 186 if o.Alias != "" && o.ReleaseName == "" { 187 bin, noTiller, helmTemplate, err := o.TeamHelmBin() 188 if err != nil { 189 return err 190 } 191 if bin != "helm" || noTiller || helmTemplate { 192 o.ReleaseName = o.Alias 193 } else { 194 o.ReleaseName = o.Alias + "-" + o.Namespace 195 } 196 } 197 198 } 199 err = o.EnsureHelm() 200 if err != nil { 201 return errors.Wrap(err, "failed to ensure that helm is present") 202 } 203 if o.GetSecretsLocation() == secrets.VaultLocationKind { 204 teamName, _, err := o.TeamAndEnvironmentNames() 205 if err != nil { 206 return err 207 } 208 installOpts.TeamName = teamName 209 client, err := o.SystemVaultClient("") 210 if err != nil { 211 return err 212 } 213 installOpts.VaultClient = client 214 } 215 216 args := o.Args 217 if len(args) == 0 { 218 return o.Cmd.Help() 219 } 220 if len(args) > 1 { 221 return o.Cmd.Help() 222 } 223 224 if o.Repo == "" { 225 return fmt.Errorf("must specify a repository") 226 } 227 228 var version string 229 if o.Version != "" { 230 version = o.Version 231 } 232 app := args[0] 233 return installOpts.AddApp(app, version, o.Repo, o.Username, o.Password, o.ReleaseName, o.ValuesFiles, o.SetValues, 234 o.Alias, o.HelmUpdate) 235 } 236 237 // TODO create test for GitOps