Skip to content

Commit 46ad1cd

Browse files
authored
cmd: add instance flags to deployment create command (#224)
Adds instance definition flags to the `ecctl deployment create` command so it is not necessary to use a predefined deployment definition JSON file. Things to note: - All deployments must at least have one ES and one Kibana instance. This mimics the UI. - For now each resource type that is being created makes a call to retrieve the deployment template definition. This is far from ideal, but the `deployment {kibana | apm | appsearch} create` commands use the same functions to update deployments with new instances. Refactoring this falls out of the scope of this PR. I will write a separate issue to integrate the `deployment {kibana | apm | appsearch} create` commands into the `deployment update` command which will address this issue and have the `deployment update` command act in a similar way to the `deployment create` command with the newly introduced flags. - I have added `params.DeploymentID != "" && len(params.DeploymentID) != 32` to the `NewStateless` validation as a temporary measure until the above has been implemented. - I have removed all output examples from the help text that weren't strictly necessary. - The links on the help documentation don't work yet, but they will once the ESS public API is released
1 parent 84cf2ce commit 46ad1cd

File tree

10 files changed

+895
-225
lines changed

10 files changed

+895
-225
lines changed

cmd/deployment/create.go

Lines changed: 125 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -32,136 +32,108 @@ import (
3232
"github.com/elastic/ecctl/pkg/util"
3333
)
3434

35-
const createLong = `Creates a deployment from a file definition with an automatically generated idempotency token.
36-
On creation failure, please use the displayed idempotency token to retry the cluster creation with --request-id=<token>.
37-
To track the creation of the resources toggle the --track flag.
38-
39-
Read more about the deployment definition in https://www.elastic.co/guide/en/cloud-enterprise/current/Deployment_-_CRUD.html`
40-
41-
var createExample = `
42-
$ cat deployment_example.json
43-
{
44-
"name": "my example cluster",
45-
"resources": {
46-
"apm": [
47-
{
48-
"display_name": "my apm instance",
49-
"ref_id": "my-apm-instance",
50-
"elasticsearch_cluster_ref_id": "my-es-cluster",
51-
"plan": {
52-
"apm": {
53-
"version": "6.8.4"
54-
},
55-
"cluster_topology": [{
56-
"instance_configuration_id": "apm",
57-
"size": {
58-
"resource": "memory",
59-
"value": 512
60-
},
61-
"zone_count": 1
62-
}]
63-
}
64-
}
65-
],
66-
"elasticsearch": [
67-
{
68-
"display_name": "my elasticsearch cluster",
69-
"ref_id": "my-es-cluster",
70-
"plan": {
71-
"deployment_template": {
72-
"id": "default"
73-
},
74-
"elasticsearch": {
75-
"version": "6.8.4"
76-
},
77-
"cluster_topology": [
78-
{
79-
"instance_configuration_id": "data.default",
80-
"memory_per_node": 1024,
81-
"node_count_per_zone": 1,
82-
"node_type": {
83-
"data": true,
84-
"ingest": true,
85-
"master": true,
86-
"ml": false
87-
},
88-
"zone_count": 1
89-
}
90-
]
91-
}
92-
}
93-
],
94-
"kibana": [
95-
{
96-
"display_name": "my kibana instance",
97-
"ref_id": "my-kibana-instance",
98-
"elasticsearch_cluster_ref_id": "my-es-cluster",
99-
"plan": {
100-
"kibana": {
101-
"version": "6.8.4"
102-
},
103-
"cluster_topology": [
104-
{
105-
"instance_configuration_id": "kibana",
106-
"memory_per_node": 1024,
107-
"node_count_per_zone": 1,
108-
"zone_count": 1
109-
}
110-
]
111-
}
112-
}
113-
]
114-
}
115-
}
116-
$ ecctl deployment create -f deployment_example.json --version=7.4.1
117-
[...]
118-
119-
## If the previous deployment creation failed
120-
$ ecctl deployment create -f deployment_example.json --name adeploy --version=7.4.1
121-
The deployment creation returned with an error, please use the displayed idempotency token
122-
to recreate the deployment resources
123-
Idempotency token: GMZPMRrcMYqHdmxjIQkHbdjnhPIeBElcwrHwzVlhGUSMXrEIzVXoBykSVRsKncNb
124-
unknown error (status 500)
125-
$ ecctl deployment create -f deployment_example.json --name adeploy --version=7.4.1 --request-id=GMZPMRrcMYqHdmxjIQkHbdjnhPIeBElcwrHwzVlhGUSMXrEIzVXoBykSVRsKncNb
126-
[...]`[1:]
127-
12835
var createCmd = &cobra.Command{
129-
Use: `create -f <file definition.json>`,
130-
Short: "Creates a deployment from a file definition, allowing certain flag overrides",
36+
Use: "create {--file | --size <int> --zones <string> | --topology-element <obj>}",
37+
Short: "Creates a deployment",
38+
PreRunE: cobra.MaximumNArgs(0),
13139
Long: createLong,
13240
Example: createExample,
133-
PreRunE: cobra.NoArgs,
13441
RunE: func(cmd *cobra.Command, args []string) error {
135-
filename, _ := cmd.Flags().GetString("file")
136-
var r models.DeploymentCreateRequest
137-
if err := sdkcmdutil.DecodeFile(filename, &r); err != nil {
138-
return err
42+
var track, _ = cmd.Flags().GetBool("track")
43+
var generatePayload, _ = cmd.Flags().GetBool("generate-payload")
44+
var name, _ = cmd.Flags().GetString("name")
45+
var version, _ = cmd.Flags().GetString("version")
46+
var dt, _ = cmd.Flags().GetString("deployment-template")
47+
48+
var zoneCount, _ = cmd.Flags().GetInt32("zones")
49+
var size, _ = cmd.Flags().GetInt32("size")
50+
var esRefID, _ = cmd.Flags().GetString("ref-id")
51+
var te, _ = cmd.Flags().GetStringArray("topology-element")
52+
var plugin, _ = cmd.Flags().GetStringSlice("plugin")
53+
54+
var kibanaZoneCount, _ = cmd.Flags().GetInt32("kibana-zones")
55+
var kibanaSize, _ = cmd.Flags().GetInt32("kibana-size")
56+
var kibanaRefID, _ = cmd.Flags().GetString("kibana-ref-id")
57+
58+
var apmEnable, _ = cmd.Flags().GetBool("apm")
59+
var apmZoneCount, _ = cmd.Flags().GetInt32("apm-zones")
60+
var apmSize, _ = cmd.Flags().GetInt32("apm-size")
61+
var apmRefID, _ = cmd.Flags().GetString("apm-ref-id")
62+
63+
var appsearchEnable, _ = cmd.Flags().GetBool("appsearch")
64+
var appsearchZoneCount, _ = cmd.Flags().GetInt32("appsearch-zones")
65+
var appsearchSize, _ = cmd.Flags().GetInt32("appsearch-size")
66+
var appsearchRefID, _ = cmd.Flags().GetString("appsearch-ref-id")
67+
68+
region := ecctl.Get().Config.Region
69+
if region == "" {
70+
region = cmdutil.DefaultECERegion
13971
}
14072

141-
var region = ecctl.Get().Config.Region
142-
if ecctl.Get().Config.Region == "" {
143-
region = cmdutil.DefaultECERegion
73+
var payload *models.DeploymentCreateRequest
74+
if err := sdkcmdutil.FileOrStdin(cmd, "file"); err == nil {
75+
err := sdkcmdutil.DecodeDefinition(cmd, "file", &payload)
76+
if err != nil && err != sdkcmdutil.ErrNodefinitionLoaded {
77+
return err
78+
}
79+
}
80+
81+
if payload == nil {
82+
var err error
83+
payload, err = depresource.New(depresource.NewParams{
84+
API: ecctl.Get().API,
85+
Name: name,
86+
DeploymentTemplateID: dt,
87+
Version: version,
88+
Region: region,
89+
Writer: ecctl.Get().Config.ErrorDevice,
90+
Plugins: plugin,
91+
TopologyElements: te,
92+
ApmEnable: apmEnable,
93+
AppsearchEnable: appsearchEnable,
94+
ElasticsearchInstance: depresource.InstanceParams{
95+
RefID: esRefID,
96+
Size: size,
97+
ZoneCount: zoneCount,
98+
},
99+
KibanaInstance: depresource.InstanceParams{
100+
RefID: kibanaRefID,
101+
Size: kibanaSize,
102+
ZoneCount: kibanaZoneCount,
103+
},
104+
ApmInstance: depresource.InstanceParams{
105+
RefID: apmRefID,
106+
Size: apmSize,
107+
ZoneCount: apmZoneCount,
108+
},
109+
AppsearchInstance: depresource.InstanceParams{
110+
RefID: appsearchRefID,
111+
Size: appsearchSize,
112+
ZoneCount: appsearchZoneCount,
113+
},
114+
})
115+
if err != nil {
116+
return err
117+
}
144118
}
145119

146-
name, _ := cmd.Flags().GetString("name")
147-
version, _ := cmd.Flags().GetString("version")
120+
// Returns the DeploymentCreateRequest skipping the creation of the resources.
121+
if generatePayload {
122+
return ecctl.Get().Formatter.Format("", payload)
123+
}
148124

149125
reqID, _ := cmd.Flags().GetString("request-id")
150126
if reqID == "" {
151127
reqID = util.RandomString(64)
152128
}
153129

154-
res, err := deployment.Create(deployment.CreateParams{
130+
var createParams = deployment.CreateParams{
155131
API: ecctl.Get().API,
156132
RequestID: reqID,
157-
Request: &r,
158-
Overrides: &deployment.PayloadOverrides{
159-
Name: name,
160-
Region: region,
161-
Version: version,
162-
},
163-
})
133+
Request: payload,
134+
}
164135

136+
res, err := deployment.Create(createParams)
165137
if err != nil {
166138
fmt.Fprintln(os.Stderr,
167139
"The deployment creation returned with an error, please use the displayed idempotency token to recreate the deployment resources",
@@ -170,27 +142,52 @@ var createCmd = &cobra.Command{
170142
return err
171143
}
172144

173-
var track, _ = cmd.Flags().GetBool("track")
174-
return cmdutil.Track(cmdutil.TrackParams{
175-
TrackResourcesParams: depresource.TrackResourcesParams{
176-
API: ecctl.Get().API,
177-
Resources: res.Resources,
178-
OutputDevice: ecctl.Get().Config.OutputDevice,
179-
},
180-
Formatter: ecctl.Get().Formatter,
181-
Track: track,
182-
Response: res,
145+
if err := ecctl.Get().Formatter.Format("", res); err != nil {
146+
if !track {
147+
return err
148+
}
149+
fmt.Fprintln(ecctl.Get().Config.OutputDevice, err)
150+
}
151+
152+
if !track {
153+
return nil
154+
}
155+
156+
return depresource.TrackResources(depresource.TrackResourcesParams{
157+
API: ecctl.Get().API,
158+
Resources: res.Resources,
159+
OutputDevice: ecctl.Get().Config.OutputDevice,
183160
})
184161
},
185162
}
186163

187164
func init() {
188165
Command.AddCommand(createCmd)
166+
createCmd.Flags().StringP("file", "f", "", "DeploymentCreateRequest file definition. See help for more information")
167+
createCmd.Flags().String("deployment-template", "default", "Deployment template ID on which to base the deployment from")
168+
createCmd.Flags().String("version", "", "Version to use, if not specified, the latest available stack version will be used")
169+
createCmd.Flags().String("name", "", "Optional name for the deployment")
189170
createCmd.Flags().BoolP("track", "t", false, cmdutil.TrackFlagMessage)
190-
createCmd.Flags().String("name", "", "Overrides the deployment name")
191-
createCmd.Flags().String("version", "", "Overrides all the deployment's resources to the specified version")
171+
createCmd.Flags().Bool("generate-payload", false, "Returns the deployment payload without actually creating the deployment resources")
192172
createCmd.Flags().String("request-id", "", "Optional idempotency token - Can be found in the Stderr device when a previous deployment creation failed, for more information see the examples in the help command page")
193-
createCmd.Flags().StringP("file", "f", "", "JSON file that contains JSON-style domain-specific deployment definition")
194-
createCmd.MarkFlagRequired("file")
195-
createCmd.MarkFlagFilename("file", "*.json")
173+
174+
createCmd.Flags().String("ref-id", "main-elasticsearch", "Optional RefId for the Elasticsearch deployment")
175+
createCmd.Flags().Int32("zones", 1, "Number of zones the Elasticsearch instances will span")
176+
createCmd.Flags().Int32("size", 4096, "Memory (RAM) in MB that each of the Elasticsearch instances will have")
177+
createCmd.Flags().StringArrayP("topology-element", "e", nil, "Optional Elasticsearch topology element definition. See help for more information")
178+
createCmd.Flags().StringSlice("plugin", nil, "Additional plugins to add to the Elasticsearch deployment")
179+
180+
createCmd.Flags().String("kibana-ref-id", "main-kibana", "Optional RefId for the Kibana deployment")
181+
createCmd.Flags().Int32("kibana-zones", 1, "Number of zones the Kibana instances will span")
182+
createCmd.Flags().Int32("kibana-size", 1024, "Memory (RAM) in MB that each of the Kibana instances will have")
183+
184+
createCmd.Flags().Bool("apm", false, "Enables APM for the deployment")
185+
createCmd.Flags().String("apm-ref-id", "main-apm", "Optional RefId for the APM deployment")
186+
createCmd.Flags().Int32("apm-zones", 1, "Number of zones the APM instances will span")
187+
createCmd.Flags().Int32("apm-size", 512, "Memory (RAM) in MB that each of the APM instances will have")
188+
189+
createCmd.Flags().Bool("appsearch", false, "Enables AppSearch for the deployment")
190+
createCmd.Flags().String("appsearch-ref-id", "main-appsearch", "Optional RefId for the AppSearch deployment")
191+
createCmd.Flags().Int32("appsearch-zones", 1, "Number of zones the AppSearch instances will span")
192+
createCmd.Flags().Int32("appsearch-size", 2048, "Memory (RAM) in MB that each of the AppSearch instances will have")
196193
}

cmd/deployment/create_help.go

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// Licensed to Elasticsearch B.V. under one or more contributor
2+
// license agreements. See the NOTICE file distributed with
3+
// this work for additional information regarding copyright
4+
// ownership. Elasticsearch B.V. licenses this file to you under
5+
// the Apache License, Version 2.0 (the "License"); you may
6+
// not use this file except in compliance with the License.
7+
// You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package cmddeployment
19+
20+
const (
21+
createLong = `Creates a deployment which can be defined through flags or from a file definition.
22+
Sane default values are provided, making the command work out of the box even when no parameters are set.
23+
When version is not specified, the latest available stack version will automatically be used.
24+
These are the available options:
25+
26+
* Simplified flags to set size and zone count for each instance type (Elasticsearch, Kibana, APM and AppSearch).
27+
* Advanced flag for different Elasticsearch node types: --topology-element <json obj> (shorthand: -e).
28+
Note that the flag can be specified multiple times for complex topologies.
29+
The JSON object has the following format:
30+
{
31+
"name": "["data", "master", "ml"]" # type string
32+
"size": 1024 # type int32
33+
"zone_count": 1 # type int32
34+
}
35+
* File definition: --file=<file path> (shorthand: -f). You can create a definition by using the sample JSON seen here:
36+
https://elastic.co/guide/en/cloud/current/ec-api-deployment-crud.html#ec_create_a_deployment
37+
38+
As an option "--generate-payload" can be used in order to obtain the generated payload that would be sent as a request.
39+
Save it, update or extend the topology and create a deployment using the saved payload with the "--file" flag.`
40+
41+
createExample = `## Create a deployment with the default values for Elasticsearch, a Kibana instance with a modified size,
42+
and a default APM instance. While Elasticsearch and Kibana come enabled by default, both APM and AppSearch need to be
43+
enabled by using the "--apm" and "--appsearch" flags. The command will exit after the API response has been returned, without
44+
waiting until the deployment resources have been created.
45+
$ ecctl deployment create --name my-deployment --zones 2 --kibana-size 2048 --apm --apm-size 1024
46+
47+
## To make the command wait until the resources have been created use the "--track" flag, which will output
48+
the current stage on which the deployment resources are in.
49+
$ deployment create --name my-deployment --track
50+
[...]
51+
Cluster [38e0ff5b58a9483c96a98c923b22194e][Elasticsearch]: finished running all the plan steps (Total plan duration: 1m0.911628175s)
52+
Cluster [51178ffc645d48b7859dbf17388a6c35][Kibana]: finished running all the plan steps (Total plan duration: 1m11.246662764s)
53+
54+
## Additionally, a more advanced topology for Elasticsearch can be created through "--topology-element" or shorthand "-e".
55+
The following command will create a deployment with two 1GB Elasticsearch instances of the type "data" and
56+
one 1GB Elasticsearch instance of the type "ml".
57+
$ ecctl deployment create --name my-deployment --topology-element '{"size": 1024, "zone_count": 2, "name": "data"}' --topology-element '{"size": 1024, "zone_count": 1, "name": "ml"}'
58+
59+
## In order to use the "--deployment-template" flag, you'll need to know which deployment templates ara available to you.
60+
Visit https://elastic.co/guide/en/cloud/current/ec-regions-templates-instances.html.
61+
If you are an Elastic Cloud Enterprise customer, you'll need to run the following command to view your deployment templates:
62+
$ ecctl platform deployment-template list
63+
64+
## Use the "--generate-payload" flag to save the definition to a file for later use.
65+
$ ecctl deployment create --name my-deployment --size 1024 --track --generate-payload --zones 2 > elasticsearch_create_example.json
66+
67+
## Create a deployment through the file definition.
68+
$ ecctl deployment create --file elasticsearch_create_example.json --track
69+
70+
## To retry a when the previous deployment creation failed:
71+
$ ecctl deployment create
72+
The deployment creation returned with an error, please use the displayed idempotency token
73+
to recreate the deployment resources
74+
Idempotency token: GMZPMRrcMYqHdmxjIQkHbdjnhPIeBElcwrHwzVlhGUSMXrEIzVXoBykSVRsKncNb
75+
unknown error (status 500)
76+
$ ecctl deployment create --request-id=GMZPMRrcMYqHdmxjIQkHbdjnhPIeBElcwrHwzVlhGUSMXrEIzVXoBykSVRsKncNb`
77+
)

docs/ecctl_deployment.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ ecctl deployment [flags]
4242
* [ecctl](ecctl.md) - Elastic Cloud Control
4343
* [ecctl deployment apm](ecctl_deployment_apm.md) - Manages APM deployments
4444
* [ecctl deployment appsearch](ecctl_deployment_appsearch.md) - Manages AppSearch deployments
45-
* [ecctl deployment create](ecctl_deployment_create.md) - Creates a deployment from a file definition, allowing certain flag overrides
45+
* [ecctl deployment create](ecctl_deployment_create.md) - Creates a deployment
4646
* [ecctl deployment delete](ecctl_deployment_delete.md) - Deletes a previously stopped deployment from the platform
4747
* [ecctl deployment elasticsearch](ecctl_deployment_elasticsearch.md) - Manages Elasticsearch clusters
4848
* [ecctl deployment kibana](ecctl_deployment_kibana.md) - Manages Kibana instances

0 commit comments

Comments
 (0)