github.com/jenkins-x/jx/v2@v2.1.155/pkg/cmd/step/env/step_env_apply.go (about) 1 package env 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "os" 7 "path/filepath" 8 9 "github.com/jenkins-x/jx/v2/pkg/platform" 10 11 "github.com/jenkins-x/jx/v2/pkg/cmd/opts/step" 12 13 "github.com/jenkins-x/jx/v2/pkg/cmd/helper" 14 "github.com/jenkins-x/jx/v2/pkg/cmd/namespace" 15 16 "github.com/ghodss/yaml" 17 v1 "github.com/jenkins-x/jx-api/pkg/apis/jenkins.io/v1" 18 "github.com/jenkins-x/jx-logging/pkg/log" 19 "github.com/jenkins-x/jx/v2/pkg/cmd/opts" 20 helm_cmd "github.com/jenkins-x/jx/v2/pkg/cmd/step/helm" 21 "github.com/jenkins-x/jx/v2/pkg/cmd/templates" 22 "github.com/jenkins-x/jx/v2/pkg/helm" 23 "github.com/jenkins-x/jx/v2/pkg/kube" 24 "github.com/jenkins-x/jx/v2/pkg/util" 25 "github.com/pkg/errors" 26 "github.com/spf13/cobra" 27 ) 28 29 // StepEnvApplyOptions contains the command line flags 30 type StepEnvApplyOptions struct { 31 StepEnvOptions 32 33 Namespace string 34 Dir string 35 ReleaseName string 36 Wait bool 37 Force bool 38 DisableHelmVersion bool 39 ChangeNs bool 40 Vault bool 41 } 42 43 var ( 44 // stepEnvApplyLong long description 45 stepEnvApplyLong = templates.LongDesc(` 46 Applies the GitOps source code (by default in the current directory) to the Environment. 47 48 This command will lazily create an environment, setup Helm and build and apply any helm charts defined in the env/Chart.yaml 49 `) 50 51 // StepEnvApplyExample example 52 stepEnvApplyExample = templates.Examples(` 53 # setup and/or update the helm charts for the environment 54 jx step env apply --namespace jx-staging 55 `) 56 ) 57 58 // NewCmdStepEnvApply registers the command 59 func NewCmdStepEnvApply(commonOpts *opts.CommonOptions) *cobra.Command { 60 options := StepEnvApplyOptions{ 61 StepEnvOptions: StepEnvOptions{ 62 StepOptions: step.StepOptions{ 63 CommonOptions: commonOpts, 64 }, 65 }, 66 } 67 cmd := &cobra.Command{ 68 Use: "apply", 69 Short: "Applies the GitOps source code to an environment", 70 Aliases: []string{""}, 71 Long: stepEnvApplyLong, 72 Example: stepEnvApplyExample, 73 Run: func(cmd *cobra.Command, args []string) { 74 options.Cmd = cmd 75 options.Args = args 76 err := options.Run() 77 helper.CheckErr(err) 78 }, 79 } 80 cmd.Flags().StringVarP(&options.Namespace, "namespace", "n", "", "The Kubernetes namespace to apply the helm charts to") 81 cmd.Flags().StringVarP(&options.ReleaseName, "name", "r", "", "The name of the release") 82 cmd.Flags().StringVarP(&options.Dir, "dir", "d", "", "The directory to look for the environment chart") 83 cmd.Flags().BoolVarP(&options.ChangeNs, "change-namespace", "", false, "Set the given namespace as the current namespace in Kubernetes configuration") 84 cmd.Flags().BoolVarP(&options.Vault, "vault", "", false, "Environment secrets are stored in vault") 85 86 // step helm apply flags 87 cmd.Flags().BoolVarP(&options.Wait, "wait", "", true, "Wait for Kubernetes readiness probe to confirm deployment") 88 cmd.Flags().BoolVarP(&options.Force, "force", "f", true, "Whether to to pass '--force' to helm to help deal with upgrading if a previous promote failed") 89 cmd.Flags().BoolVar(&options.DisableHelmVersion, "no-helm-version", false, "Don't set Chart version before applying") 90 91 return cmd 92 } 93 94 // Run performs the comamand 95 func (o *StepEnvApplyOptions) Run() error { 96 var err error 97 dir := o.Dir 98 if dir == "" { 99 dir, err = os.Getwd() 100 if err != nil { 101 return errors.Wrap(err, "getting the working directory") 102 } 103 } 104 105 ns, err := o.GetDeployNamespace(o.Namespace) 106 if err != nil { 107 return err 108 } 109 kubeClient, err := o.KubeClient() 110 if err != nil { 111 return err 112 } 113 o.SetDevNamespace(ns) 114 115 apisClient, err := o.ApiExtensionsClient() 116 if err != nil { 117 return errors.Wrap(err, "creating the API extensions client") 118 } 119 err = kube.RegisterAllCRDs(apisClient) 120 if err != nil { 121 return errors.Wrap(err, "registering all CRDs") 122 } 123 124 // now lets find the dev environment to know what kind of helmer to use 125 chartFile := filepath.Join(dir, helm.ChartFileName) 126 exists, err := util.FileExists(chartFile) 127 if err != nil { 128 return errors.Wrap(err, "checking if file exits") 129 } 130 if !exists { 131 envDir := filepath.Join(dir, "env") 132 chartFile2 := filepath.Join(envDir, helm.ChartFileName) 133 exists2, err := util.FileExists(chartFile2) 134 if exists2 && err == nil { 135 dir = envDir 136 } else { 137 return fmt.Errorf("there is no Environment chart file at %s or %s\nplease try specify the directory containing the Chart.yaml or env/Chart.yaml with --dir", chartFile, chartFile2) 138 } 139 } 140 devEnvFile := filepath.Join(dir, "templates", "dev-env.yaml") 141 exists, err = util.FileExists(chartFile) 142 if exists && err == nil { 143 // lets setup the Helmer based on the current settings 144 log.Logger().Infof("Loading the latest Dev Environment configuration from %s", devEnvFile) 145 146 env := v1.Environment{} 147 data, err := ioutil.ReadFile(devEnvFile) 148 if err != nil { 149 return errors.Wrapf(err, "loading configuration file %s", devEnvFile) 150 } 151 err = yaml.Unmarshal(data, &env) 152 if err != nil { 153 return errors.Wrapf(err, "unmarshalling YAML file %s", devEnvFile) 154 } 155 156 teamSettings := &env.Spec.TeamSettings 157 158 // disable the modify of the Dev Environment lazily... 159 o.ModifyDevEnvironmentFn = func(callback func(env *v1.Environment) error) error { 160 err = callback(&env) 161 return err 162 } 163 164 helm := o.NewHelm(false, teamSettings.HelmBinary, teamSettings.NoTiller, teamSettings.HelmTemplate) 165 o.SetHelm(helm) 166 167 // ensure there's a development namespace setup 168 err = kube.EnsureDevNamespaceCreatedWithoutEnvironment(kubeClient, ns) 169 if err != nil { 170 return errors.Wrapf(err, "creating namespace %s for development environment", ns) 171 } 172 173 if o.ReleaseName == "" { 174 o.ReleaseName = platform.JenkinsXPlatformRelease 175 } 176 } else { 177 // ensure there's a development namespace setup 178 err = kube.EnsureNamespaceCreated(kubeClient, ns, nil, nil) 179 if err != nil { 180 return errors.Wrapf(err, "creating namespace %s for environment", ns) 181 } 182 } 183 184 // Change the current namesapce before applying the environment step 185 if o.ChangeNs { 186 _, currentNs, err := o.KubeClientAndNamespace() 187 if err != nil { 188 return errors.Wrap(err, "creating the kube client") 189 } 190 if currentNs != ns { 191 nsOptions := &namespace.NamespaceOptions{ 192 CommonOptions: o.CommonOptions, 193 } 194 nsOptions.BatchMode = true 195 nsOptions.Args = []string{ns} 196 err := nsOptions.Run() 197 if err != nil { 198 log.Logger().Warnf("Failed to set context to namespace %s: %s", ns, err) 199 } 200 o.ResetClientsAndNamespaces() 201 } 202 } 203 204 stepHelmBuild := &helm_cmd.StepHelmBuildOptions{ 205 StepHelmOptions: helm_cmd.StepHelmOptions{ 206 StepOptions: step.StepOptions{ 207 CommonOptions: o.CommonOptions, 208 }, 209 Dir: dir, 210 }, 211 } 212 err = stepHelmBuild.Run() 213 if err != nil { 214 return errors.Wrapf(err, "building helm chart in dir %s", dir) 215 } 216 217 stepApply := &helm_cmd.StepHelmApplyOptions{ 218 StepHelmOptions: stepHelmBuild.StepHelmOptions, 219 Namespace: ns, 220 ReleaseName: o.ReleaseName, 221 Wait: o.Wait, 222 DisableHelmVersion: o.DisableHelmVersion, 223 Force: o.Force, 224 Vault: o.Vault, 225 } 226 err = stepApply.Run() 227 if err != nil { 228 return errors.Wrapf(err, "applying the helm chart in dir %s", dir) 229 } 230 log.Logger().Infof("Environment applied in namespace %s", util.ColorInfo(ns)) 231 return nil 232 }