morpheus-cli 2.10.0 → 2.10.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/bin/morpheus +27 -32
  3. data/lib/morpheus/api/accounts_interface.rb +36 -47
  4. data/lib/morpheus/api/api_client.rb +141 -110
  5. data/lib/morpheus/api/app_templates_interface.rb +56 -72
  6. data/lib/morpheus/api/apps_interface.rb +111 -132
  7. data/lib/morpheus/api/auth_interface.rb +30 -0
  8. data/lib/morpheus/api/clouds_interface.rb +71 -76
  9. data/lib/morpheus/api/custom_instance_types_interface.rb +21 -46
  10. data/lib/morpheus/api/dashboard_interface.rb +10 -17
  11. data/lib/morpheus/api/deploy_interface.rb +60 -72
  12. data/lib/morpheus/api/deployments_interface.rb +53 -71
  13. data/lib/morpheus/api/groups_interface.rb +55 -45
  14. data/lib/morpheus/api/instance_types_interface.rb +19 -23
  15. data/lib/morpheus/api/instances_interface.rb +179 -177
  16. data/lib/morpheus/api/key_pairs_interface.rb +11 -17
  17. data/lib/morpheus/api/license_interface.rb +18 -23
  18. data/lib/morpheus/api/load_balancers_interface.rb +54 -69
  19. data/lib/morpheus/api/logs_interface.rb +25 -29
  20. data/lib/morpheus/api/options_interface.rb +13 -17
  21. data/lib/morpheus/api/provision_types_interface.rb +19 -22
  22. data/lib/morpheus/api/roles_interface.rb +75 -94
  23. data/lib/morpheus/api/security_group_rules_interface.rb +28 -37
  24. data/lib/morpheus/api/security_groups_interface.rb +39 -51
  25. data/lib/morpheus/api/servers_interface.rb +113 -115
  26. data/lib/morpheus/api/setup_interface.rb +31 -0
  27. data/lib/morpheus/api/task_sets_interface.rb +36 -38
  28. data/lib/morpheus/api/tasks_interface.rb +56 -69
  29. data/lib/morpheus/api/users_interface.rb +67 -76
  30. data/lib/morpheus/api/virtual_images_interface.rb +61 -61
  31. data/lib/morpheus/api/whoami_interface.rb +12 -15
  32. data/lib/morpheus/cli.rb +71 -60
  33. data/lib/morpheus/cli/accounts.rb +254 -315
  34. data/lib/morpheus/cli/alias_command.rb +219 -0
  35. data/lib/morpheus/cli/app_templates.rb +264 -272
  36. data/lib/morpheus/cli/apps.rb +608 -671
  37. data/lib/morpheus/cli/cli_command.rb +259 -21
  38. data/lib/morpheus/cli/cli_registry.rb +99 -14
  39. data/lib/morpheus/cli/clouds.rb +599 -372
  40. data/lib/morpheus/cli/config_file.rb +126 -0
  41. data/lib/morpheus/cli/credentials.rb +141 -117
  42. data/lib/morpheus/cli/dashboard_command.rb +48 -56
  43. data/lib/morpheus/cli/deployments.rb +254 -268
  44. data/lib/morpheus/cli/deploys.rb +150 -142
  45. data/lib/morpheus/cli/error_handler.rb +38 -0
  46. data/lib/morpheus/cli/groups.rb +551 -179
  47. data/lib/morpheus/cli/hosts.rb +862 -617
  48. data/lib/morpheus/cli/instance_types.rb +103 -95
  49. data/lib/morpheus/cli/instances.rb +1335 -1009
  50. data/lib/morpheus/cli/key_pairs.rb +82 -90
  51. data/lib/morpheus/cli/library.rb +498 -499
  52. data/lib/morpheus/cli/license.rb +83 -101
  53. data/lib/morpheus/cli/load_balancers.rb +314 -300
  54. data/lib/morpheus/cli/login.rb +66 -44
  55. data/lib/morpheus/cli/logout.rb +47 -46
  56. data/lib/morpheus/cli/mixins/accounts_helper.rb +69 -31
  57. data/lib/morpheus/cli/mixins/infrastructure_helper.rb +106 -0
  58. data/lib/morpheus/cli/mixins/print_helper.rb +181 -17
  59. data/lib/morpheus/cli/mixins/provisioning_helper.rb +535 -458
  60. data/lib/morpheus/cli/mixins/whoami_helper.rb +2 -2
  61. data/lib/morpheus/cli/option_parser.rb +35 -0
  62. data/lib/morpheus/cli/option_types.rb +232 -192
  63. data/lib/morpheus/cli/recent_activity_command.rb +61 -65
  64. data/lib/morpheus/cli/remote.rb +446 -199
  65. data/lib/morpheus/cli/roles.rb +884 -906
  66. data/lib/morpheus/cli/security_group_rules.rb +213 -203
  67. data/lib/morpheus/cli/security_groups.rb +237 -192
  68. data/lib/morpheus/cli/shell.rb +338 -231
  69. data/lib/morpheus/cli/tasks.rb +326 -308
  70. data/lib/morpheus/cli/users.rb +457 -462
  71. data/lib/morpheus/cli/version.rb +1 -1
  72. data/lib/morpheus/cli/version_command.rb +16 -18
  73. data/lib/morpheus/cli/virtual_images.rb +526 -345
  74. data/lib/morpheus/cli/whoami.rb +125 -111
  75. data/lib/morpheus/cli/workflows.rb +338 -185
  76. data/lib/morpheus/formatters.rb +8 -1
  77. data/lib/morpheus/logging.rb +1 -1
  78. data/lib/morpheus/rest_client.rb +17 -8
  79. metadata +9 -3
  80. data/lib/morpheus/api/custom_instance_types.rb +0 -55
@@ -1,116 +1,124 @@
1
1
  require 'io/console'
2
2
  require 'optparse'
3
- require 'filesize'
4
3
  require 'morpheus/cli/cli_command'
5
4
 
6
5
  class Morpheus::Cli::InstanceTypes
7
6
  include Morpheus::Cli::CliCommand
8
7
 
9
- def initialize()
10
- @appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
11
- @access_token = Morpheus::Cli::Credentials.new(@appliance_name,@appliance_url).request_credentials()
12
- @instance_types_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).instance_types
13
- end
8
+ register_subcommands :list, :get
9
+ alias_subcommand :details, :get
10
+ set_default_subcommand :list
14
11
 
12
+ def initialize()
13
+ # @appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
14
+ end
15
15
 
16
- def handle(args)
17
- if @access_token.empty?
18
- print_red_alert "Invalid Credentials. Unable to acquire access token. Please verify your credentials and try again."
19
- return 1
20
- end
21
- if args.empty?
22
- puts "\nUsage: morpheus instance-types [list,details] [name]\n\n"
23
- return
24
- end
16
+ def connect(opts)
17
+ @api_client = establish_remote_appliance_connection(opts)
18
+ @instance_types_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).instance_types
19
+ end
25
20
 
26
- case args[0]
27
- when 'list'
28
- list(args[1..-1])
29
- when 'details'
30
- details(args[1..-1])
31
- else
32
- puts "\nUsage: morpheus instance-types [list,details] [name]\n\n"
33
- end
34
- end
21
+ def handle(args)
22
+ handle_subcommand(args)
23
+ end
35
24
 
25
+ def get(args)
26
+ options = {}
27
+ optparse = OptionParser.new do|opts|
28
+ opts.banner = subcommand_usage("[name]")
29
+ build_common_options(opts, options, [:json, :dry_run])
30
+ end
31
+ optparse.parse!(args)
32
+ if args.count < 1
33
+ puts optparse
34
+ exit
35
+ end
36
+ name = args[0]
37
+ connect(options)
38
+ begin
39
+ if options[:dry_run]
40
+ print_dry_run @instance_types_interface.dry.get({name: name})
41
+ return
42
+ end
43
+ json_response = @instance_types_interface.get({name: name})
36
44
 
37
- def details(args)
38
- options = {}
39
- optparse = OptionParser.new do|opts|
40
- opts.banner = "Usage: morpheus instance-type details [name]"
41
- build_common_options(opts, options, [:json])
42
- end
43
- optparse.parse(args)
44
- if args.count < 1
45
- puts "\n#{optparse.banner}\n\n"
46
- return
47
- end
48
- name = args[0]
49
- begin
50
- json_response = @instance_types_interface.get({name: name})
45
+ if options[:json]
46
+ print JSON.pretty_generate(json_response), "\n"
47
+ return
48
+ end
51
49
 
52
- if options[:json]
53
- print JSON.pretty_generate(json_response), "\n"
54
- return
55
- end
50
+ instance_type = json_response['instanceTypes'][0]
56
51
 
57
- instance_type = json_response['instanceTypes'][0]
52
+ if instance_type.nil?
53
+ puts yellow,"No instance type found by name #{name}.",reset
54
+ else
55
+ print "\n" ,cyan, bold, "Instance Type Details\n","==================", reset, "\n\n"
56
+ versions = instance_type['versions'].join(', ')
57
+ print cyan, "= #{instance_type['name']} (#{instance_type['code']}) - #{versions}\n"
58
+ layout_names = instance_type['instanceTypeLayouts'].collect { |layout| layout['name'] }.uniq.sort
59
+ layout_names.each do |layout_name|
60
+ print green, " - #{layout_name}\n",reset
61
+ end
62
+ # instance_type['instanceTypeLayouts'].each do |layout|
63
+ # print green, " - #{layout['name']}\n",reset
64
+ # end
65
+ print reset,"\n"
66
+ end
58
67
 
59
- if instance_type.nil?
60
- puts yellow,"No instance type found by name #{name}.",reset
61
- else
62
- print "\n" ,cyan, bold, "Instance Type Details\n","==================", reset, "\n\n"
63
- versions = instance_type['versions'].join(', ')
64
- print cyan, "= #{instance_type['name']} (#{instance_type['code']}) - #{versions}\n"
65
- instance_type['instanceTypeLayouts'].each do |layout|
66
- print green, " - #{layout['name']}\n",reset
67
- end
68
- print reset,"\n\n"
69
- end
68
+ rescue RestClient::Exception => e
69
+ print_rest_exception(e, options)
70
+ exit 1
71
+ end
72
+ end
70
73
 
71
- rescue RestClient::Exception => e
72
- print_rest_exception(e, options)
73
- exit 1
74
- end
75
- end
74
+ def list(args)
75
+ options = {}
76
+ optparse = OptionParser.new do|opts|
77
+ opts.banner = subcommand_usage()
78
+ build_common_options(opts, options, [:list, :json, :dry_run])
79
+ end
80
+ optparse.parse!(args)
81
+ connect(options)
82
+ begin
83
+ params = {}
84
+ [:phrase, :offset, :max, :sort, :direction].each do |k|
85
+ params[k] = options[k] unless options[k].nil?
86
+ end
76
87
 
77
- def list(args)
78
- options = {}
79
- optparse = OptionParser.new do|opts|
80
- build_common_options(opts, options, [:list, :json])
81
- end
82
- optparse.parse(args)
83
- begin
84
- params = {}
85
- [:phrase, :offset, :max, :sort, :direction].each do |k|
86
- params[k] = options[k] unless options[k].nil?
87
- end
88
+ if options[:dry_run]
89
+ print_dry_run @instance_types_interface.dry.get(params)
90
+ return
91
+ end
92
+ json_response = @instance_types_interface.get(params)
88
93
 
89
- json_response = @instance_types_interface.get(params)
94
+ if options[:json]
95
+ print JSON.pretty_generate(json_response), "\n"
96
+ return
97
+ end
90
98
 
91
- if options[:json]
92
- print JSON.pretty_generate(json_response), "\n"
93
- return
94
- end
99
+ instance_types = json_response['instanceTypes']
100
+ print "\n" ,cyan, bold, "Morpheus Instance Types\n","==================", reset, "\n\n"
101
+ if instance_types.empty?
102
+ puts yellow,"No instance types currently configured.",reset
103
+ else
104
+ instance_types.each do |instance_type|
105
+ versions = instance_type['versions'].join(', ')
106
+ print cyan, "= #{instance_type['name']} (#{instance_type['code']}) - #{versions}\n"
107
+ layout_names = instance_type['instanceTypeLayouts'].collect { |layout| layout['name'] }.uniq.sort
108
+ layout_names.each do |layout_name|
109
+ print green, " - #{layout_name}\n",reset
110
+ end
111
+ # instance_type['instanceTypeLayouts'].each do |layout|
112
+ # print green, " - #{layout['name']}\n",reset
113
+ # end
114
+ #print JSON.pretty_generate(instance_type['instanceTypeLayouts'].first), "\n"
115
+ end
95
116
 
96
- instance_types = json_response['instanceTypes']
97
- print "\n" ,cyan, bold, "Morpheus Instance Types\n","==================", reset, "\n\n"
98
- if instance_types.empty?
99
- puts yellow,"No instance types currently configured.",reset
100
- else
101
- instance_types.each do |instance_type|
102
- versions = instance_type['versions'].join(', ')
103
- print cyan, "= #{instance_type['name']} (#{instance_type['code']}) - #{versions}\n"
104
- instance_type['instanceTypeLayouts'].each do |layout|
105
- print green, " - #{layout['name']}\n",reset
106
- end
107
- end
108
- end
109
- print reset,"\n\n"
110
-
111
- rescue RestClient::Exception => e
112
- print_rest_exception(e, options)
113
- exit 1
114
- end
115
- end
117
+ end
118
+ print reset,"\n"
119
+ rescue RestClient::Exception => e
120
+ print_rest_exception(e, options)
121
+ exit 1
122
+ end
123
+ end
116
124
  end
