morpheus-cli 5.2.2 → 5.3.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 91687d55f353976028bdebb05b8b588fc56ae1d590694da9948115098b05fb5f
4
- data.tar.gz: 370d606fe6b918dcc18a94f191fc9706bba0aef4832a3ec1aa24da8fc8d3377a
3
+ metadata.gz: f860d6a411e83d66114f0c40e20aec9980aa97315af9872f5776686f4def717e
4
+ data.tar.gz: fa2b969306e2345724805ddf065343d46629ec9ab546ee6c502377a7529bc462
5
5
  SHA512:
6
- metadata.gz: dba600f78525d9176052b7a6319db0c2131c4e1cbf140eea951613ff5920b3b7be3b2cf597a9dfa77c512336a936122c1b2cfc2c0d4436ee857c016ecf6da200
7
- data.tar.gz: 7cc0c47c12664abe7f012dd6520762fcbb8be6a9cc95a75d81688e7f3340bdcf8fbdd73c7347d3fc741bcc67853eaf42fe490ed097ba69558f76a1482d702fb9
6
+ metadata.gz: 4a84820acae372fc570a52750eaa03bb978812a7a40b6303ee85b0537f8fc1105eba5bc944da1f8f0876cae19b2d16c8abfd00fa7685949ef70a051f64c19a4a
7
+ data.tar.gz: de7be6c0d53e63c60e0941265deedca0f86574ed0060f7873fb38c54411daa6c142ba68818710d44fbf34240e0c2c81c0214f0d2d4a18b9346f452762967c7e6
data/Dockerfile CHANGED
@@ -1,5 +1,5 @@
1
1
  FROM ruby:2.5.1
2
2
 
3
- RUN gem install morpheus-cli -v 5.2.2
3
+ RUN gem install morpheus-cli -v 5.3.0.1
4
4
 
5
5
  ENTRYPOINT ["morpheus"]
data/README.md CHANGED
@@ -1,12 +1,12 @@
1
+ <img src="https://morpheusdata.com/wp-content/uploads/2020/04/morpheus-logo-v2.svg" width="200px">
2
+
1
3
  # Morpheus CLI
2
4
 
3
5
  - Website: https://www.morpheusdata.com/
