-
Notifications
You must be signed in to change notification settings - Fork 0
/
deploy.go
321 lines (283 loc) · 9.66 KB
/
deploy.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
// Copyright © 2017 Chef Software
package main
import (
"fmt"
"os"
"path"
"github.com/spf13/cobra"
dc "github.com/chef/automate/api/config/deployment"
api "github.com/chef/automate/api/interservice/deployment"
"github.com/chef/automate/components/automate-cli/pkg/status"
"github.com/chef/automate/components/automate-deployment/pkg/airgap"
"github.com/chef/automate/components/automate-deployment/pkg/client"
"github.com/chef/automate/components/automate-deployment/pkg/manifest"
mc "github.com/chef/automate/components/automate-deployment/pkg/manifest/client"
"github.com/chef/automate/lib/version"
)
var deployLong = `Deploy a new Chef Automate instance using the supplied configuration.
- <CONFIG_FILE> must be a valid path to a TOML formatted configuration file`
var promptMLSA = `
To continue, you'll need to accept our terms of service:
Terms of Service
https://www.chef.io/terms-of-service
Master License and Services Agreement
https://www.chef.io/online-master-agreement
I agree to the Terms of Service and the Master License and Services Agreement
`
var errMLSA = "Chef Software Terms of Service and Master License and Services Agreement were not accepted"
var deployCmdFlags = struct {
channel string
upgradeStrategy string
keyPath string
certPath string
adminPassword string
hartifactsPath string
overrideOrigin string
manifestDir string
fqdn string
airgap string
skipPreflight bool
acceptMLSA bool
enableChefServer bool
enableDeploymentOrderStressMode bool
enableWorkflow bool
}{}
// deployCmd represents the new command
var deployCmd = newDeployCmd()
func init() {
RootCmd.AddCommand(deployCmd)
}
func newDeployCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "deploy [/path/to/config.toml]",
Short: "Deploy Chef Automate",
Long: deployLong,
Annotations: map[string]string{
NoCheckVersionAnnotation: NoCheckVersionAnnotation,
},
Args: cobra.RangeArgs(0, 1),
RunE: runDeployCmd,
}
// flags for Deploy Command
cmd.PersistentFlags().BoolVar(
&deployCmdFlags.skipPreflight,
"skip-preflight",
false,
"Deploy regardless of pre-flight conditions")
cmd.PersistentFlags().StringVar(
&deployCmdFlags.overrideOrigin,
"override-origin",
"",
"Optional origin to install local .hart packages from")
cmd.PersistentFlags().StringVar(
&deployCmdFlags.hartifactsPath,
"hartifacts",
"",
"Optional path to cache of local .hart packages")
cmd.PersistentFlags().StringVar(
&deployCmdFlags.manifestDir,
"manifest-dir",
"",
"Optional path to local automate manifest files")
cmd.PersistentFlags().StringVar(
&deployCmdFlags.channel,
"channel",
"",
"Release channel to deploy all services from")
cmd.PersistentFlags().StringVar(
&deployCmdFlags.upgradeStrategy,
"upgrade-strategy",
"at-once",
"Upgrade strategy to use for this deployment.")
cmd.PersistentFlags().StringVar(
&deployCmdFlags.certPath,
"certificate",
"",
"The path to a certificate that should be used for external TLS connections (web and API).")
cmd.PersistentFlags().StringVar(
&deployCmdFlags.keyPath,
"private-key",
"",
"The path to a private key corresponding to the TLS certificate.")
cmd.PersistentFlags().StringVar(
&deployCmdFlags.adminPassword,
"admin-password",
"",
"The password for the initial admin user. Auto-generated by default.")
cmd.PersistentFlags().BoolVar(
&deployCmdFlags.acceptMLSA,
"accept-terms-and-mlsa",
false,
"Agree to the Chef Software Terms of Service and the Master License and Services Agreement")
cmd.PersistentFlags().StringVar(
&deployCmdFlags.fqdn,
"fqdn",
"",
"The fully-qualified domain name that Chef Automate can be accessed at. (default: hostname of this machine)")
cmd.PersistentFlags().StringVar(
&deployCmdFlags.airgap,
"airgap-bundle",
"",
"Path to an airgap install bundle")
cmd.PersistentFlags().BoolVar(
&deployCmdFlags.enableChefServer,
"enable-chef-server",
false,
"Deploy Chef Server services along with Chef Automate")
cmd.PersistentFlags().BoolVar(
&deployCmdFlags.enableDeploymentOrderStressMode,
"enable-deploy-order-stress-mode",
false,
"Deploy services in the order that stresses hab the most")
cmd.PersistentFlags().BoolVar(
&deployCmdFlags.enableWorkflow,
"enable-workflow",
false,
"Deploy Workflow services along with Chef Automate")
if !isDevMode() {
for _, flagName := range []string{
"override-origin",
"hartifacts",
"manifest-dir",
// passwords are not validated until the end of the deploy, which makes this
// feature dangerous. But we still want to have it in Ci, so we mark it as
// hidden
"admin-password",
"enable-chef-server",
"enable-deploy-order-stress-mode",
"enable-workflow",
} {
err := cmd.PersistentFlags().MarkHidden(flagName)
if err != nil {
fmt.Printf("failed configuring cobra: %s\n", err.Error())
panic(":(")
}
}
}
return cmd
}
func runDeployCmd(cmd *cobra.Command, args []string) error {
if !deployCmdFlags.acceptMLSA {
agree, err := writer.Confirm(promptMLSA)
if err != nil {
return status.Wrap(err, status.InvalidCommandArgsError, errMLSA)
}
if !agree {
return status.New(status.InvalidCommandArgsError, errMLSA)
}
}
if deployCmdFlags.keyPath != "" && deployCmdFlags.certPath == "" {
msg := "Cannot provide --private-key without also providing --certificate."
return status.New(status.InvalidCommandArgsError, msg)
}
if deployCmdFlags.certPath != "" && deployCmdFlags.keyPath == "" {
msg := "cannot provide --certificate without also providing --private-key."
return status.New(status.InvalidCommandArgsError, msg)
}
conf := new(dc.AutomateConfig)
var err error
if len(args) == 0 {
// Use default configuration if no configuration file was provided
conf, err = generatedConfig()
if err != nil {
return status.Annotate(err, status.ConfigError)
}
} else {
conf, err = dc.LoadUserOverrideConfigFile(args[0])
if err != nil {
return status.Wrapf(
err,
status.ConfigError,
"Loading configuration file %s failed",
args[0],
)
}
}
if err = mergeFlagOverrides(conf); err != nil {
return status.Wrap(
err,
status.ConfigError,
"Merging command flag overrides into Chef Automate config failed",
)
}
adminPassword := deployCmdFlags.adminPassword
if adminPassword == "" {
adminPassword, err = dc.GeneratePassword()
if err != nil {
return status.Wrap(err, status.ConfigError, "Generating the admin user password failed")
}
}
err = conf.AddCredentials("Local Administrator", "admin", adminPassword)
if err != nil {
return status.Wrap(err, status.ConfigError, "Applying the admin user password to configuration failed")
}
offlineMode := deployCmdFlags.airgap != ""
manifestPath := ""
if offlineMode {
writer.Title("Installing artifact")
metadata, err := airgap.Unpack(deployCmdFlags.airgap)
if err != nil {
return status.Annotate(err, status.AirgapUnpackInstallBundleError)
}
manifestPath = api.AirgapManifestPath
// We need to set the path for the hab binary so that the deployer does not
// try to go to the internet to get it
pathEnv := os.Getenv("PATH")
err = os.Setenv("PATH", fmt.Sprintf("%s:%s", path.Dir(metadata.HabBinPath), pathEnv))
if err != nil {
return err
}
} else {
manifestPath = conf.Deployment.GetV1().GetSvc().GetManifestDirectory().GetValue()
}
manifestProvider := manifest.NewLocalHartManifestProvider(
mc.NewDefaultClient(manifestPath),
conf.Deployment.GetV1().GetSvc().GetHartifactsPath().GetValue(),
conf.Deployment.GetV1().GetSvc().GetOverrideOrigin().GetValue())
err = client.Deploy(writer, conf, deployCmdFlags.skipPreflight, manifestProvider, version.BuildTime, offlineMode)
if err != nil && !status.IsStatusError(err) {
return status.Annotate(err, status.DeployError)
}
return err
}
func generatedConfig() (*dc.AutomateConfig, error) {
cfg, err := dc.GenerateInitConfig(
deployCmdFlags.channel,
deployCmdFlags.upgradeStrategy,
dc.InitialTLSCerts(deployCmdFlags.keyPath, deployCmdFlags.certPath),
dc.InitialFQDN(deployCmdFlags.fqdn),
)
if err != nil {
return nil, status.Wrap(err, status.ConfigError, "Generating initial default configuration failed")
}
return cfg.AutomateConfig(), nil
}
// mergeFlagOverrides merges the flag provided configuration options into the
// user override config. Because the override configuration will be persisted
// we only want to add overrides for flags that have been specifically set so
// that we don't accidentally set an override with a default value.
func mergeFlagOverrides(conf *dc.AutomateConfig) error {
overrideOpts := []dc.AutomateConfigOpt{}
if deployCmdFlags.manifestDir != "" {
overrideOpts = append(overrideOpts, dc.WithManifestDir(deployCmdFlags.manifestDir))
}
if deployCmdFlags.channel != "" {
overrideOpts = append(overrideOpts, dc.WithChannel(deployCmdFlags.channel))
}
if deployCmdFlags.hartifactsPath != "" {
overrideOpts = append(overrideOpts, dc.WithHartifacts(deployCmdFlags.hartifactsPath))
}
if deployCmdFlags.overrideOrigin != "" {
overrideOpts = append(overrideOpts, dc.WithOrigin(deployCmdFlags.overrideOrigin))
}
if deployCmdFlags.enableChefServer {
overrideOpts = append(overrideOpts, dc.WithChefServerEnabled(true))
}
if deployCmdFlags.enableDeploymentOrderStressMode {
overrideOpts = append(overrideOpts, dc.WithDeploymentOrderStressMode(true))
}
if deployCmdFlags.enableWorkflow {
overrideOpts = append(overrideOpts, dc.WithWorkflowEnabled(true))
}
return dc.WithConfigOptions(conf, overrideOpts...)
}