@@ -5,198 +5,127 @@ require 'filesize'
5
5
  require 'table_print'
6
6
  require 'morpheus/cli/cli_command'
7
7
  require 'morpheus/cli/mixins/provisioning_helper'
8
+ require 'morpheus/cli/option_types'
8
9
 
9
10
  class Morpheus::Cli::Instances
10
11
  include Morpheus::Cli::CliCommand
11
12
  include Morpheus::Cli::ProvisioningHelper
12
13
 
13
- def initialize()
14
- @appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
15
-
16
- end
17
-
18
- def connect(opts)
19
- if opts[:remote]
20
- @appliance_url = opts[:remote]
21
- @appliance_name = opts[:remote]
22
- @access_token = Morpheus::Cli::Credentials.new(@appliance_name,@appliance_url).request_credentials(opts)
23
- else
24
- @access_token = Morpheus::Cli::Credentials.new(@appliance_name,@appliance_url).request_credentials(opts)
25
- end
26
- @api_client = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url)
27
- @instances_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).instances
28
- @task_sets_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).task_sets
29
- @logs_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).logs
30
- @tasks_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).tasks
31
- @instance_types_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).instance_types
32
- @groups_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).groups
33
- @provision_types_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).provision_types
34
- @options_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).options
35
- @active_groups = ::Morpheus::Cli::Groups.load_group_file
36
- if @access_token.empty?
37
- print_red_alert "Invalid Credentials. Unable to acquire access token. Please verify your credentials and try again."
38
- exit 1
39
- end
40
- end
41
-
42
-
43
- def handle(args)
44
- usage = "Usage: morpheus instances [list,details,add,update,remove,stop,start,restart,backup,run-workflow,stop-service,start-service,restart-service,resize,upgrade,clone,envs,setenv,delenv] [name]"
45
- if args.empty?
46
- puts "\n#{usage}\n\n"
47
- return
48
- end
49
-
50
- case args[0]
51
- when 'list'
52
- list(args[1..-1])
53
- when 'details'
54
- details(args[1..-1])
55
- when 'add'
56
- add(args[1..-1])
57
- when 'update'
58
- update(args[1..-1])
59
- when 'remove'
60
- remove(args[1..-1])
61
- when 'stop'
62
- stop(args[1..-1])
63
- when 'start'
64
- start(args[1..-1])
65
- when 'restart'
66
- restart(args[1..-1])
67
- when 'stop-service'
68
- stop_service(args[1..-1])
69
- when 'start-service'
70
- start_service(args[1..-1])
71
- when 'restart-service'
72
- restart_service(args[1..-1])
73
- when 'resize'
74
- resize(args[1..-1])
75
- when 'run-workflow'
76
- run_workflow(args[1..-1])
77
- when 'stats'
78
- stats(args[1..-1])
79
- when 'logs'
80
- logs(args[1..-1])
81
- when 'envs'
82
- envs(args[1..-1])
83
- when 'setenv'
84
- setenv(args[1..-1])
85
- when 'delenv'
86
- delenv(args[1..-1])
87
- when 'firewall-disable'
88
- firewall_disable(args[1..-1])
89
- when 'firewall-enable'
90
- firewall_enable(args[1..-1])
91
- when 'security-groups'
92
- security_groups(args[1..-1])
93
- when 'apply-security-groups'
94
- apply_security_groups(args[1..-1])
95
- when 'backup'
96
- backup(args[1..-1])
97
- else
98
- puts "\n#{usage}\n\n"
99
- exit 127
100
- end
101
- end
102
-
103
- def add(args)
104
- options = {}
105
- optparse = OptionParser.new do|opts|
106
- opts.banner = "Usage: morpheus instances add [type] [name]"
107
- opts.on( '-g', '--group GROUP', "Group Name" ) do |val|
108
- options[:group_name] = val
109
- end
110
- opts.on( '-G', '--group-id ID', "Group Id" ) do |val|
111
- options[:group_id] = val
112
- end
113
- opts.on( '-c', '--cloud CLOUD', "Cloud Name" ) do |val|
114
- options[:cloud_name] = val
115
- end
116
- # this conflicts with --nocolor option
117
- # opts.on( '-C', '--cloud CLOUD', "Cloud Id" ) do |val|
118
- # options[:cloud] = val
119
- # end
120
- opts.on( '-t', '--type CODE', "Instance Type" ) do |val|
121
- options[:instance_type_code] = val
122
- end
123
- build_common_options(opts, options, [:options, :json, :dry_run, :remote])
124
-
125
- end
126
-
127
- optparse.parse(args)
128
- connect(options)
129
-
130
- # support old format of `instance add TYPE NAME`
131
- if args[0] && args[0] !~ /\A\-/
132
- options[:instance_type_code] = args[0]
133
- if args[1] && args[1] !~ /\A\-/
134
- options[:instance_name] = args[1]
135
- end
136
- end
137
-
138
- # use active group by default
139
- if !options[:group_name] && !options[:group_id]
140
- options[:group_id] = @active_groups[@appliance_name.to_sym]
141
- end
142
-
143
- options[:name_required] = true
144
-
145
- begin
146
-
147
- payload = prompt_new_instance(options)
148
-
149
- if options[:dry_run]
150
- print_dry_run("POST #{@appliance_url}/api/instances", payload)
151
- return
152
- end
153
- json_response = @instances_interface.create(payload)
154
- if options[:json]
155
- print JSON.pretty_generate(json_response)
156
- print "\n"
157
- else
158
- instance_name = json_response["instance"]["name"]
159
- print_green_success "Provisioning instance #{instance_name}"
160
- list([])
161
- end
162
- rescue RestClient::Exception => e
163
- print_rest_exception(e, options)
164
- exit 1
165
- end
166
- end
167
-
168
- def update(args)
169
- usage = "Usage: morpheus instances update [name] [options]"
14
+ register_subcommands :list, :get, :add, :update, :remove, :stats, :stop, :start, :restart, :suspend, :eject, :backup, :backups, :stop_service, :start_service, :restart_service, :resize, :upgrade, :clone, :envs, :setenv, :delenv, :security_groups, :apply_security_groups, :firewall_enable, :firewall_disable, :run_workflow, :import_snapshot, :console, :status_check
15
+ alias_subcommand :details, :get
16
+ set_default_subcommand :list
17
+
18
+ def initialize()
19
+ #@appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
20
+ end
21
+
22
+ def connect(opts)
23
+ @api_client = establish_remote_appliance_connection(opts)
24
+ @instances_interface = @api_client.instances
25
+ @task_sets_interface = @api_client.task_sets
26
+ @logs_interface = @api_client.logs
27
+ @tasks_interface = @api_client.tasks
28
+ @instance_types_interface = @api_client.instance_types
29
+ @clouds_interface = @api_client.clouds
30
+ @provision_types_interface = @api_client.provision_types
31
+ @options_interface = @api_client.options
32
+ @active_group_id = Morpheus::Cli::Groups.active_group
33
+ end
34
+
35
+ def handle(args)
36
+ handle_subcommand(args)
37
+ end
38
+
39
+ def add(args)
170
40
  options = {}
171
41
  optparse = OptionParser.new do|opts|
172
- opts.banner = usage
173
- build_common_options(opts, options, [:options, :json, :dry_run])
42
+ opts.banner = subcommand_usage("[type] [name]")
43
+ opts.on( '-g', '--group GROUP', "Group Name or ID" ) do |val|
44
+ options[:group] = val
45
+ end
46
+ opts.on( '-c', '--cloud CLOUD', "Cloud Name or ID" ) do |val|
47
+ options[:cloud] = val
48
+ end
49
+ opts.on( '-t', '--type CODE', "Instance Type" ) do |val|
50
+ options[:instance_type_code] = val
51
+ end
52
+ opts.on("--copies NUMBER", Integer, "Number of copies to provision") do |val|
53
+ options[:copies] = val.to_i
54
+ end
55
+ opts.on("--layout-size NUMBER", Integer, "Apply a multiply factor of containers/vms within the instance") do |val|
56
+ options[:layout_size] = val.to_i
57
+ end
58
+ build_common_options(opts, options, [:options, :json, :dry_run, :remote])
59
+ end
60
+
61
+ optparse.parse!(args)
62
+ connect(options)
63
+
64
+ # support old format of `instance add TYPE NAME`
65
+ if args[0]
66
+ options[:instance_type_code] = args[0]
67
+ end
68
+ if args[1]
69
+ options[:instance_name] = args[1]
70
+ end
71
+ # use active group by default
72
+ options[:group] ||= @active_group_id
73
+
74
+ options[:name_required] = true
75
+ begin
76
+
77
+ payload = prompt_new_instance(options)
78
+ payload[:copies] = options[:copies] if options[:copies] && options[:copies] > 0
79
+ payload[:layoutSize] = options[:layout_size] if options[:layout_size] && options[:layout_size] > 0
80
+ if options[:dry_run]
81
+ print_dry_run @instances_interface.dry.create(payload)
82
+ return
83
+ end
84
+ json_response = @instances_interface.create(payload)
85
+ if options[:json]
86
+ print JSON.pretty_generate(json_response)
87
+ print "\n"
88
+ else
89
+ instance_name = json_response["instance"]["name"]
90
+ print_green_success "Provisioning instance #{instance_name}"
91
+ list([])
92
+ end
93
+ rescue RestClient::Exception => e
94
+ print_rest_exception(e, options)
95
+ exit 1
96
+ end
97
+ end
98
+
99
+ def update(args)
100
+ usage = "Usage: morpheus instances update [name] [options]"
101
+ options = {}
102
+ optparse = OptionParser.new do|opts|
103
+ opts.banner = subcommand_usage("[name]")
104
+ build_common_options(opts, options, [:options, :json, :dry_run, :remote])
174
105
  end
175
- optparse.parse(args)
106
+ optparse.parse!(args)
176
107
  if args.count < 1
177
- puts "\n#{optparse.banner}\n\n"
178
- exit 1
179
- end
108
+ puts optparse
109
+ exit 1
110
+ end
180
111
  connect(options)
181
112
 
182
113
  begin
183
-
184
- instance = find_instance_by_name_or_id(args[0])
185
114
 
186
- # group = find_group_from_options(options)
115
+ instance = find_instance_by_name_or_id(args[0])
187
116
 
188
- payload = {
189
- 'instance' => {id: instance["id"]}
190
- }
117
+ payload = {
118
+ 'instance' => {id: instance["id"]}
119
+ }
191
120
 
192
- update_instance_option_types = [
193
- {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'description' => 'Enter a name for this instance'},
194
- {'fieldName' => 'description', 'fieldLabel' => 'Description', 'type' => 'text', 'required' => false},
195
- {'fieldName' => 'instanceContext', 'fieldLabel' => 'Environment', 'type' => 'select', 'required' => false, 'selectOptions' => instance_context_options()},
196
- {'fieldName' => 'tags', 'fieldLabel' => 'Tags', 'type' => 'text', 'required' => false}
197
- ]
121
+ update_instance_option_types = [
122
+ {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'description' => 'Enter a name for this instance'},
123
+ {'fieldName' => 'description', 'fieldLabel' => 'Description', 'type' => 'text', 'required' => false},
124
+ {'fieldName' => 'instanceContext', 'fieldLabel' => 'Environment', 'type' => 'select', 'required' => false, 'selectOptions' => instance_context_options()},
125
+ {'fieldName' => 'tags', 'fieldLabel' => 'Tags', 'type' => 'text', 'required' => false}
126
+ ]
198
127
 
199
- params = options[:options] || {}
128
+ params = options[:options] || {}
200
129
 
201
130
  if params.empty?
202
131
  puts "\n#{usage}\n"
@@ -209,13 +138,11 @@ class Morpheus::Cli::Instances
209
138
  params = params.select {|k,v| instance_keys.include?(k) }
210
139
  params['tags'] = params['tags'].split(',').collect {|it| it.to_s.strip }.compact.uniq if params['tags']
211
140
  payload['instance'].merge!(params)
212
-
213
- json_response = @instances_interface.update(instance["id"], payload)
214
-
215
141
  if options[:dry_run]
216
- print_dry_run("PUT #{@appliance_url}/api/instances", payload)
217
- return
218
- end
142
+ print_dry_run @instances_interface.dry.update(instance["id"], payload)
143
+ return
144
+ end
145
+ json_response = @instances_interface.update(instance["id"], payload)
219
146
 
220
147
  if options[:json]
221
148
  print JSON.pretty_generate(json_response)
@@ -223,838 +150,1237 @@ class Morpheus::Cli::Instances
223
150
  else
224
151
  print_green_success "Updated instance #{instance['name']}"
225
152
  list([])
226
- # details_options = [payload['app']['name']]
227
- # details(details_options)
228
153
  end
229
154
 
230
155
  rescue RestClient::Exception => e
231
156
  print_rest_exception(e, options)
232
157
  exit 1
233
158
  end