4
6
  - Guide: [Morpheus CLI Wiki](https://github.com/gomorpheus/morpheus-cli/wiki)
5
- - Docs: [Morpheus Documentation](https://docs.morpheusdata.com)
7
+ - Docs: [Morpheus CLI Documentation](https://clidocs.morpheusdata.com)
6
8
  - Support: [Morpheus Support](https://support.morpheusdata.com)
7
9
 
8
- <img src="https://www.morpheusdata.com/wp-content/uploads/2018/06/cropped-morpheus_highres.png" width="600px">
9
-
10
10
  This library is a Ruby gem that provides a command line interface for interacting with the Morpheus Data appliance. The features provided include provisioning clusters, hosts, and containers, deploying and monitoring applications, automating tasks, and much more.
11
11
 
12
12
  ## Installation
@@ -190,6 +190,27 @@ class Morpheus::InstancesInterface < Morpheus::APIClient
190
190
  execute(opts)
191
191
  end
192
192
 
193
+ def clone_image(id, payload)
194
+ url = "#{@base_url}/api/instances/#{id}/clone-image"
195
+ headers = {:authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
196
+ opts = {method: :put, url: url, headers: headers, payload: payload.to_json}
197
+ execute(opts)
198
+ end
199
+
200
+ def lock(id, payload)
201
+ url = "#{@base_url}/api/instances/#{id}/lock"
202
+ headers = {:authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
203
+ opts = {method: :put, url: url, headers: headers, payload: payload.to_json}
204
+ execute(opts)
205
+ end
206
+
207
+ def unlock(id, payload)
208
+ url = "#{@base_url}/api/instances/#{id}/unlock"
209
+ headers = {:authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
210
+ opts = {method: :put, url: url, headers: headers, payload: payload.to_json}
211
+ execute(opts)
212
+ end
213
+
193
214
  def firewall_disable(id)
194
215
  url = "#{@base_url}/api/instances/#{id}/security-groups/disable"
195
216
  headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
@@ -22,6 +22,9 @@ class Morpheus::Cli::ActivityCommand
22
22
  params, options = {}, {}
23
23
  optparse = Morpheus::Cli::OptionParser.new do |opts|
24
24
  opts.banner = subcommand_usage()
25
+ opts.on('-a', '--details', "Display more details object id, full date and time, etc." ) do
26
+ options[:details] = true
27
+ end
25
28
  opts.on('-t','--type TYPE', "Activity Type eg. Provisioning, Admin") do |val|
26
29
  options[:type] ||= []
27
30
  options[:type] << val
@@ -115,20 +118,20 @@ EOT
115
118
  # {"SEVERITY" => lambda {|record| format_activity_severity(record['severity']) } },
116
119
  {"TYPE" => lambda {|record| record['activityType'] } },
117
120
  {"NAME" => lambda {|record| record['name'] } },
118
- {"RESOURCE" => lambda {|record| "#{record['objectType']} #{record['objectId']}" } },
121
+ options[:details] ? {"RESOURCE" => lambda {|record| "#{record['objectType']} #{record['objectId']}" } } : nil,
119
122
  {"MESSAGE" => lambda {|record| record['message'] || '' } },
120
123
  {"USER" => lambda {|record| record['user'] ? record['user']['username'] : record['userName'] } },
121
124
  #{"DATE" => lambda {|record| "#{format_duration_ago(record['ts'] || record['timestamp'])}" } },
122
125
  {"DATE" => lambda {|record|
123
- # show full time if searching for custom timerange, otherwise the default is to show relative time
124
- if params['start'] || params['end'] || params['timeframe']
126
+ # show full time if searching for custom timerange or --details, otherwise the default is to show relative time
127
+ if params['start'] || params['end'] || params['timeframe'] || options[:details]
125
128
  "#{format_local_dt(record['ts'] || record['timestamp'])}"
126
129
  else
127
130
  "#{format_duration_ago(record['ts'] || record['timestamp'])}"
128
131
  end
129
132
 
130
133
  } },
131
- ]
134
+ ].compact
132
135
  print as_pretty_table(activity, columns, options)
133
136
  print_results_pagination(json_response)
134
137
  end
@@ -10,7 +10,7 @@ class Morpheus::Cli::BackupJobsCommand
10
10
 
11
11
  set_command_name :'backup-jobs'
12
12
 
13
- register_subcommands :list, :get, :add, :update, :remove, :run
13
+ register_subcommands :list, :get #, :add, :update, :remove, :run
14
14
 
15
15
  def connect(opts)
16
16
  @api_client = establish_remote_appliance_connection(opts)
@@ -10,7 +10,7 @@ class Morpheus::Cli::BackupsCommand
10
10
 
11
11
  set_command_name :'backups'
12
12
 
13
- register_subcommands :list, :get, :add, :update, :remove, :run, :restore
13
+ register_subcommands :list, :get #, :add, :update, :remove, :run, :restore
14
14
 
15
15
  def connect(opts)
16
16
  @api_client = establish_remote_appliance_connection(opts)
@@ -82,8 +82,7 @@ EOT
82
82
  end
83
83
  end
84
84
 
85
- def _get(id, options)
86
- params = {}
85
+ def _get(id, params, options)
87
86
  @backups_interface.setopts(options)
88
87
  if options[:dry_run]
89
88
  print_dry_run @backups_interface.dry.get(id, params)
@@ -466,11 +466,16 @@ module Morpheus
466
466
 
467
467
  when :list
468
468
  opts.on( '-m', '--max MAX', "Max Results" ) do |val|
469
- max = val.to_i
470
- if max <= 0
471
- raise ::OptionParser::InvalidArgument.new("must be a positive integer")
469
+ # api supports max=-1 for all at the moment..
470
+ if val.to_s == "all" || val.to_s == "-1"
471
+ options[:max] = "-1"
472
+ else
473
+ max = val.to_i
474
+ if max <= 0
475
+ raise ::OptionParser::InvalidArgument.new("must be a positive integer")
476
+ end
477
+ options[:max] = max
472
478
  end
473
- options[:max] = max
474
479
  end
475
480
 
476
481
  opts.on( '-o', '--offset OFFSET', "Offset Results" ) do |val|
@@ -486,12 +491,17 @@ module Morpheus
486
491
  end
487
492
 
488
493
  opts.on( '-S', '--sort ORDER', "Sort Order. DIRECTION may be included as \"ORDER [asc|desc]\"." ) do |v|
489
- v_parts = v.to_s.split(" ")
490
- if v_parts.size > 1
491
- options[:sort] = v_parts[0]
492
- options[:direction] = (v_parts[1].strip == "desc") ? "desc" : "asc"
493
- else
494
+ if v.to_s.include?(",")
495
+ # sorting on multiple properties, just pass it as is, newer api supports multiple fields
494
496
  options[:sort] = v
497
+ else
498
+ v_parts = v.to_s.split(" ")
499
+ if v_parts.size > 1
500
+ options[:sort] = v_parts[0]
501
+ options[:direction] = (v_parts[1].strip == "desc") ? "desc" : "asc"
502
+ else
503
+ options[:sort] = v
504
+ end
495
505
  end
496
506
  end
497
507
 
@@ -934,6 +934,9 @@ class Morpheus::Cli::Clusters
934
934
  end
935
935
  else
936
936
  payload = {"permissions" => prompt_permissions(options.merge({:available_plans => namespace_service_plans}))}
937
+ # if payload["permissions"] && payload["permissions"]["resourcePool"]
938
+ # payload["permissions"].delete("resourcePool")
939
+ # end
937
940
  end
938
941
 
939
942
  @clusters_interface.setopts(options)
@@ -3897,8 +3900,8 @@ class Morpheus::Cli::Clusters
3897
3900
  perms = prompt_permissions(options.merge({:available_plans => namespace_service_plans}))
3898
3901
  if perms['resourcePool'] && !perms['resourcePool']['visibility'].nil?
3899
3902
  rtn['visibility'] = perms['resourcePool']['visibility']
3900
- perms.delete('resourcePool')
3901
3903
  end
3904
+ perms.delete('resourcePool')
3902
3905
  rtn['permissions'] = perms
3903
3906
  rtn
3904
3907
  end
@@ -14,14 +14,14 @@ class Morpheus::Cli::HistoryCommand
14
14
  # AND start logging every terminal command, not just shell...
15
15
  def handle(args)
16
16
  options = {show_pagination:false}
17
- optparse = Morpheus::Cli::OptionParser.new do|opts|
18
- opts.banner = "Usage: morpheus #{command_name} [search]"
17
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
18
+ opts.banner = "Usage: #{prog_name} #{command_name} [search]"
19
19
  # -n is a hidden alias for -m
20
20
  opts.on( '-n', '--max-commands MAX', "Alias for -m, --max option." ) do |val|
21
21
  options[:max] = val
22
22
  end
23
23
  opts.add_hidden_option('-n')
24
- opts.on( '-p', '--pagination', "Display pagination and count info eg. Viewing 1-M of N" ) do
24
+ opts.on( '-p', '--pagination', "Display pagination and count info eg. Viewing 1-25 of 42" ) do
25
25
  options[:show_pagination] = true
26
26
  end
27
27
  opts.on( nil, '--flush', "Flush history, purges entire shell history file." ) do
@@ -38,10 +38,9 @@ Examples:
38
38
  history "instances list"
39
39
  history --flush
40
40
 
41
- The most recently executed commands are seen by default. Use --reverse to see the oldest commands.
41
+ The most recently executed commands are seen by default. Use --desc to see the oldest commands.
42
42
  EOT
43
43
  end
44
- raw_cmd = "#{command_name} #{args.join(' ')}"
45
44
  optparse.parse!(args)
46
45
  # verify_args!(args:args, count: 0, optparse:optparse)
47
46
  if args.count > 0
@@ -272,20 +272,20 @@ This includes instance and backup counts, favorite instances, monitoring and rec
272
272
  # {"SEVERITY" => lambda {|record| format_activity_severity(record['severity']) } },
273
273
  {"TYPE" => lambda {|record| record['activityType'] } },
274
274
  {"NAME" => lambda {|record| record['name'] } },
275
- {"RESOURCE" => lambda {|record| "#{record['objectType']} #{record['objectId']}" } },
275
+ options[:details] ? {"RESOURCE" => lambda {|record| "#{record['objectType']} #{record['objectId']}" } } : nil,
276
276
  {"MESSAGE" => lambda {|record| record['message'] || '' } },
277
277
  {"USER" => lambda {|record| record['user'] ? record['user']['username'] : record['userName'] } },
278
278
  #{"DATE" => lambda {|record| "#{format_duration_ago(record['ts'] || record['timestamp'])}" } },
279
279
  {"DATE" => lambda {|record|
280
280
  # show full time if searching for custom timerange, otherwise the default is to show relative time
281
- if params['start'] || params['end'] || params['timeframe']
281
+ if params['start'] || params['end'] || params['timeframe'] || options[:details]
282
282
  "#{format_local_dt(record['ts'] || record['timestamp'])}"
283
283
  else
284
284
  "#{format_duration_ago(record['ts'] || record['timestamp'])}"
285
285
  end
286
286
 
287
287
  } },
288
- ]
288
+ ].compact
289
289
  print as_pretty_table(activity, columns, options)
290
290
  # print_results_pagination(json_response)
291
291
  # print reset,"\n"
@@ -31,6 +31,10 @@ class Morpheus::Cli::ExecutionRequestCommand
31
31
  handle_subcommand(args)
32
32
  end
33
33
 
34
+ def default_refresh_interval
35
+ 5
36
+ end
37
+
34
38
  def get(args)
35
39
  raw_args = args
36
40
  options = {}
@@ -134,7 +138,7 @@ class Morpheus::Cli::ExecutionRequestCommand
134
138
  options = {}
135
139
  params = {}
136
140
  script_content = nil
137
- do_refresh = true
141
+ options[:refresh_until_finished] = true
138
142
  optparse = Morpheus::Cli::OptionParser.new do|opts|
139
143
  opts.banner = subcommand_usage("[options]")
140
144
  opts.on('--server ID', String, "Server ID") do |val|
@@ -161,8 +165,14 @@ class Morpheus::Cli::ExecutionRequestCommand
161
165
  exit 1
162
166
  end
163
167
  end
164
- opts.on(nil, '--no-refresh', "Do not refresh until finished" ) do
165
- do_refresh = false
168
+ opts.on('--refresh [SECONDS]', String, "Refresh until execution is finished. Default interval is #{default_refresh_interval} seconds.") do |val|
169
+ options[:refresh_until_finished] = true
170
+ if !val.to_s.empty?
171
+ options[:refresh_interval] = val.to_f
172
+ end
173
+ end
174
+ opts.on(nil, '--no-refresh', "Do not refresh. The default behavior is to refresh until finished." ) do
175
+ options[:refresh_until_finished] = false
166
176
  end
167
177
  #build_option_type_options(opts, options, add_user_source_option_types())
168
178
  build_common_options(opts, options, [:options, :payload, :json, :dry_run, :quiet, :remote])
@@ -212,8 +222,8 @@ class Morpheus::Cli::ExecutionRequestCommand
212
222
  end
213
223
  execution_request = json_response['executionRequest']
214
224
  print_green_success "Executing request #{execution_request['uniqueId']}"
215
- if do_refresh
216
- get([execution_request['uniqueId'], "--refresh"] + (options[:remote] ? ["-r",options[:remote]] : []))
225
+ if options[:refresh_until_finished]
226
+ get([execution_request['uniqueId'], "--refresh", options[:refresh_interval] ? options[:refresh_interval].to_s : nil].compact + (options[:remote] ? ["-r",options[:remote]] : []))
217
227
  else
218
228
  get([execution_request['uniqueId']] + (options[:remote] ? ["-r",options[:remote]] : []))
219
229
  end
@@ -117,6 +117,12 @@ class Morpheus::Cli::Hosts
117
117
  opts.on( '--tenant TENANT', "Tenant Name or ID" ) do |val|
118
118
  options[:account] = val
119
119
  end
120
+ opts.on('--labels label',String, "Filter by labels (keywords).") do |val|
121
+ val.split(",").each do |k|
122
+ options[:labels] ||= []
123
+ options[:labels] << k.strip
124
+ end
125
+ end
120
126
  opts.on('--tags Name=Value',String, "Filter by tags.") do |val|
121
127
  val.split(",").each do |value_pair|
122
128
  k,v = value_pair.strip.split("=")
@@ -186,6 +192,7 @@ class Morpheus::Cli::Hosts
186
192
  params['clusterId'] = cluster['id']
187
193
  end
188
194
  end
195
+ params['labels'] = options[:labels] if options[:labels]
189
196
  if options[:tags] && !options[:tags].empty?
190
197
  options[:tags].each do |k,v|
191
198
  params['tags.' + k] = v
@@ -542,6 +549,7 @@ class Morpheus::Cli::Hosts
542
549
  "Name" => 'name',
543
550
  "Hostname" => 'hostname',
544
551
  "Description" => 'description',
552
+ "Labels" => lambda {|it| it['labels'] ? it['labels'].join(',') : '' },
545
553
  "Tags" => lambda {|it| tags ? format_metadata(tags) : '' },
546
554
  "Owner" => lambda {|it| it['owner'] ? it['owner']['username'] : '' },
547
555
  "Tenant" => lambda {|it| it['account'] ? it['account']['name'] : '' },
@@ -566,6 +574,7 @@ class Morpheus::Cli::Hosts
566
574
  # server_columns.delete("Tenant") if multi_tenant != true
567
575
  server_columns.delete("Cost") if server['hourlyCost'].to_f == 0
568
576
  server_columns.delete("Price") if server['hourlyPrice'].to_f == 0 || server['hourlyPrice'] == server['hourlyCost']
577
+ server_columns.delete("Labels") if server['labels'].nil? || server['labels'].empty?
569
578
  server_columns.delete("Tags") if tags.nil? || tags.empty?
570
579
 
571
580
  print_description_list(server_columns, server)
@@ -993,6 +1002,9 @@ class Morpheus::Cli::Hosts
993
1002
  opts.on('--power-schedule-type ID', String, "Power Schedule Type ID") do |val|
994
1003
  params['powerScheduleType'] = val == "null" ? nil : val
995
1004
  end
1005
+ opts.on('--labels [LIST]', String, "Labels (keywords) in the format 'foo, bar'") do |val|
1006
+ params['labels'] = val.to_s.split(',').collect {|it| it.to_s.strip }.compact.uniq.join(',')
1007
+ end
996
1008
  opts.on('--tags LIST', String, "Tags in the format 'name:value, name:value'. This will add and remove tags.") do |val|
997
1009
  options[:tags] = val
998
1010
  end
@@ -19,6 +19,7 @@ class Morpheus::Cli::Instances
19
19
  :history, {:'history-details' => :history_details}, {:'history-event' => :history_event_details},
20
20
  :stats, :stop, :start, :restart, :actions, :action, :suspend, :eject, :stop_service, :start_service, :restart_service,
21
21
  :backup, :backups, :resize, :clone, :envs, :setenv, :delenv,
22
+ :lock, :unlock, :clone_image,
22
23
  :security_groups, :apply_security_groups, :run_workflow, :import_snapshot, :snapshot, :snapshots,
23
24
  :console, :status_check, {:containers => :list_containers},
24
25
  :scaling, {:'scaling-update' => :scaling_update},
@@ -603,8 +604,8 @@ class Morpheus::Cli::Instances
603
604
  opts.on('--group GROUP', String, "Group Name or ID") do |val|
604
605
  options[:group] = val
605
606
  end
606
- opts.on('--labels LIST', String, "Labels (keywords) in the format 'foo, bar'") do |val|
607
- params['labels'] = val.split(',').collect {|it| it.to_s.strip }.compact.uniq.join(',')
607
+ opts.on('--labels [LIST]', String, "Labels (keywords) in the format 'foo, bar'") do |val|
608
+ params['labels'] = val.to_s.split(',').collect {|it| it.to_s.strip }.compact.uniq.join(',')
608
609
  end
609
610
  opts.on('--tags LIST', String, "Tags in the format 'name:value, name:value'. This will add and remove tags.") do |val|
610
611
  options[:tags] = val
@@ -1350,6 +1351,7 @@ class Morpheus::Cli::Instances
1350
1351
  "Shutdown Date" => lambda {|it| it['shutdownDate'] ? format_local_dt(it['shutdownDate']) : '' },
1351
1352
  "Nodes" => lambda {|it| it['containers'] ? it['containers'].count : 0 },
1352
1353
  "Connection" => lambda {|it| format_instance_connection_string(it) },
1354
+ "Locked" => lambda {|it| format_boolean(it['locked']) },
1353
1355
  "Status" => lambda {|it| format_instance_status(it) }
1354
1356
  }
1355
1357
  description_cols.delete("Labels") if labels.nil? || labels.empty?
@@ -1359,6 +1361,7 @@ class Morpheus::Cli::Instances
1359
1361
  description_cols.delete("Shutdown Date") if instance['shutdownDate'].nil?
1360
1362
  description_cols["Removal Date"] = lambda {|it| format_local_dt(it['removalDate'])} if instance['status'] == 'pendingRemoval'
1361
1363
  description_cols.delete("Last Deployment") if instance['lastDeploy'].nil?
1364
+ description_cols.delete("Locked") if instance['locked'] != true
1362
1365
  #description_cols.delete("Environment") if instance['instanceContext'].nil?
1363
1366
  print_description_list(description_cols, instance)
1364
1367
 
@@ -3888,6 +3891,117 @@ EOT
3888
3891
  return 0
3889
3892
  end
3890
3893
 
3894
+ def clone_image(args)
3895
+ options = {}
3896
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
3897
+ opts.banner = subcommand_usage("[instance]")
3898
+ opts.on( '--name VALUE', String, "Image Name (Template Name). Default is server name + timestamp" ) do |val|
3899
+ options[:options]['templateName'] = val
3900
+ end
3901
+ build_standard_update_options(opts, options)
3902
+ opts.footer = <<-EOT
3903
+ Clone to image (template) for an instance
3904
+ [instance] is required. This is the name or id of an instance
3905
+ EOT
3906
+ end
3907
+ optparse.parse!(args)
3908
+ verify_args!(args:args, optparse:optparse, count:1)
3909
+ connect(options)
3910
+ instance = find_instance_by_name_or_id(args[0])
3911
+ return 1 if instance.nil?
3912
+ payload = {}
3913
+ if options[:payload]
3914
+ payload = options[:payload]
3915
+ payload.deep_merge!(parse_passed_options(options))
3916
+ else
3917
+ payload.deep_merge!(parse_passed_options(options))
3918
+ if payload['templateName'].nil?
3919
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'templateName', 'type' => 'text', 'fieldLabel' => 'Image Name', 'description' => 'Choose a name for the new image template. Default is the server name + timestamp'}], options[:options])
3920
+ if v_prompt['templateName'].to_s != ''
3921
+ payload['templateName'] = v_prompt['templateName']
3922
+ end
3923
+ end
3924
+ end
3925
+ @instances_interface.setopts(options)
3926
+ if options[:dry_run]
3927
+ print_dry_run @instances_interface.dry.clone_image(instance['id'], payload)
3928
+ return
3929
+ end
3930
+ json_response = @instances_interface.clone_image(instance['id'], payload)
3931
+ render_response(json_response, options) do
3932
+ print_green_success "Clone Image initiated."
3933
+ end
3934
+ return 0, nil
3935
+ end
3936
+
3937
+ def lock(args)
3938
+ options = {}
3939
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
3940
+ opts.banner = subcommand_usage("[instance]")
3941
+ build_standard_update_options(opts, options)
3942
+ opts.footer = <<-EOT
3943
+ Lock an instance
3944
+ [instance] is required. This is the name or id of an instance
3945
+ EOT
3946
+ end
3947
+ optparse.parse!(args)
3948
+ verify_args!(args:args, optparse:optparse, count:1)
3949
+ connect(options)
3950
+ instance = find_instance_by_name_or_id(args[0])
3951
+ return 1 if instance.nil?
3952
+ payload = {}
3953
+ if options[:payload]
3954
+ payload = options[:payload]
3955
+ payload.deep_merge!(parse_passed_options(options))
3956
+ else
3957
+ payload.deep_merge!(parse_passed_options(options))
3958
+ end
3959
+ @instances_interface.setopts(options)
3960
+ if options[:dry_run]
3961
+ print_dry_run @instances_interface.dry.lock(instance['id'], payload)
3962
+ return
3963
+ end
3964
+ json_response = @instances_interface.lock(instance['id'], payload)
3965
+ render_response(json_response, options) do
3966
+ print_green_success "Locked instance #{instance['name']}"
3967
+ end
3968
+ return 0, nil
3969
+ end
3970
+
3971
+ def unlock(args)
3972
+ options = {}
3973
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
3974
+ opts.banner = subcommand_usage("[instance]")
3975
+ build_standard_update_options(opts, options)
3976
+ opts.footer = <<-EOT
3977
+ Unlock an instance
3978
+ [instance] is required. This is the name or id of an instance
3979
+ EOT
3980
+ end
3981
+ optparse.parse!(args)
3982
+ verify_args!(args:args, optparse:optparse, count:1)
3983
+ connect(options)
3984
+ instance = find_instance_by_name_or_id(args[0])
3985
+ return 1 if instance.nil?
3986
+ payload = {}
3987
+ if options[:payload]
3988
+ payload = options[:payload]
3989
+ payload.deep_merge!(parse_passed_options(options))
3990
+ else
3991
+ payload.deep_merge!(parse_passed_options(options))
3992
+ end
3993
+ @instances_interface.setopts(options)
3994
+ if options[:dry_run]
3995
+ print_dry_run @instances_interface.dry.unlock(instance['id'], payload)
3996
+ return
3997
+ end
3998
+ json_response = @instances_interface.unlock(instance['id'], payload)
3999
+ render_response(json_response, options) do
4000
+ print_green_success "Unlocked instance #{instance['name']}"
4001
+ end
4002
+ return 0, nil
4003
+ end
4004
+
3891
4005
  private
3892
4006
 
3893
4007
  def find_zone_by_name_or_id(group_id, val)