234
- end
235
-
236
- def stats(args)
237
- options = {}
238
- optparse = OptionParser.new do|opts|
239
- opts.banner = "Usage: morpheus instances stats [name]"
240
- build_common_options(opts, options, [:json, :remote])
241
- end
242
- if args.count < 1
243
- puts "\n#{optparse.banner}\n\n"
244
- return
245
- end
246
- optparse.parse(args)
247
- connect(options)
248
- begin
249
- instance = find_instance_by_name_or_id(args[0])
250
- json_response = @instances_interface.get(instance['id'])
251
- if options[:json]
252
- print JSON.pretty_generate(json_response)
253
- return
254
- end
255
- instance = json_response['instance']
256
- stats = json_response['stats'] || {}
257
- if options[:json]
258
- print JSON.pretty_generate(stats)
259
- print "\n"
260
- else
261
- print "\n" ,cyan, bold, "#{instance['name']} (#{instance['instanceType']['name']})\n","==================", "\n\n", reset, cyan
262
- stats_map = {}
263
- stats_map[:memory] = "#{Filesize.from("#{stats['usedMemory']} B").pretty} / #{Filesize.from("#{stats['maxMemory']} B").pretty}"
264
- stats_map[:storage] = "#{Filesize.from("#{stats['usedStorage']} B").pretty} / #{Filesize.from("#{stats['maxStorage']} B").pretty}"
265
- stats_map[:cpu] = "#{stats['usedCpu'].to_f.round(2)}%"
266
- tp [stats_map], :memory,:storage,:cpu
267
- print reset, "\n"
268
- end
269
- rescue RestClient::Exception => e
270
- print_rest_exception(e, options)
271
- exit 1
272
- end
273
- end
274
-
275
- def logs(args)
276
- options = {}
277
- optparse = OptionParser.new do|opts|
278
- opts.banner = "Usage: morpheus instances logs [name]"
279
- opts.on( '-n', '--node NODE_ID', "Scope logs to specific Container or VM" ) do |node_id|
280
- options[:node_id] = node_id.to_i
281
- end
282
- build_common_options(opts, options, [:list, :json, :remote])
283
- end
284
- if args.count < 1
285
- puts "\n#{optparse.banner}\n\n"
286
- return
287
- end
288
- optparse.parse(args)
289
- connect(options)
290
- begin
291
- instance = find_instance_by_name_or_id(args[0])
292
- container_ids = instance['containers']
293
- if options[:node_id] && container_ids.include?(options[:node_id])
294
- container_ids = [options[:node_id]]
295
- end
296
- logs = @logs_interface.container_logs(container_ids, { max: options[:max] || 100, offset: options[:offset] || 0, query: options[:phrase]})
297
- if options[:json]
298
- puts logs
299
- else
300
- logs['data'].reverse.each do |log_entry|
301
- log_level = ''
302
- case log_entry['level']
303
- when 'INFO'
304
- log_level = "#{blue}#{bold}INFO#{reset}"
305
- when 'DEBUG'
306
- log_level = "#{white}#{bold}DEBUG#{reset}"
307
- when 'WARN'
308
- log_level = "#{yellow}#{bold}WARN#{reset}"
309
- when 'ERROR'
310
- log_level = "#{red}#{bold}ERROR#{reset}"
311
- when 'FATAL'
312
- log_level = "#{red}#{bold}FATAL#{reset}"
313
- end
314
- puts "[#{log_entry['ts']}] #{log_level} - #{log_entry['message']}"
315
- end
316
- print reset,"\n"
317
- end
318
- rescue RestClient::Exception => e
319
- print_rest_exception(e, options)
320
- exit 1
321
- end
322
- end
323
-
324
- def details(args)
325
- options = {}
326
- optparse = OptionParser.new do|opts|
327
- opts.banner = "Usage: morpheus instances details [name]"
328
- build_common_options(opts, options, [:json, :remote])
329
- end
330
- if args.count < 1
331
- puts "\n#{optparse.banner}\n\n"
332
- exit 1
333
- end
334
- optparse.parse(args)
335
- connect(options)
336
- begin
337
- instance = find_instance_by_name_or_id(args[0])
338
- json_response = @instances_interface.get(instance['id'])
339
- if options[:json]
340
- print JSON.pretty_generate(json_response)
341
- return
342
- end
343
- instance = json_response['instance']
344
- stats = json_response['stats'] || {}
345
- # load_balancers = stats = json_response['loadBalancers'] || {}
346
-
347
- status_string = instance['status']
348
- if status_string == 'running'
349
- status_string = "#{green}#{status_string.upcase}#{cyan}"
350
- elsif status_string == 'stopped' or status_string == 'failed'
351
- status_string = "#{red}#{status_string.upcase}#{cyan}"
352
- elsif status_string == 'unknown'
353
- status_string = "#{white}#{status_string.upcase}#{cyan}"
354
- else
355
- status_string = "#{yellow}#{status_string.upcase}#{cyan}"
356
- end
357
- connection_string = ''
358
- if !instance['connectionInfo'].nil? && instance['connectionInfo'].empty? == false
359
- connection_string = "#{instance['connectionInfo'][0]['ip']}:#{instance['connectionInfo'][0]['port']}"
360
- end
361
-
362
- print "\n" ,cyan, bold, "Instance Details\n","==================", reset, "\n\n"
363
- print cyan
364
- puts "ID: #{instance['id']}"
365
- puts "Name: #{instance['name']}"
366
- puts "Description: #{instance['description']}"
367
- puts "Group: #{instance['group'] ? instance['group']['name'] : ''}"
368
- puts "Cloud: #{instance['cloud'] ? instance['cloud']['name'] : ''}"
369
- puts "Type: #{instance['instanceType']['name']}"
370
- puts "Environment: #{instance['instanceContext']}"
371
- puts "Nodes: #{instance['containers'] ? instance['containers'].count : 0}"
372
- puts "Connection: #{connection_string}"
373
- #puts "Account: #{instance['account'] ? instance['account']['name'] : ''}"
374
- puts "Status: #{status_string}"
375
- print cyan, "Memory: \t#{Filesize.from("#{stats['usedMemory']} B").pretty} / #{Filesize.from("#{stats['maxMemory']} B").pretty}\n"
376
- print cyan, "Storage: \t#{Filesize.from("#{stats['usedStorage']} B").pretty} / #{Filesize.from("#{stats['maxStorage']} B").pretty}\n\n",reset
377
-
378
- #puts instance
379
- rescue RestClient::Exception => e
380
- print_rest_exception(e, options)
381
- exit 1
382
- end
383
- end
384
-
385
- def envs(args)
386
- options = {}
387
- optparse = OptionParser.new do|opts|
388
- opts.banner = "Usage: morpheus instances envs [name]"
389
- build_common_options(opts, options, [:json, :remote])
390
- end
391
- if args.count < 1
392
- puts "\n#{optparse.banner}\n\n"
393
- exit 1
394
- end
395
- optparse.parse(args)
396
- connect(options)
397
- begin
398
- instance = find_instance_by_name_or_id(args[0])
399
- env_results = @instances_interface.get_envs(instance['id'])
400
- print "\n" ,cyan, bold, "#{instance['name']} (#{instance['instanceType']['name']})\n","==================", "\n\n", reset, cyan
401
- envs = env_results['envs'] || {}
402
- if env_results['readOnlyEnvs']
403
- envs += env_results['readOnlyEnvs'].map { |k,v| {:name => k, :value => k.downcase.include?("password") || v['masked'] ? "********" : v['value'], :export => true}}
404
- end
405
- tp envs, :name, :value, :export
406
- print "\n" ,cyan, bold, "Imported Envs\n","==================", "\n\n", reset, cyan
407
- imported_envs = env_results['importedEnvs'].map { |k,v| {:name => k, :value => k.downcase.include?("password") || v['masked'] ? "********" : v['value']}}
408
- tp imported_envs
409
- print reset, "\n"
410
-
411
- rescue RestClient::Exception => e
412
- print_rest_exception(e, options)
413
- exit 1
414
- end
415
- end
416
-
417
- def setenv(args)
418
- options = {}
419
-
420
- optparse = OptionParser.new do|opts|
421
- opts.banner = "Usage: morpheus instances setenv INSTANCE NAME VALUE [-e]"
422
- opts.on( '-e', "Exportable" ) do |exportable|
423
- options[:export] = exportable
424
- end
425
- opts.on( '-M', "Masked" ) do |masked|
426
- options[:masked] = masked
427
- end
428
- build_common_options(opts, options, [:json, :remote])
429
- end
430
- if args.count < 3
431
- puts "\n#{optparse.banner}\n\n"
432
- exit 1
433
- end
434
- optparse.parse(args)
435
- connect(options)
436
- begin
437
- instance = find_instance_by_name_or_id(args[0])
438
- evar = {name: args[1], value: args[2], export: options[:export], masked: options[:masked]}
439
- params = {}
440
- @instances_interface.create_env(instance['id'], [evar])
441
- envs([args[0]])
442
- rescue RestClient::Exception => e
443
- print_rest_exception(e, options)
444
- exit 1
445
- end
446
- end
447
-
448
- def delenv(args)
449
- options = {}
450
- optparse = OptionParser.new do|opts|
451
- opts.banner = "Usage: morpheus instances setenv INSTANCE NAME"
452
- build_common_options(opts, options, [:json, :remote])
453
- end
454
- if args.count < 2
455
- puts "\n#{optparse.banner}\n\n"
456
- exit 1
457
- end
458
- optparse.parse(args)
459
- connect(options)
460
- begin
461
- instance = find_instance_by_name_or_id(args[0])
462
- @instances_interface.del_env(instance['id'], args[1])
463
- envs([args[0]])
464
- rescue RestClient::Exception => e
465
- print_rest_exception(e, options)
466
- exit 1
467
- end
468
- end
469
-
470
- def stop(args)
471
- options = {}
472
- optparse = OptionParser.new do|opts|
473
- opts.banner = "Usage: morpheus instances stop [name]"
474
- build_common_options(opts, options, [:auto_confirm, :json, :remote])
475
- end
476
- if args.count < 1
477
- puts "\n#{optparse.banner}\n\n"
478
- exit 1
479
- end
480
- optparse.parse(args)
481
- connect(options)
482
- begin
483
- instance = find_instance_by_name_or_id(args[0])
484
- unless options[:yes] || ::Morpheus::Cli::OptionTypes::confirm("Are you sure you would like to stop this instance?", options)
485
- exit 1
486
- end
487
- json_response = @instances_interface.stop(instance['id'])
488
- if options[:json]
489
- print JSON.pretty_generate(json_response)
490
- print "\n"
491
- end
492
- return
493
- rescue RestClient::Exception => e
494
- print_rest_exception(e, options)
495
- exit 1
496
- end
497
- end
498
-
499
- def start(args)
500
- options = {}
501
- optparse = OptionParser.new do|opts|
502
- opts.banner = "Usage: morpheus instances start [name]"
503
- build_common_options(opts, options, [:json, :remote])
504
- end
505
- if args.count < 1
506
- puts "\n#{optparse.banner}\n\n"
507
- exit 1
508
- end
509
- optparse.parse(args)
510
- connect(options)
511
- begin
512
- instance = find_instance_by_name_or_id(args[0])
513
- json_response = @instances_interface.start(instance['id'])
514
- if options[:json]
515
- print JSON.pretty_generate(json_response)
516
- print "\n"
517
- end
518
- return
519
- rescue RestClient::Exception => e
520
- print_rest_exception(e, options)
521
- exit 1
522
- end
523
- end
524
-
525
- def restart(args)
526
- options = {}
527
- optparse = OptionParser.new do|opts|
528
- opts.banner = "Usage: morpheus instances restart [name]"
529
- build_common_options(opts, options, [:auto_confirm, :json, :remote])
530
- end
531
- if args.count < 1
532
- puts "\n#{optparse.banner}\n\n"
533
- exit 1
534
- end
535
- optparse.parse(args)
536
- connect(options)
537
- begin
538
- instance = find_instance_by_name_or_id(args[0])
539
- unless options[:yes] || ::Morpheus::Cli::OptionTypes::confirm("Are you sure you would like to restart this instance?", options)
540
- exit 1
541
- end
542
- json_response = @instances_interface.restart(instance['id'])
543
- if options[:json]
544
- print JSON.pretty_generate(json_response)
545
- print "\n"
546
- end
547
- return
548
- rescue RestClient::Exception => e
549
- print_rest_exception(e, options)
550
- exit 1
551
- end
552
- end
553
-
554
- def stop_service(args)
555
- options = {}
556
- optparse = OptionParser.new do|opts|
557
- opts.banner = "Usage: morpheus instances stop-service [name]"
558
- build_common_options(opts, options, [:auto_confirm, :json, :remote])
559
- end
560
- if args.count < 1
561
- puts "\n#{optparse.banner}\n\n"
562
- exit 1
563
- end
564
- optparse.parse(args)
565
- connect(options)
566
- begin
567
- instance = find_instance_by_name_or_id(args[0])
568
- unless options[:yes] || ::Morpheus::Cli::OptionTypes::confirm("Are you sure you would like to stop this instance?", options)
569
- exit 1
570
- end
571
- json_response = @instances_interface.stop(instance['id'],false)
572
- if options[:json]
573
- print JSON.pretty_generate(json_response)
574
- print "\n"
575
- else
576
- puts "Stopping service on #{args[0]}"
577
- end
578
- return
579
- rescue RestClient::Exception => e
580
- print_rest_exception(e, options)
581
- exit 1
582
- end
583
- end
584
-
585
- def start_service(args)
586
- options = {}
587
- optparse = OptionParser.new do|opts|
588
- opts.banner = "Usage: morpheus instances start-service [name]"
589
- build_common_options(opts, options, [:json, :remote])
590
- end
591
- if args.count < 1
592
- puts "\n#{optparse.banner}\n\n"
593
- exit 1
594
- end
595
- optparse.parse(args)
596
- connect(options)
597
- begin
598
- instance = find_instance_by_name_or_id(args[0])
599
- json_response = @instances_interface.start(instance['id'],false)
600
- if options[:json]
601
- print JSON.pretty_generate(json_response)
602
- print "\n"
603
- else
604
- puts "Starting service on #{args[0]}"
605
- end
606
- return
607
- rescue RestClient::Exception => e
608
- print_rest_exception(e, options)
609
- exit 1
610
- end
611
- end
612
-
613
- def restart_service(args)
614
- options = {}
615
- optparse = OptionParser.new do|opts|
616
- opts.banner = "Usage: morpheus instances restart-service [name]"
617
- build_common_options(opts, options, [:auto_confirm, :json, :remote])
618
- end
619
- if args.count < 1
620
- puts "\n#{optparse.banner}\n\n"
621
- exit 1
622
- end
623
- optparse.parse(args)
624
- connect(options)
625
- begin
626
- instance = find_instance_by_name_or_id(args[0])
627
- unless options[:yes] || ::Morpheus::Cli::OptionTypes::confirm("Are you sure you would like to restart this instance?", options)
628
- exit 1
629
- end
630
- json_response = @instances_interface.restart(instance['id'],false)
631
- if options[:json]
632
- print JSON.pretty_generate(json_response)
633
- print "\n"
634
- else
635
- puts "Restarting service on instance #{args[0]}"
636
- end
637
- return
638
- rescue RestClient::Exception => e
639
- print_rest_exception(e, options)
640
- exit 1
641
- end
642
- end
643
-
644
- def resize(args)
645
- options = {}
646
- optparse = OptionParser.new do|opts|
647
- opts.banner = "Usage: morpheus instances resize [name]"
648
- build_common_options(opts, options, [:options, :json, :dry_run, :remote])
649
- end
650
- if args.count < 1
651
- puts "\n#{optparse.banner}\n\n"
652
- exit 1
653
- end
654
- optparse.parse(args)
655
- connect(options)
656
- begin
657
- instance = find_instance_by_name_or_id(args[0])
658
-
659
- group_id = instance['group']['id']
660
- cloud_id = instance['cloud']['id']
661
- layout_id = instance['layout']['id']
662
-
663
- plan_id = instance['plan']['id']
664
- payload = {
665
- :instance => {:id => instance["id"]}
666
- }
667
-
668
- # avoid 500 error
669
- # payload[:servicePlanOptions] = {}
670
-
671
- puts "\nDue to limitations by most Guest Operating Systems, Disk sizes can only be expanded and not reduced.\nIf a smaller plan is selected, memory and CPU (if relevant) will be reduced but storage will not.\n\n"
672
-
673
- # prompt for service plan
674
- service_plans_json = @instances_interface.service_plans({zoneId: cloud_id, layoutId: layout_id})
675
- service_plans = service_plans_json["plans"]
676
- service_plans_dropdown = service_plans.collect {|sp| {'name' => sp["name"], 'value' => sp["id"]} } # already sorted
677
- service_plans_dropdown.each do |plan|
678
- if plan['value'] && plan['value'].to_i == plan_id.to_i
679
- plan['name'] = "#{plan['name']} (current)"
680
- end
681
- end
682
- plan_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'servicePlan', 'type' => 'select', 'fieldLabel' => 'Plan', 'selectOptions' => service_plans_dropdown, 'required' => true, 'description' => 'Choose the appropriately sized plan for this instance'}],options[:options])
683
- service_plan = service_plans.find {|sp| sp["id"] == plan_prompt['servicePlan'].to_i }
684
- new_plan_id = service_plan["id"]
685
- #payload[:servicePlan] = new_plan_id # ew, this api uses servicePlanId instead
686
- payload[:servicePlanId] = new_plan_id
687
- payload[:instance][:plan] = {id: service_plan["id"]}
688
-
689
- volumes_response = @instances_interface.volumes(instance['id'])
690
- current_volumes = volumes_response['volumes'].sort {|x,y| x['displayOrder'] <=> y['displayOrder'] }
691
-
692
- # prompt for volumes
693
- volumes = prompt_resize_volumes(current_volumes, service_plan, options, @api_client, {})
694
- if !volumes.empty?
695
- payload[:volumes] = volumes
696
- end
697
-
698
- # only amazon supports this option
699
- # for now, always do this
700
- payload[:deleteOriginalVolumes] = true
701
-
702
- if options[:dry_run]
703
- print_dry_run("PUT #{@appliance_url}/api/instances/#{instance['id']}/resize", payload)
704
- return
705
- end
706
- json_response = @instances_interface.resize(instance['id'], payload)
707
- if options[:json]
708
- print JSON.pretty_generate(json_response)
709
- print "\n"
710
- else
711
- print_green_success "Resizing instance #{instance['name']}"
712
- list([])
713
- end
714
-
715
- rescue RestClient::Exception => e
716
- print_rest_exception(e, options)
717
- exit 1
718
- end
719
- end
720
-
721
- def backup(args)
722
- options = {}
723
- optparse = OptionParser.new do|opts|
724
- opts.banner = "Usage: morpheus instances backup [name]"
725
- build_common_options(opts, options, [:json, :remote])
726
- end
727
- if args.count < 1
728
- puts "\n#{optparse.banner}\n\n"
729
- exit 1
730
- end
731
- optparse.parse(args)
732
- connect(options)
733
- begin
734
- instance = find_instance_by_name_or_id(args[0])
735
- json_response = @instances_interface.backup(instance['id'])
736
- if options[:json]
737
- print JSON.pretty_generate(json_response)
738
- print "\n"
739
- else
740
- puts "Backup initiated."
741
- end
742
- return
743
- rescue RestClient::Exception => e
744
- print_rest_exception(e, options)
745
- exit 1
746
- end
747
- end
748
-
749
- def list(args)
750
- options = {}
751
- optparse = OptionParser.new do|opts|
752
- opts.on( '-g', '--group GROUP', "Group Name" ) do |val|
753
- options[:group_name] = val
754
- end
755
- build_common_options(opts, options, [:list, :json, :remote])
756
- end
757
- optparse.parse(args)
758
- connect(options)
759
- begin
760
- params = {}
761
- group = find_group_from_options(options)
762
- if group
763
- params['site'] = group['id']
764
- end
765
- [:phrase, :offset, :max, :sort, :direction].each do |k|
766
- params[k] = options[k] unless options[k].nil?
767
- end
768
-
769
- json_response = @instances_interface.get(params)
770
- if options[:json]
771
- print JSON.pretty_generate(json_response)
772
- print "\n"
773
- else
774
- instances = json_response['instances']
775
-
776
- print "\n" ,cyan, bold, "Morpheus Instances\n","==================", reset, "\n\n"
777
- if instances.empty?
778
- puts yellow,"No instances currently configured.",reset
779
- else
780
- print cyan
781
- instance_table = instances.collect do |instance|
782
- status_string = instance['status']
783
- if status_string == 'running'
784
- status_string = "#{green}#{status_string.upcase}#{cyan}"
785
- elsif status_string == 'stopped' or status_string == 'failed'
786
- status_string = "#{red}#{status_string.upcase}#{cyan}"
787
- elsif status_string == 'unknown'
788
- status_string = "#{white}#{status_string.upcase}#{cyan}"
789
- else
790
- status_string = "#{yellow}#{status_string.upcase}#{cyan}"
791
- end
792
- connection_string = ''
793
- if !instance['connectionInfo'].nil? && instance['connectionInfo'].empty? == false
794
- connection_string = "#{instance['connectionInfo'][0]['ip']}:#{instance['connectionInfo'][0]['port']}"
795
- end
796
- {id: instance['id'], name: instance['name'], connection: connection_string, environment: instance['instanceContext'], nodes: instance['containers'].count, status: status_string, type: instance['instanceType']['name'], group: !instance['group'].nil? ? instance['group']['name'] : nil, cloud: !instance['cloud'].nil? ? instance['cloud']['name'] : nil}
797
- end
798
- tp instance_table, :id, :name, :group, :cloud, :type, :environment, :nodes, :connection, :status
799
- end
800
- print reset,"\n\n"
801
- end
802
-
803
- rescue RestClient::Exception => e
804
- print_rest_exception(e, options)
805
- exit 1
806
- end
807
- end
808
-
809
- def remove(args)
810
- options = {}
811
- query_params = {keepBackups: 'off', force: 'off'}
812
- optparse = OptionParser.new do|opts|
813
- opts.banner = "Usage: morpheus instances remove [name] [-fB]"
814
- opts.on( '-f', '--force', "Force Remove" ) do
815
- query_params[:force] = 'on'
816
- end
817
- opts.on( '-B', '--keep-backups', "Preserve copy of backups" ) do
818
- query_params[:keepBackups] = 'on'
819
- end
820
- build_common_options(opts, options, [:auto_confirm, :json, :remote])
821
-
822
- end
823
- if args.count < 1
824
- puts "\n#{optparse}\n\n"
825
- exit 1
826
- end
827
- optparse.parse(args)
828
- connect(options)
829
- begin
830
- instance = find_instance_by_name_or_id(args[0])
831
- unless options[:yes] || ::Morpheus::Cli::OptionTypes::confirm("Are you sure you would like to remove the instance '#{instance['name']}'?", options)
832
- exit 1
833
- end
834
- @instances_interface.destroy(instance['id'],query_params)
835
- list([])
836
- rescue RestClient::Exception => e
837
- print_rest_exception(e, options)
838
- exit 1
839
- end
840
- end
841
-
842
- def firewall_disable(args)
843
- options = {}
844
- optparse = OptionParser.new do|opts|
845
- opts.banner = "Usage: morpheus instances firewall-disable [name]"
846
- build_common_options(opts, options, [:json, :remote])
847
- end
848
- if args.count < 1
849
- puts "\n#{optparse.banner}\n\n"
850
- exit 1
851
- end
852
- optparse.parse(args)
853
- connect(options)
854
- begin
855
- instance = find_instance_by_name_or_id(args[0])
856
- @instances_interface.firewall_disable(instance['id'])
857
- security_groups([args[0]])
858
- rescue RestClient::Exception => e
859
- print_rest_exception(e, options)
860
- exit 1
861
- end
862
- end
863
-
864
- def firewall_enable(args)
865
- options = {}
866
- optparse = OptionParser.new do|opts|
867
- opts.banner = "Usage: morpheus instances firewall-enable [name]"
868
- build_common_options(opts, options, [:json, :remote])
869
- end
870
- if args.count < 1
871
- puts "\n#{optparse.banner}\n\n"
872
- exit 1
873
- end
874
- optparse.parse(args)
875
- connect(options)
876
- begin
877
- instance_results = @instances_interface.get({name: args[0]})
878
- if instance_results['instances'].empty?
879
- puts "Instance not found by name #{args[0]}"
880
- return
881
- end
882
- @instances_interface.firewall_enable(instance_results['instances'][0]['id'])
883
- security_groups([args[0]])
884
- rescue RestClient::Exception => e
885
- print_rest_exception(e, options)
886
- exit 1
887
- end
888
- end
889
-
890
- def security_groups(args)
891
- options = {}
892
- optparse = OptionParser.new do|opts|
893
- opts.banner = "Usage: morpheus instances security-groups [name]"
894
- build_common_options(opts, options, [:json, :remote])
895
- end
896
- if args.count < 1
897
- puts "\n#{optparse.banner}\n\n"
898
- exit 1
899
- end
900
- optparse.parse(args)
901
- connect(options)
902
- begin
903
- instance = find_instance_by_name_or_id(args[0])
904
- instance_id = instance['id']
905
- json_response = @instances_interface.security_groups(instance_id)
906
-
907
- securityGroups = json_response['securityGroups']
908
- print "\n" ,cyan, bold, "Morpheus Security Groups for Instance:#{instance_id}\n","==================", reset, "\n\n"
909
- print cyan, "Firewall Enabled=#{json_response['firewallEnabled']}\n\n"
910
- if securityGroups.empty?
911
- puts yellow,"No security groups currently applied.",reset
912
- else
913
- securityGroups.each do |securityGroup|
914
- print cyan, "= #{securityGroup['id']} (#{securityGroup['name']}) - (#{securityGroup['description']})\n"
915
- end
916
- end
917
- print reset,"\n\n"
918
-
919
- rescue RestClient::Exception => e
920
- print_rest_exception(e, options)
921
- exit 1
922
- end
923
- end
924
-
925
- def apply_security_groups(args)
926
- options = {}
927
- clear_or_secgroups_specified = false
928
- optparse = OptionParser.new do|opts|
929
- opts.banner = "Usage: morpheus instances apply-security-groups [name] [options]"
930
- opts.on( '-c', '--clear', "Clear all security groups" ) do
931
- options[:securityGroupIds] = []
932
- clear_or_secgroups_specified = true
933
- end
934
- opts.on( '-S', '--secgroups SECGROUPS', "Apply the specified comma separated security group ids" ) do |secgroups|
935
- options[:securityGroupIds] = secgroups.split(",")
936
- clear_or_secgroups_specified = true
937
- end
938
- build_common_options(opts, options, [:json, :remote])
939
- end
940
- if args.count < 1
941
- puts "\n#{optparse.banner}\n\n"
942
- exit 1
943
- end
944
- optparse.parse(args)
945
- connect(options)
946
-
947
- if !clear_or_secgroups_specified
948
- puts usage
949
- exit
950
- end
951
-
952
- begin
953
- instance = find_instance_by_name_or_id(args[0])
954
- @instances_interface.apply_security_groups(instance['id'], options)
955
- security_groups([args[0]])
956
- rescue RestClient::Exception => e
957
- print_rest_exception(e, options)
958
- exit 1
959
- end
960
- end
961
-
962
-
963
- def run_workflow(args)
964
- options = {}
965
-
966
- optparse = OptionParser.new do|opts|
967
- opts.banner = "Usage: morpheus instances run-workflow [INSTANCE] [name] [options]"
968
- build_common_options(opts, options, [:options, :json, :remote])
969
- end
970
- if args.count < 2
971
- puts "\n#{optparse}\n\n"
972
- exit 1
973
- end
974
-
975
- optparse.parse(args)
976
- connect(options)
977
- instance = find_instance_by_name_or_id(args[0])
978
- workflow = find_workflow_by_name(args[1])
979
- task_types = @tasks_interface.task_types()
980
- editable_options = []
981
- workflow['taskSetTasks'].sort{|a,b| a['taskOrder'] <=> b['taskOrder']}.each do |task_set_task|
982
- task_type_id = task_set_task['task']['taskType']['id']
983
- task_type = task_types['taskTypes'].find{ |current_task_type| current_task_type['id'] == task_type_id}
984
- task_opts = task_type['optionTypes'].select { |otype| otype['editable']}
985
- if !task_opts.nil? && !task_opts.empty?
986
- editable_options += task_opts.collect do |task_opt|
987
- new_task_opt = task_opt.clone
988
- new_task_opt['fieldContext'] = "#{task_set_task['id']}.#{new_task_opt['fieldContext']}"
989
- end
990
- end
991
- end
992
- params = options[:options] || {}
993
-
994
- if params.empty? && !editable_options.empty?
995
- puts "\n#{optparse.banner}\n\n"
996
- option_lines = editable_options.collect {|it| "\t-O #{it['fieldContext'] ? (it['fieldContext'] + '.') : ''}#{it['fieldName']}=\"value\"" }.join("\n")
997
- puts "\nAvailable Options:\n#{option_lines}\n\n"
998
- exit 1
999
- end
1000
-
1001
- workflow_payload = {taskSet: {"#{workflow['id']}" => params }}
1002
- begin
1003
-
1004
- json_response = @instances_interface.workflow(instance['id'],workflow['id'], workflow_payload)
1005
- if options[:json]
1006
- print JSON.pretty_generate(json_response)
1007
- print "\n"
1008
- else
1009
- puts "Running workflow..."
1010
- end
1011
- rescue RestClient::Exception => e
1012
- print_rest_exception(e, options)
1013
- exit 1
1014
- end
1015
- end
1016
-
1017
- private
1018
-
1019
- def find_instance_by_id(id)
1020
- instance_results = @instances_interface.get(id.to_i)
1021
- if instance_results['instance'].empty?
1022
- print_red_alert "Instance not found by id #{id}"
1023
- exit 1
1024
- end
1025
- instance = instance_results['instance']
1026
- # instance['stats'] = instance_results['stats'] || {}
1027
- # instance['loadBalancers'] = instance_results['loadBalancers'][0]['lbs'] || {}
1028
- return instance
1029
- end
1030
-
1031
- def find_instance_by_name(name)
1032
- instance_results = @instances_interface.get({name: name})
1033
- if instance_results['instances'].empty?
1034
- print_red_alert "Instance not found by name #{name}"
1035
- exit 1
1036
- end
1037
- instance = instance_results['instances'][0]
1038
- # instance['stats'] = instance_results['stats'][instance['id'].to_s] || {}
1039
- return instance
1040
- end
1041
-
1042
- def find_instance_by_name_or_id(val)
1043
- if val.to_s =~ /\A\d{1,}\Z/
1044
- return find_instance_by_id(val)
1045
- else
1046
- return find_instance_by_name(val)
1047
- end
1048
- end
1049
-
1050
- def find_workflow_by_name(name)
1051
- task_set_results = @task_sets_interface.get(name)
1052
- if !task_set_results['taskSets'].nil? && !task_set_results['taskSets'].empty?
1053
- return task_set_results['taskSets'][0]
1054
- else
1055
- print_red_alert "Workflow not found by name #{name}"
1056
- exit 1
1057
- end
1058
- end
159
+ end
160
+
161
+ def status_check(args)
162
+ out = ""
163
+ options = {}
164
+ optparse = OptionParser.new do|opts|
165
+ opts.banner = subcommand_usage("[name]")
166
+ build_common_options(opts, options, [:quiet, :json, :remote]) # no :dry_run, just do it man
167
+ end
168
+ optparse.parse!(args)
169
+ if args.count < 1
170
+ puts optparse
171
+ exit 1
172
+ end
173
+ connect(options)
174
+ # todo: just return status or maybe check if instance['status'] == args[0]
175
+ instance = find_instance_by_name_or_id(args[0])
176
+ exit_code = 0
177
+ if instance['status'].to_s.downcase != (args[1] || "running").to_s.downcase
178
+ exit_code = 1
179
+ end
180
+ if options[:json]
181
+ mock_json = {status: instance['status'], exit: exit_code}
182
+ out << JSON.pretty_generate(mock_json)
183
+ out << "\n"
184
+ elsif !options[:quiet]
185
+ out << cyan
186
+ out << "Status: #{format_instance_status(instance)}"
187
+ out << reset
188
+ out << "\n"
189
+ end
190
+ print out unless options[:quiet]
191
+ exit exit_code #return exit_code
192
+ end
193
+
194
+ def stats(args)
195
+ options = {}
196
+ optparse = OptionParser.new do|opts|
197
+ opts.banner = subcommand_usage("[name]")
198
+ build_common_options(opts, options, [:json, :dry_run, :remote])
199
+ end
200
+ optparse.parse!(args)
201
+ if args.count < 1
202
+ puts optparse
203
+ exit 1
204
+ end
205
+ connect(options)
206
+ begin
207
+ instance = find_instance_by_name_or_id(args[0])
208
+ if options[:dry_run]
209
+ print_dry_run @instances_interface.dry.get(instance['id'])
210
+ return
211
+ end
212
+ json_response = @instances_interface.get(instance['id'])
213
+ if options[:json]
214
+ print JSON.pretty_generate(json_response), "\n"
215
+ return
216
+ end
217
+ instance = json_response['instance']
218
+ stats = json_response['stats'] || {}
219
+ print "\n" ,cyan, bold, "Instance Stats: #{instance['name']} (#{instance['instanceType']['name']})\n","==================", "\n\n", reset, cyan
220
+ puts "Status: #{format_instance_status(instance)}"
221
+ print "\n"
222
+ if ((stats['maxMemory'].to_i != 0) || (stats['maxStorage'].to_i != 0))
223
+ # stats_map = {}
224
+ # stats_map[:memory] = "#{Filesize.from("#{stats['usedMemory']} B").pretty} / #{Filesize.from("#{stats['maxMemory']} B").pretty}"
225
+ # stats_map[:storage] = "#{Filesize.from("#{stats['usedStorage']} B").pretty} / #{Filesize.from("#{stats['maxStorage']} B").pretty}"
226
+ # stats_map[:cpu] = "#{stats['usedCpu'].to_f.round(2)}%"
227
+ # tp [stats_map], :memory,:storage,:cpu
228
+ # print "\n"
229
+ print_stats_usage(stats)
230
+ else
231
+ print cyan, "No data.", "\n", reset
232
+ end
233
+ print reset, "\n"
234
+ rescue RestClient::Exception => e
235
+ print_rest_exception(e, options)
236
+ exit 1
237
+ end
238
+ end
239
+
240
+ def console(args)
241
+ options = {}
242
+ optparse = OptionParser.new do|opts|
243
+ opts.banner = subcommand_usage("[name]")
244
+ opts.on( '-n', '--node NODE_ID', "Scope console to specific Container or VM" ) do |node_id|
245
+ options[:node_id] = node_id.to_i
246
+ end
247
+ # build_common_options(opts, options, [:list, :json, :dry_run, :remote])
248
+ end
249
+ optparse.parse!(args)
250
+ if args.count < 1
251
+ puts optparse
252
+ exit 1
253
+ end
254
+ connect(options)
255
+
256
+ begin
257
+ instance = find_instance_by_name_or_id(args[0])
258
+ link = "#{@appliance_url}/login/oauth-redirect?access_token=#{@access_token}\\&redirectUri=/terminal/#{instance['id']}"
259
+ container_ids = instance['containers']
260
+ if options[:node_id] && container_ids.include?(options[:node_id])
261
+ link += "?containerId=#{options[:node_id]}"
262
+ end
263
+
264
+ if RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/
265
+ system "start #{link}"
266
+ elsif RbConfig::CONFIG['host_os'] =~ /darwin/
267
+ system "open #{link}"
268
+ elsif RbConfig::CONFIG['host_os'] =~ /linux|bsd/
269
+ system "xdg-open #{link}"
270
+ end
271
+ rescue RestClient::Exception => e
272
+ print_rest_exception(e, options)
273
+ exit 1
274
+ end
275
+ end
276
+
277
+ def logs(args)
278
+ options = {}
279
+ optparse = OptionParser.new do|opts|
280
+ opts.banner = subcommand_usage("[name]")
281
+ opts.on( '-n', '--node NODE_ID', "Scope logs to specific Container or VM" ) do |node_id|
282
+ options[:node_id] = node_id.to_i
283
+ end
284
+ build_common_options(opts, options, [:list, :json, :dry_run, :remote])
285
+ end
286
+ optparse.parse!(args)
287
+ if args.count < 1
288
+ puts optparse
289
+ exit 1
290
+ end
291
+ connect(options)
292
+ begin
293
+ instance = find_instance_by_name_or_id(args[0])
294
+ container_ids = instance['containers']
295
+ if options[:node_id] && container_ids.include?(options[:node_id])
296
+ container_ids = [options[:node_id]]
297
+ end
298
+ query_params = { max: options[:max] || 100, offset: options[:offset] || 0, query: options[:phrase]}
299
+ if options[:dry_run]
300
+ print_dry_run @logs_interface.dry.container_logs(container_ids, query_params)
301
+ return
302
+ end
303
+ logs = @logs_interface.container_logs(container_ids, query_params)
304
+ if options[:json]
305
+ puts logs
306
+ else
307
+ logs['data'].reverse.each do |log_entry|
308
+ log_level = ''
309
+ case log_entry['level']
310
+ when 'INFO'
311
+ log_level = "#{blue}#{bold}INFO#{reset}"
312
+ when 'DEBUG'
313
+ log_level = "#{white}#{bold}DEBUG#{reset}"
314
+ when 'WARN'
315
+ log_level = "#{yellow}#{bold}WARN#{reset}"
316
+ when 'ERROR'
317
+ log_level = "#{red}#{bold}ERROR#{reset}"
318
+ when 'FATAL'
319
+ log_level = "#{red}#{bold}FATAL#{reset}"
320
+ end
321
+ puts "[#{log_entry['ts']}] #{log_level} - #{log_entry['message']}"
322
+ end
323
+ print reset,"\n"
324
+ end
325
+ rescue RestClient::Exception => e
326
+ print_rest_exception(e, options)
327
+ exit 1
328
+ end
329
+ end
330
+
331
+ def get(args)
332
+ options = {}
333
+ optparse = OptionParser.new do|opts|
334
+ opts.banner = subcommand_usage("[name]")
335
+ build_common_options(opts, options, [:json, :dry_run, :remote])
336
+ end
337
+ optparse.parse!(args)
338
+ if args.count < 1
339
+ puts optparse
340
+ exit 1
341
+ end
342
+ connect(options)
343
+ begin
344
+ if options[:dry_run]
345
+ if args[0].to_s =~ /\A\d{1,}\Z/
346
+ print_dry_run @instances_interface.dry.get(args[0].to_i)
347
+ else
348
+ print_dry_run @instances_interface.dry.get({name:args[0]})
349
+ end
350
+ return
351
+ end
352
+ instance = find_instance_by_name_or_id(args[0])
353
+ json_response = @instances_interface.get(instance['id'])
354
+ if options[:json]
355
+ print JSON.pretty_generate(json_response), "\n"
356
+ return
357
+ end
358
+ instance = json_response['instance']
359
+ stats = json_response['stats'] || {}
360
+ # load_balancers = stats = json_response['loadBalancers'] || {}
361
+
362
+ connection_string = ''
363
+ if !instance['connectionInfo'].nil? && instance['connectionInfo'].empty? == false
364
+ connection_string = "#{instance['connectionInfo'][0]['ip']}:#{instance['connectionInfo'][0]['port']}"
365
+ end
366
+
367
+ print "\n" ,cyan, bold, "Instance Details\n","==================", reset, "\n\n"
368
+ print cyan
369
+ puts "ID: #{instance['id']}"
370
+ puts "Name: #{instance['name']}"
371
+ puts "Description: #{instance['description']}"
372
+ puts "Group: #{instance['group'] ? instance['group']['name'] : ''}"
373
+ puts "Cloud: #{instance['cloud'] ? instance['cloud']['name'] : ''}"
374
+ puts "Type: #{instance['instanceType']['name']}"
375
+ puts "Plan: #{instance['plan'] ? instance['plan']['name'] : ''}"
376
+ puts "Environment: #{instance['instanceContext']}"
377
+ puts "Nodes: #{instance['containers'] ? instance['containers'].count : 0}"
378
+ puts "Connection: #{connection_string}"
379
+ #puts "Account: #{instance['account'] ? instance['account']['name'] : ''}"
380
+ puts "Status: #{format_instance_status(instance)}"
381
+ if ((stats['maxMemory'].to_i != 0) || (stats['maxStorage'].to_i != 0))
382
+ print "\n"
383
+ # stats_map = {}
384
+ # stats_map[:memory] = "#{Filesize.from("#{stats['usedMemory']} B").pretty} / #{Filesize.from("#{stats['maxMemory']} B").pretty}"
385
+ # stats_map[:storage] = "#{Filesize.from("#{stats['usedStorage']} B").pretty} / #{Filesize.from("#{stats['maxStorage']} B").pretty}"
386
+ # stats_map[:cpu] = "#{stats['usedCpu'].to_f.round(2)}%"
387
+ # tp [stats_map], :memory,:storage,:cpu
388
+ print_stats_usage(stats)
389
+ else
390
+ # print cyan, "No data.", "\n", reset
391
+ end
392
+ print reset, "\n"
393
+
394
+ #puts instance
395
+ rescue RestClient::Exception => e
396
+ print_rest_exception(e, options)
397
+ exit 1
398
+ end
399
+ end
400
+
401
+ def backups(args)
402
+ options = {}
403
+ optparse = OptionParser.new do|opts|
404
+ opts.banner = subcommand_usage("[name]")
405
+ build_common_options(opts, options, [:auto_confirm, :json, :dry_run, :remote])
406
+ end
407
+ optparse.parse!(args)
408
+ if args.count < 1
409
+ puts optparse
410
+ exit 1
411
+ end
412
+ connect(options)
413
+ begin
414
+ instance = find_instance_by_name_or_id(args[0])
415
+ params = {}
416
+ if options[:dry_run]
417
+ print_dry_run @instances_interface.dry.backups(instance['id'], params)
418
+ return
419
+ end
420
+ json_response = @instances_interface.backups(instance['id'], params)
421
+ if options[:json]
422
+ print JSON.pretty_generate(json_response), "\n"
423
+ return
424
+ end
425
+ backups = json_response['backups']
426
+ stats = json_response['stats'] || {}
427
+ # load_balancers = stats = json_response['loadBalancers'] || {}
428
+
429
+ print "\n" ,cyan, bold, "Instance Backups\n","==================", reset, "\n\n"
430
+ print cyan
431
+ puts "ID: #{instance['id']}"
432
+ puts "Name: #{instance['name']}"
433
+ print "\n"
434
+ puts "Backups:"
435
+ backup_rows = backups.collect {|it| {id: it['id'], name: it['name'], dateCreated: it['dateCreated']} }
436
+ print cyan
437
+ tp backup_rows, [
438
+ :id,
439
+ :name,
440
+ {:dateCreated => {:display_name => "Date Created"} }
441
+ ]
442
+ print reset, "\n"
443
+ rescue RestClient::Exception => e
444
+ print_rest_exception(e, options)
445
+ exit 1
446
+ end
447
+ end
448
+
449
+ def envs(args)
450
+ options = {}
451
+ optparse = OptionParser.new do|opts|
452
+ opts.banner = subcommand_usage("[name]")
453
+ build_common_options(opts, options, [:json, :dry_run, :remote])
454
+ end
455
+ optparse.parse!(args)
456
+ if args.count < 1
457
+ puts optparse
458
+ exit 1
459
+ end
460
+ connect(options)
461
+ begin
462
+ instance = find_instance_by_name_or_id(args[0])
463
+ if options[:dry_run]
464
+ print_dry_run @instances_interface.dry.get_envs(instance['id'])
465
+ return
466
+ end
467
+ json_response = @instances_interface.get_envs(instance['id'])
468
+ if options[:json]
469
+ print JSON.pretty_generate(json_response), "\n"
470
+ return
471
+ end
472
+ print "\n" ,cyan, bold, "#{instance['name']} (#{instance['instanceType']['name']})\n","==================", "\n\n", reset, cyan
473
+ envs = json_response['envs'] || {}
474
+ if json_response['readOnlyEnvs']
475
+ envs += json_response['readOnlyEnvs'].map { |k,v| {:name => k, :value => k.downcase.include?("password") || v['masked'] ? "********" : v['value'], :export => true}}
476
+ end
477
+ tp envs, :name, :value, :export
478
+ print "\n" ,cyan, bold, "Imported Envs\n","==================", "\n\n", reset, cyan
479
+ imported_envs = json_response['importedEnvs'].map { |k,v| {:name => k, :value => k.downcase.include?("password") || v['masked'] ? "********" : v['value']}}
480
+ tp imported_envs
481
+ print reset, "\n"
482
+ rescue RestClient::Exception => e
483
+ print_rest_exception(e, options)
484
+ exit 1
485
+ end
486
+ end
487
+
488
+ def setenv(args)
489
+ options = {}
490
+
491
+ optparse = OptionParser.new do|opts|
492
+ opts.banner = subcommand_usage("[name] VAR VALUE [-e]")
493
+ opts.on( '-e', "Exportable" ) do |exportable|
494
+ options[:export] = exportable
495
+ end
496
+ opts.on( '-M', "Masked" ) do |masked|
497
+ options[:masked] = masked
498
+ end
499
+ build_common_options(opts, options, [:json, :dry_run, :remote, :quiet])
500
+ end
501
+ optparse.parse!(args)
502
+ if args.count < 3
503
+ puts optparse
504
+ exit 1
505
+ end
506
+ connect(options)
507
+ begin
508
+ instance = find_instance_by_name_or_id(args[0])
509
+ evar = {name: args[1], value: args[2], export: options[:export], masked: options[:masked]}
510
+ payload = {envs: [evar]}
511
+ if options[:dry_run]
512
+ print_dry_run @instances_interface.dry.create_env(instance['id'], payload)
513
+ return
514
+ end
515
+ json_response = @instances_interface.create_env(instance['id'], payload)
516
+ if options[:json]
517
+ print JSON.pretty_generate(json_response), "\n"
518
+ return
519
+ end
520
+ if !options[:quiet]
521
+ envs([args[0]])
522
+ end
523
+ rescue RestClient::Exception => e
524
+ print_rest_exception(e, options)
525
+ exit 1
526
+ end
527
+ end
528
+
529
+ def delenv(args)
530
+ options = {}
531
+ optparse = OptionParser.new do|opts|
532
+ opts.banner = subcommand_usage("[name] VAR")
533
+ build_common_options(opts, options, [:json, :dry_run, :remote])
534
+ end
535
+ optparse.parse!(args)
536
+ if args.count < 2
537
+ puts optparse
538
+ exit 1
539
+ end
540
+ connect(options)
541
+ begin
542
+ instance = find_instance_by_name_or_id(args[0])
543
+ if options[:dry_run]
544
+ print_dry_run @instances_interface.dry.del_env(instance['id'], args[1])
545
+ return
546
+ end
547
+ json_response = @instances_interface.del_env(instance['id'], args[1])
548
+ if options[:json]
549
+ print JSON.pretty_generate(json_response), "\n"
550
+ return
551
+ end
552
+ if !options[:quiet]
553
+ envs([args[0]])
554
+ end
555
+ rescue RestClient::Exception => e
556
+ print_rest_exception(e, options)
557
+ exit 1
558
+ end
559
+ end
560
+
561
+ def stop(args)
562
+ options = {}
563
+ optparse = OptionParser.new do|opts|
564
+ opts.banner = subcommand_usage("[name]")
565
+ build_common_options(opts, options, [:auto_confirm, :json, :dry_run, :remote])
566
+ end
567
+ optparse.parse!(args)
568
+ if args.count < 1
569
+ puts optparse
570
+ exit 1
571
+ end
572
+ connect(options)
573
+ begin
574
+ instance = find_instance_by_name_or_id(args[0])
575
+ unless options[:yes] || ::Morpheus::Cli::OptionTypes::confirm("Are you sure you would like to stop this instance?", options)
576
+ exit 1
577
+ end
578
+ if options[:dry_run]
579
+ print_dry_run @instances_interface.dry.stop(instance['id'])
580
+ return
581
+ end
582
+ json_response = @instances_interface.stop(instance['id'])
583
+ if options[:json]
584
+ print JSON.pretty_generate(json_response)
585
+ print "\n"
586
+ end
587
+ return
588
+ rescue RestClient::Exception => e
589
+ print_rest_exception(e, options)
590
+ exit 1
591
+ end
592
+ end
593
+
594
+ def start(args)
595
+ options = {}
596
+ optparse = OptionParser.new do|opts|
597
+ opts.banner = subcommand_usage("[name]")
598
+ build_common_options(opts, options, [:json, :dry_run, :remote])
599
+ end
600
+ optparse.parse!(args)
601
+ if args.count < 1
602
+ puts optparse
603
+ exit 1
604
+ end
605
+ connect(options)
606
+ begin
607
+ instance = find_instance_by_name_or_id(args[0])
608
+ if options[:dry_run]
609
+ print_dry_run @instances_interface.dry.start(instance['id'])
610
+ return
611
+ end
612
+ json_response = @instances_interface.start(instance['id'])
613
+ if options[:json]
614
+ print JSON.pretty_generate(json_response)
615
+ print "\n"
616
+ end
617
+ return
618
+ rescue RestClient::Exception => e
619
+ print_rest_exception(e, options)
620
+ exit 1
621
+ end
622
+ end
1059
623
 
624
+ def restart(args)
625
+ options = {}
626
+ optparse = OptionParser.new do|opts|
627
+ opts.banner = subcommand_usage("[name]")
628
+ build_common_options(opts, options, [:auto_confirm, :json, :dry_run, :remote])
629
+ end
630
+ optparse.parse!(args)
631
+ if args.count < 1
632
+ puts optparse
633
+ exit 1
634
+ end
635
+ connect(options)
636
+ begin
637
+ instance = find_instance_by_name_or_id(args[0])
638
+ unless options[:yes] || ::Morpheus::Cli::OptionTypes::confirm("Are you sure you would like to restart this instance?", options)
639
+ exit 1
640
+ end
641
+ if options[:dry_run]
642
+ print_dry_run @instances_interface.dry.restart(instance['id'])
643
+ return
644
+ end
645
+ json_response = @instances_interface.restart(instance['id'])
646
+ if options[:json]
647
+ print JSON.pretty_generate(json_response)
648
+ print "\n"
649
+ end
650
+ return
651
+ rescue RestClient::Exception => e
652
+ print_rest_exception(e, options)
653
+ exit 1
654
+ end
655
+ end
656
+
657
+ def suspend(args)
658
+ options = {}
659
+ optparse = OptionParser.new do|opts|
660
+ opts.banner = subcommand_usage("[name]")
661
+ build_common_options(opts, options, [:auto_confirm, :json, :dry_run, :remote])
662
+ end
663
+ optparse.parse!(args)
664
+ if args.count < 1
665
+ puts optparse
666
+ exit 1
667
+ end
668
+ connect(options)
669
+ begin
670
+ instance = find_instance_by_name_or_id(args[0])
671
+ unless options[:yes] || ::Morpheus::Cli::OptionTypes::confirm("Are you sure you would like to suspend this instance?", options)
672
+ exit 1
673
+ end
674
+ if options[:dry_run]
675
+ print_dry_run @instances_interface.dry.suspend(instance['id'])
676
+ return
677
+ end
678
+ json_response = @instances_interface.suspend(instance['id'])
679
+ if options[:json]
680
+ print JSON.pretty_generate(json_response)
681
+ print "\n"
682
+ end
683
+ return
684
+ rescue RestClient::Exception => e
685
+ print_rest_exception(e, options)
686
+ exit 1
687
+ end
688
+ end
689
+
690
+ def eject(args)
691
+ options = {}
692
+ optparse = OptionParser.new do|opts|
693
+ opts.banner = subcommand_usage("restart [name]")
694
+ build_common_options(opts, options, [:auto_confirm, :json, :dry_run, :remote])
695
+ end
696
+ optparse.parse!(args)
697
+ if args.count < 1
698
+ puts optparse
699
+ exit 1
700
+ end
701
+ connect(options)
702
+ begin
703
+ instance = find_instance_by_name_or_id(args[0])
704
+ unless options[:yes] || ::Morpheus::Cli::OptionTypes::confirm("Are you sure you would like to eject this instance?", options)
705
+ exit 1
706
+ end
707
+ if options[:dry_run]
708
+ print_dry_run @instances_interface.dry.eject(instance['id'])
709
+ return
710
+ end
711
+ json_response = @instances_interface.eject(instance['id'])
712
+ if options[:json]
713
+ print JSON.pretty_generate(json_response)
714
+ print "\n"
715
+ end
716
+ return
717
+ rescue RestClient::Exception => e
718
+ print_rest_exception(e, options)
719
+ exit 1
720
+ end
721
+ end
722
+
723
+ def stop_service(args)
724
+ options = {}
725
+ optparse = OptionParser.new do|opts|
726
+ opts.banner = subcommand_usage("[name]")
727
+ build_common_options(opts, options, [:auto_confirm, :json, :dry_run, :remote])
728
+ end
729
+ optparse.parse!(args)
730
+ if args.count < 1
731
+ puts optparse
732
+ exit 1
733
+ end
734
+ connect(options)
735
+ begin
736
+ instance = find_instance_by_name_or_id(args[0])
737
+ unless options[:yes] || ::Morpheus::Cli::OptionTypes::confirm("Are you sure you would like to stop this instance?", options)
738
+ exit 1
739
+ end
740
+ if options[:dry_run]
741
+ print_dry_run @instances_interface.dry.stop(instance['id'],false)
742
+ return
743
+ end
744
+ json_response = @instances_interface.stop(instance['id'],false)
745
+ if options[:json]
746
+ print JSON.pretty_generate(json_response)
747
+ print "\n"
748
+ else
749
+ puts "Stopping service on #{args[0]}"
750
+ end
751
+ return
752
+ rescue RestClient::Exception => e
753
+ print_rest_exception(e, options)
754
+ exit 1
755
+ end
756
+ end
757
+
758
+ def start_service(args)
759
+ options = {}
760
+ optparse = OptionParser.new do|opts|
761
+ opts.banner = subcommand_usage("[name]")
762
+ build_common_options(opts, options, [:json, :dry_run, :remote])
763
+ end
764
+ optparse.parse!(args)
765
+ if args.count < 1
766
+ puts optparse
767
+ exit 1
768
+ end
769
+ connect(options)
770
+ begin
771
+ instance = find_instance_by_name_or_id(args[0])
772
+ if options[:dry_run]
773
+ print_dry_run @instances_interface.dry.start(instance['id'], false)
774
+ return
775
+ end
776
+ json_response = @instances_interface.start(instance['id'],false)
777
+ if options[:json]
778
+ print JSON.pretty_generate(json_response)
779
+ print "\n"
780
+ else
781
+ puts "Starting service on #{args[0]}"
782
+ end
783
+ return
784
+ rescue RestClient::Exception => e
785
+ print_rest_exception(e, options)
786
+ exit 1
787
+ end
788
+ end
789
+
790
+ def restart_service(args)
791
+ options = {}
792
+ optparse = OptionParser.new do|opts|
793
+ opts.banner = subcommand_usage("[name]")
794
+ build_common_options(opts, options, [:auto_confirm, :json, :dry_run, :remote])
795
+ end
796
+ optparse.parse!(args)
797
+ if args.count < 1
798
+ puts optparse
799
+ exit 1
800
+ end
801
+ connect(options)
802
+ begin
803
+ instance = find_instance_by_name_or_id(args[0])
804
+ unless options[:yes] || ::Morpheus::Cli::OptionTypes::confirm("Are you sure you would like to restart this instance?", options)
805
+ exit 1
806
+ end
807
+ if options[:dry_run]
808
+ print_dry_run @instances_interface.dry.restart(instance['id'],false)
809
+ return
810
+ end
811
+ json_response = @instances_interface.restart(instance['id'],false)
812
+ if options[:json]
813
+ print JSON.pretty_generate(json_response)
814
+ print "\n"
815
+ else
816
+ puts "Restarting service on instance #{args[0]}"
817
+ end
818
+ return
819
+ rescue RestClient::Exception => e
820
+ print_rest_exception(e, options)
821
+ exit 1
822
+ end
823
+ end
824
+
825
+ def resize(args)
826
+ options = {}
827
+ optparse = OptionParser.new do|opts|
828
+ opts.banner = subcommand_usage("[name]")
829
+ build_common_options(opts, options, [:options, :json, :dry_run, :remote])
830
+ end
831
+ optparse.parse!(args)
832
+ if args.count < 1
833
+ puts optparse
834
+ exit 1
835
+ end
836
+ connect(options)
837
+ begin
838
+ instance = find_instance_by_name_or_id(args[0])
839
+
840
+ group_id = instance['group']['id']
841
+ cloud_id = instance['cloud']['id']
842
+ layout_id = instance['layout']['id']
843
+
844
+ plan_id = instance['plan']['id']
845
+ payload = {
846
+ :instance => {:id => instance["id"]}
847
+ }
848
+
849
+ # avoid 500 error
850
+ # payload[:servicePlanOptions] = {}
851
+
852
+ puts "\nDue to limitations by most Guest Operating Systems, Disk sizes can only be expanded and not reduced.\nIf a smaller plan is selected, memory and CPU (if relevant) will be reduced but storage will not.\n\n"
853
+
854
+ # prompt for service plan
855
+ service_plans_json = @instances_interface.service_plans({zoneId: cloud_id, layoutId: layout_id})
856
+ service_plans = service_plans_json["plans"]
857
+ service_plans_dropdown = service_plans.collect {|sp| {'name' => sp["name"], 'value' => sp["id"]} } # already sorted
858
+ service_plans_dropdown.each do |plan|
859
+ if plan['value'] && plan['value'].to_i == plan_id.to_i
860
+ plan['name'] = "#{plan['name']} (current)"
861
+ end
862
+ end
863
+ plan_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'servicePlan', 'type' => 'select', 'fieldLabel' => 'Plan', 'selectOptions' => service_plans_dropdown, 'required' => true, 'description' => 'Choose the appropriately sized plan for this instance'}],options[:options])
864
+ service_plan = service_plans.find {|sp| sp["id"] == plan_prompt['servicePlan'].to_i }
865
+ new_plan_id = service_plan["id"]
866
+ #payload[:servicePlan] = new_plan_id # ew, this api uses servicePlanId instead
867
+ #payload[:servicePlanId] = new_plan_id
868
+ payload[:instance][:plan] = {id: service_plan["id"]}
869
+
870
+ volumes_response = @instances_interface.volumes(instance['id'])
871
+ current_volumes = volumes_response['volumes'].sort {|x,y| x['displayOrder'] <=> y['displayOrder'] }
872
+
873
+ # prompt for volumes
874
+ volumes = prompt_resize_volumes(current_volumes, service_plan, options)
875
+ if !volumes.empty?
876
+ payload[:volumes] = volumes
877
+ end
878
+
879
+ # only amazon supports this option
880
+ # for now, always do this
881
+ payload[:deleteOriginalVolumes] = true
882
+
883
+ if options[:dry_run]
884
+ print_dry_run @instances_interface.dry.resize(instance['id'], payload)
885
+ return
886
+ end
887
+ json_response = @instances_interface.resize(instance['id'], payload)
888
+ if options[:json]
889
+ print JSON.pretty_generate(json_response)
890
+ print "\n"
891
+ else
892
+ print_green_success "Resizing instance #{instance['name']}"
893
+ list([])
894
+ end
895
+ rescue RestClient::Exception => e
896
+ print_rest_exception(e, options)
897
+ exit 1
898
+ end
899
+ end
900
+
901
+ def backup(args)
902
+ options = {}
903
+ optparse = OptionParser.new do|opts|
904
+ opts.banner = subcommand_usage("[name]")
905
+ build_common_options(opts, options, [:auto_confirm, :json, :dry_run, :remote])
906
+ end
907
+ if args.count < 1
908
+ puts optparse
909
+ exit 1
910
+ end
911
+ optparse.parse!(args)
912
+ connect(options)
913
+ begin
914
+ instance = find_instance_by_name_or_id(args[0])
915
+ unless options[:yes] || ::Morpheus::Cli::OptionTypes::confirm("Are you sure you would like to backup the instance '#{instance['name']}'?", options)
916
+ exit 1
917
+ end
918
+ if options[:dry_run]
919
+ print_dry_run @instances_interface.dry.backup(instance['id'])
920
+ return
921
+ end
922
+ json_response = @instances_interface.backup(instance['id'])
923
+ if options[:json]
924
+ print JSON.pretty_generate(json_response)
925
+ print "\n"
926
+ else
927
+ puts "Backup initiated."
928
+ end
929
+ return
930
+ rescue RestClient::Exception => e
931
+ print_rest_exception(e, options)
932
+ exit 1
933
+ end
934
+ end
935
+
936
+ def list(args)
937
+ options = {}
938
+ optparse = OptionParser.new do|opts|
939
+ opts.banner = subcommand_usage()
940
+ opts.on( '-g', '--group GROUP', "Group Name or ID" ) do |val|
941
+ options[:group] = val
942
+ end
943
+ opts.on( '-c', '--cloud CLOUD', "Cloud Name or ID" ) do |val|
944
+ options[:cloud] = val
945
+ end
946
+ build_common_options(opts, options, [:list, :json, :dry_run, :remote])
947
+ end
948
+ optparse.parse!(args)
949
+ connect(options)
950
+ begin
951
+ params = {}
952
+ group = options[:group] ? find_group_by_name_or_id_for_provisioning(options[:group]) : nil
953
+ if group
954
+ params['siteId'] = group['id']
955
+ end
956
+
957
+ # argh, this doesn't work because group_id is required for options/clouds
958
+ # cloud = options[:cloud] ? find_cloud_by_name_or_id_for_provisioning(group_id, options[:cloud]) : nil
959
+ cloud = options[:cloud] ? find_zone_by_name_or_id(nil, options[:cloud]) : nil
960
+ if cloud
961
+ params['zoneId'] = cloud['id']
962
+ end
963
+
964
+ [:phrase, :offset, :max, :sort, :direction].each do |k|
965
+ params[k] = options[k] unless options[k].nil?
966
+ end
967
+
968
+ if options[:dry_run]
969
+ print_dry_run @instances_interface.dry.list(params)
970
+ return
971
+ end
972
+ json_response = @instances_interface.get(params)
973
+ if options[:json]
974
+ print JSON.pretty_generate(json_response)
975
+ print "\n"
976
+ else
977
+ instances = json_response['instances']
978
+
979
+ title = "Morpheus Instances"
980
+ subtitles = []
981
+ if group
982
+ subtitles << "Group: #{group['name']}".strip
983
+ end
984
+ if cloud
985
+ subtitles << "Cloud: #{cloud['name']}".strip
986
+ end
987
+ if params[:phrase]
988
+ subtitles << "Search: #{params[:phrase]}".strip
989
+ end
990
+ subtitle = subtitles.join(', ')
991
+ print "\n" ,cyan, bold, title, (subtitle.empty? ? "" : " - #{subtitle}"), "\n", "==================", reset, "\n\n"
992
+ if instances.empty?
993
+ puts yellow,"No instances found.",reset
994
+ else
995
+ print_instances_table(instances)
996
+ print_results_pagination(json_response)
997
+ end
998
+ print reset,"\n"
999
+ end
1000
+ rescue RestClient::Exception => e
1001
+ print_rest_exception(e, options)
1002
+ exit 1
1003
+ end
1004
+ end
1005
+
1006
+ def remove(args)
1007
+ options = {}
1008
+ query_params = {keepBackups: 'off', force: 'off'}
1009
+ optparse = OptionParser.new do|opts|
1010
+ opts.banner = subcommand_usage("[name] [-fB]")
1011
+ opts.on( '-f', '--force', "Force Remove" ) do
1012
+ query_params[:force] = 'on'
1013
+ end
1014
+ opts.on( '-B', '--keep-backups', "Preserve copy of backups" ) do
1015
+ query_params[:keepBackups] = 'on'
1016
+ end
1017
+ build_common_options(opts, options, [:auto_confirm, :json, :dry_run, :quiet, :remote])
1018
+
1019
+ end
1020
+ if args.count < 1
1021
+ puts "\n#{optparse}\n\n"
1022
+ exit 1
1023
+ end
1024
+ optparse.parse!(args)
1025
+ connect(options)
1026
+ begin
1027
+ instance = find_instance_by_name_or_id(args[0])
1028
+ unless options[:yes] || ::Morpheus::Cli::OptionTypes::confirm("Are you sure you would like to remove the instance '#{instance['name']}'?", options)
1029
+ exit 1
1030
+ end
1031
+ if options[:dry_run]
1032
+ print_dry_run @instances_interface.dry.destroy(instance['id'],query_params)
1033
+ return
1034
+ end
1035
+ json_response = @instances_interface.destroy(instance['id'],query_params)
1036
+ if options[:json]
1037
+ print JSON.pretty_generate(json_response)
1038
+ print "\n"
1039
+ elsif !options[:quiet]
1040
+ list([])
1041
+ end
1042
+ rescue RestClient::Exception => e
1043
+ print_rest_exception(e, options)
1044
+ exit 1
1045
+ end
1046
+ end
1047
+
1048
+ def firewall_disable(args)
1049
+ options = {}
1050
+ optparse = OptionParser.new do|opts|
1051
+ opts.banner = subcommand_usage("[name]")
1052
+ build_common_options(opts, options, [:json, :dry_run, :quiet, :remote])
1053
+ end
1054
+ if args.count < 1
1055
+ puts optparse
1056
+ exit 1
1057
+ end
1058
+ optparse.parse!(args)
1059
+ connect(options)
1060
+ begin
1061
+ instance = find_instance_by_name_or_id(args[0])
1062
+ if options[:dry_run]
1063
+ print_dry_run @instances_interface.dry.firewall_disable(instance['id'])
1064
+ return
1065
+ end
1066
+ json_response = @instances_interface.firewall_disable(instance['id'])
1067
+ if options[:json]
1068
+ print JSON.pretty_generate(json_response)
1069
+ print "\n"
1070
+ elsif !options[:quiet]
1071
+ security_groups([args[0]])
1072
+ end
1073
+ rescue RestClient::Exception => e
1074
+ print_rest_exception(e, options)
1075
+ exit 1
1076
+ end
1077
+ end
1078
+
1079
+ def firewall_enable(args)
1080
+ options = {}
1081
+ optparse = OptionParser.new do|opts|
1082
+ opts.banner = subcommand_usage("[name]")
1083
+ build_common_options(opts, options, [:json, :dry_run, :quiet, :remote])
1084
+ end
1085
+ if args.count < 1
1086
+ puts optparse
1087
+ exit 1
1088
+ end
1089
+ optparse.parse!(args)
1090
+ connect(options)
1091
+ begin
1092
+ instance = find_instance_by_name_or_id(args[0])
1093
+ if options[:dry_run]
1094
+ print_dry_run @instances_interface.dry.firewall_enable(instance['id'])
1095
+ return
1096
+ end
1097
+ json_response = @instances_interface.firewall_enable(instance['id'])
1098
+ if options[:json]
1099
+ print JSON.pretty_generate(json_response)
1100
+ print "\n"
1101
+ elsif !options[:quiet]
1102
+ security_groups([args[0]])
1103
+ end
1104
+ rescue RestClient::Exception => e
1105
+ print_rest_exception(e, options)
1106
+ exit 1
1107
+ end
1108
+ end
1109
+
1110
+ def security_groups(args)
1111
+ options = {}
1112
+ optparse = OptionParser.new do|opts|
1113
+ opts.banner = subcommand_usage("[name]")
1114
+ build_common_options(opts, options, [:json, :dry_run, :remote])
1115
+ end
1116
+ if args.count < 1
1117
+ puts optparse
1118
+ exit 1
1119
+ end
1120
+ optparse.parse!(args)
1121
+ connect(options)
1122
+ begin
1123
+ instance = find_instance_by_name_or_id(args[0])
1124
+ if options[:dry_run]
1125
+ print_dry_run @instances_interface.dry.security_groups(instance['id'])
1126
+ return
1127
+ end
1128
+ json_response = @instances_interface.security_groups(instance['id'])
1129
+ if options[:json]
1130
+ print JSON.pretty_generate(json_response)
1131
+ print "\n"
1132
+ return
1133
+ end
1134
+ securityGroups = json_response['securityGroups']
1135
+ print "\n" ,cyan, bold, "Morpheus Security Groups for Instance: #{instance['name']}\n","==================", reset, "\n\n"
1136
+ print cyan, "Firewall Enabled=#{json_response['firewallEnabled']}\n\n"
1137
+ if securityGroups.empty?
1138
+ puts yellow,"No security groups currently applied.",reset
1139
+ else
1140
+ securityGroups.each do |securityGroup|
1141
+ print cyan, "= #{securityGroup['id']} (#{securityGroup['name']}) - (#{securityGroup['description']})\n"
1142
+ end
1143
+ end
1144
+ print reset,"\n"
1145
+
1146
+ rescue RestClient::Exception => e
1147
+ print_rest_exception(e, options)
1148
+ exit 1
1149
+ end
1150
+ end
1151
+
1152
+ def apply_security_groups(args)
1153
+ options = {}
1154
+ security_group_ids = nil
1155
+ clear_or_secgroups_specified = false
1156
+ optparse = OptionParser.new do|opts|
1157
+ opts.banner = subcommand_usage("[name] [-S] [-c]")
1158
+ opts.on( '-S', '--secgroups SECGROUPS', "Apply the specified comma separated security group ids" ) do |secgroups|
1159
+ security_group_ids = secgroups.split(",")
1160
+ clear_or_secgroups_specified = true
1161
+ end
1162
+ opts.on( '-c', '--clear', "Clear all security groups" ) do
1163
+ security_group_ids = []
1164
+ clear_or_secgroups_specified = true
1165
+ end
1166
+ build_common_options(opts, options, [:json, :dry_run, :quiet, :remote])
1167
+ end
1168
+ optparse.parse!(args)
1169
+ if args.count < 1
1170
+ puts optparse
1171
+ exit 1
1172
+ end
1173
+ if !clear_or_secgroups_specified
1174
+ puts optparse
1175
+ exit
1176
+ end
1177
+ connect(options)
1178
+ begin
1179
+ instance = find_instance_by_name_or_id(args[0])
1180
+ payload = {securityGroupIds: security_group_ids}
1181
+ if options[:dry_run]
1182
+ print_dry_run @instances_interface.dry.apply_security_groups(instance['id'], payload)
1183
+ return
1184
+ end
1185
+ json_response = @instances_interface.apply_security_groups(instance['id'], payload)
1186
+ if options[:json]
1187
+ print JSON.pretty_generate(json_response)
1188
+ print "\n"
1189
+ return
1190
+ end
1191
+ if !options[:quiet]
1192
+ security_groups([args[0]])
1193
+ end
1194
+ rescue RestClient::Exception => e
1195
+ print_rest_exception(e, options)
1196
+ exit 1
1197
+ end
1198
+ end
1199
+
1200
+
1201
+ def run_workflow(args)
1202
+ options = {}
1203
+ optparse = OptionParser.new do|opts|
1204
+ opts.banner = subcommand_usage("[name] [workflow] [options]")
1205
+ build_common_options(opts, options, [:options, :json, :dry_run, :remote])
1206
+ end
1207
+ if args.count < 2
1208
+ puts "\n#{optparse}\n\n"
1209
+ exit 1
1210
+ end
1211
+ optparse.parse!(args)
1212
+ connect(options)
1213
+ instance = find_instance_by_name_or_id(args[0])
1214
+ workflow = find_workflow_by_name(args[1])
1215
+ task_types = @tasks_interface.task_types()
1216
+ editable_options = []
1217
+ workflow['taskSetTasks'].sort{|a,b| a['taskOrder'] <=> b['taskOrder']}.each do |task_set_task|
1218
+ task_type_id = task_set_task['task']['taskType']['id']
1219
+ task_type = task_types['taskTypes'].find{ |current_task_type| current_task_type['id'] == task_type_id}
1220
+ task_opts = task_type['optionTypes'].select { |otype| otype['editable']}
1221
+ if !task_opts.nil? && !task_opts.empty?
1222
+ editable_options += task_opts.collect do |task_opt|
1223
+ new_task_opt = task_opt.clone
1224
+ new_task_opt['fieldContext'] = "#{task_set_task['id']}.#{new_task_opt['fieldContext']}"
1225
+ end
1226
+ end
1227
+ end
1228
+ params = options[:options] || {}
1229
+
1230
+ if params.empty? && !editable_options.empty?
1231
+ puts optparse
1232
+ option_lines = editable_options.collect {|it| "\t-O #{it['fieldContext'] ? (it['fieldContext'] + '.') : ''}#{it['fieldName']}=\"value\"" }.join("\n")
1233
+ puts "\nAvailable Options:\n#{option_lines}\n\n"
1234
+ exit 1
1235
+ end
1236
+
1237
+ workflow_payload = {taskSet: {"#{workflow['id']}" => params }}
1238
+ begin
1239
+ if options[:dry_run]
1240
+ print_dry_run @instances_interface.dry.workflow(instance['id'],workflow['id'], workflow_payload)
1241
+ return
1242
+ end
1243
+ json_response = @instances_interface.workflow(instance['id'],workflow['id'], workflow_payload)
1244
+ if options[:json]
1245
+ print JSON.pretty_generate(json_response)
1246
+ print "\n"
1247
+ else
1248
+ puts "Running workflow..."
1249
+ end
1250
+ rescue RestClient::Exception => e
1251
+ print_rest_exception(e, options)
1252
+ exit 1
1253
+ end
1254
+ end
1255
+
1256
+ def import_snapshot(args)
1257
+ options = {}
1258
+ storage_provider_id = nil
1259
+ optparse = OptionParser.new do|opts|
1260
+ opts.banner = subcommand_usage("[name]")
1261
+ opts.on("--storage-provider ID", String, "Optional storage provider") do |val|
1262
+ storage_provider_id = val
1263
+ end
1264
+ build_common_options(opts, options, [:auto_confirm, :json, :dry_run, :remote])
1265
+ end
1266
+ if args.count < 1
1267
+ puts optparse
1268
+ exit 1
1269
+ end
1270
+ optparse.parse!(args)
1271
+ connect(options)
1272
+ begin
1273
+ instance = find_instance_by_name_or_id(args[0])
1274
+ unless options[:yes] || ::Morpheus::Cli::OptionTypes::confirm("Are you sure you would like to import a snapshot of the instance '#{instance['name']}'?", options)
1275
+ exit 1
1276
+ end
1277
+
1278
+ payload = {}
1279
+
1280
+ # Prompt for Storage Provider, use default value.
1281
+ begin
1282
+ options[:options] ||= {}
1283
+ options[:options]['storageProviderId'] = storage_provider_id if storage_provider_id
1284
+ storage_provider_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'storageProviderId', 'type' => 'select', 'fieldLabel' => 'Storage Provider', 'optionSource' => 'storageProviders', 'required' => false, 'description' => 'Select Storage Provider.'}], options[:options], @api_client, {})
1285
+ if !storage_provider_prompt['storageProviderId'].empty?
1286
+ payload['storageProviderId'] = storage_provider_prompt['storageProviderId']
1287
+ end
1288
+ rescue RestClient::Exception => e
1289
+ puts "Failed to load storage providers"
1290
+ #print_rest_exception(e, options)
1291
+ exit 1
1292
+ end
1293
+
1294
+ if options[:dry_run]
1295
+ print_dry_run @instances_interface.dry.import_snapshot(instance['id'], payload)
1296
+ return
1297
+ end
1298
+ json_response = @instances_interface.import_snapshot(instance['id'], payload)
1299
+ if options[:json]
1300
+ print JSON.pretty_generate(json_response)
1301
+ print "\n"
1302
+ else
1303
+ puts "Snapshot import initiated."
1304
+ end
1305
+ return
1306
+ rescue RestClient::Exception => e
1307
+ print_rest_exception(e, options)
1308
+ exit 1
1309
+ end
1310
+ end
1311
+
1312
+ # check the instance
1313
+ def check_status
1314
+ end
1315
+
1316
+ private
1317
+ def find_zone_by_name_or_id(group_id, val)
1318
+ zone = nil
1319
+ if val.to_s =~ /\A\d{1,}\Z/
1320
+ json_results = @clouds_interface.get(val.to_i)
1321
+ zone = json_results['zone']
1322
+ if zone.nil?
1323
+ print_red_alert "Cloud not found by id #{val}"
1324
+ exit 1
1325
+ end
1326
+ else
1327
+ json_results = @clouds_interface.get({groupId: group_id, name: val})
1328
+ zone = json_results['zones'] ? json_results['zones'][0] : nil
1329
+ if zone.nil?
1330
+ print_red_alert "Cloud not found by name #{val}"
1331
+ exit 1
1332
+ end
1333
+ end
1334
+ return zone
1335
+ end
1336
+
1337
+ def find_workflow_by_name(name)
1338
+ task_set_results = @task_sets_interface.get(name)
1339
+ if !task_set_results['taskSets'].nil? && !task_set_results['taskSets'].empty?
1340
+ return task_set_results['taskSets'][0]
1341
+ else
1342
+ print_red_alert "Workflow not found by name #{name}"
1343
+ exit 1
1344
+ end
1345
+ end
1346
+
1347
+ def print_instances_table(instances, opts={})
1348
+ table_color = opts[:color] || cyan
1349
+ rows = instances.collect do |instance|
1350
+ connection_string = ''
1351
+ if !instance['connectionInfo'].nil? && instance['connectionInfo'].empty? == false
1352
+ connection_string = "#{instance['connectionInfo'][0]['ip']}:#{instance['connectionInfo'][0]['port']}"
1353
+ end
1354
+ {
1355
+ id: instance['id'],
1356
+ name: instance['name'],
1357
+ connection: connection_string,
1358
+ environment: instance['instanceContext'],
1359
+ nodes: instance['containers'].count,
1360
+ status: format_instance_status(instance, table_color),
1361
+ type: instance['instanceType']['name'],
1362
+ group: !instance['group'].nil? ? instance['group']['name'] : nil,
1363
+ cloud: !instance['cloud'].nil? ? instance['cloud']['name'] : nil
1364
+ }
1365
+ end
1366
+
1367
+ print table_color
1368
+ tp rows, :id, :name, :group, :cloud, :type, :environment, :nodes, :connection, :status
1369
+ print reset
1370
+ end
1371
+
1372
+ def format_instance_status(instance, return_color=cyan)
1373
+ out = ""
1374
+ status_string = instance['status']
1375
+ if status_string == 'running'
1376
+ out << "#{green}#{status_string.upcase}#{return_color}"
1377
+ elsif status_string == 'stopped' or status_string == 'failed'
1378
+ out << "#{red}#{status_string.upcase}#{return_color}"
1379
+ elsif status_string == 'unknown'
1380
+ out << "#{white}#{status_string.upcase}#{return_color}"
1381
+ else
1382
+ out << "#{yellow}#{status_string.upcase}#{return_color}"
1383
+ end
1384
+ out
1385
+ end
1060
1386
  end