morpheus-cli 3.5.2 → 3.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/lib/morpheus/api/api_client.rb +16 -0
  3. data/lib/morpheus/api/blueprints_interface.rb +84 -0
  4. data/lib/morpheus/api/execution_request_interface.rb +33 -0
  5. data/lib/morpheus/api/instances_interface.rb +21 -0
  6. data/lib/morpheus/api/packages_interface.rb +25 -5
  7. data/lib/morpheus/api/processes_interface.rb +34 -0
  8. data/lib/morpheus/api/roles_interface.rb +7 -0
  9. data/lib/morpheus/api/servers_interface.rb +8 -0
  10. data/lib/morpheus/api/user_settings_interface.rb +76 -0
  11. data/lib/morpheus/cli.rb +5 -1
  12. data/lib/morpheus/cli/alias_command.rb +1 -1
  13. data/lib/morpheus/cli/app_templates.rb +2 -1
  14. data/lib/morpheus/cli/apps.rb +173 -19
  15. data/lib/morpheus/cli/blueprints_command.rb +2134 -0
  16. data/lib/morpheus/cli/cli_command.rb +3 -1
  17. data/lib/morpheus/cli/clouds.rb +4 -10
  18. data/lib/morpheus/cli/coloring_command.rb +14 -8
  19. data/lib/morpheus/cli/containers_command.rb +92 -5
  20. data/lib/morpheus/cli/execution_request_command.rb +313 -0
  21. data/lib/morpheus/cli/hosts.rb +188 -7
  22. data/lib/morpheus/cli/instances.rb +472 -9
  23. data/lib/morpheus/cli/login.rb +1 -1
  24. data/lib/morpheus/cli/mixins/print_helper.rb +8 -0
  25. data/lib/morpheus/cli/mixins/processes_helper.rb +134 -0
  26. data/lib/morpheus/cli/option_types.rb +21 -16
  27. data/lib/morpheus/cli/packages_command.rb +469 -17
  28. data/lib/morpheus/cli/processes_command.rb +313 -0
  29. data/lib/morpheus/cli/remote.rb +20 -9
  30. data/lib/morpheus/cli/roles.rb +186 -6
  31. data/lib/morpheus/cli/shell.rb +10 -1
  32. data/lib/morpheus/cli/tasks.rb +4 -1
  33. data/lib/morpheus/cli/user_settings_command.rb +431 -0
  34. data/lib/morpheus/cli/version.rb +1 -1
  35. data/lib/morpheus/cli/whoami.rb +1 -1
  36. data/lib/morpheus/formatters.rb +14 -0
  37. data/lib/morpheus/morpkg.rb +119 -0
  38. data/morpheus-cli.gemspec +1 -0
  39. metadata +26 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e69dc73a61a5113eda7600546cc3930dfdd4f47a9a882cd0aa27bb9af12a5f97
4
- data.tar.gz: 9d47bacf74b477ab1d887f110b055b5cf9d89e0f65fff187b0bf2471a92b8616
3
+ metadata.gz: 23cf1069887e9d9fc379bb4c5d542ffaf746fb045ba394b281f1bcbe2f6979e0
4
+ data.tar.gz: 544bb68d0fc395fa8d6a76391028641e564d37f9f6f82c515d763420e83230bb
5
5
  SHA512:
6
- metadata.gz: 2187ecea61941471a82f73f0f2a86d555ec739d22bfe4bc30b7aa620fca16aa9b6a3372c9cc0adf21868d4283c83b5bd545cb8fc4cc1a253d1e37accb58e01af
7
- data.tar.gz: b39bc39b4b012dabad7c821b55690c1976d92a671abcb660fd57140506c499042b3cf77d80394d0c6e07669e59b3113856f256a5187ac7461929c8fbb4583d19
6
+ metadata.gz: '09147a460130571ad8a3f30e5e7062b290425d11c9dbf30f14ae5dedf4e99cd821b5fde46b6c3f69c1bd4eb3d2c4477a9df2ae5f766164fda7e99173bb9d877f'
7
+ data.tar.gz: 0d0775dd6ff2b7e9e670a295d44b2fe60e68095cc74df2b6cbd75d5dca3e2ea40e9378f5129fdf86bedae1ec9a1d0d667732ea50eaf03caf45d8c31837c0dc7d
@@ -61,6 +61,10 @@ class Morpheus::APIClient
61
61
  Morpheus::WhoamiInterface.new(@access_token, @refresh_token, @expires_at, @base_url)
62
62
  end
63
63
 
64
+ def user_settings
65
+ Morpheus::UserSettingsInterface.new(@access_token, @refresh_token, @expires_at, @base_url)
66
+ end
67
+
64
68
  def options
65
69
  Morpheus::OptionsInterface.new(@access_token, @refresh_token, @expires_at, @base_url)
66
70
  end
@@ -121,6 +125,10 @@ class Morpheus::APIClient
121
125
  Morpheus::AppsInterface.new(@access_token, @refresh_token, @expires_at, @base_url)
122
126
  end
123
127
 
128
+ def blueprints
129
+ Morpheus::BlueprintsInterface.new(@access_token, @refresh_token, @expires_at, @base_url)
130
+ end
131
+
124
132
  def app_templates
125
133
  Morpheus::AppTemplatesInterface.new(@access_token, @refresh_token, @expires_at, @base_url)
126
134
  end
@@ -303,4 +311,12 @@ class Morpheus::APIClient
303
311
  Morpheus::CypherInterface.new(@access_token, @refresh_token, @expires_at, @base_url)
304
312
  end
305
313
 
314
+ def execution_request
315
+ Morpheus::ExecutionRequestInterface.new(@access_token, @refresh_token, @expires_at, @base_url)
316
+ end
317
+
318
+ def processes
319
+ Morpheus::ProcessesInterface.new(@access_token, @refresh_token, @expires_at, @base_url)
320
+ end
321
+
306
322
  end
@@ -0,0 +1,84 @@
1
+ require 'morpheus/api/api_client'
2
+
3
+ class Morpheus::BlueprintsInterface < Morpheus::APIClient
4
+ def initialize(access_token, refresh_token,expires_at = nil, base_url=nil)
5
+ @access_token = access_token
6
+ @refresh_token = refresh_token
7
+ @base_url = base_url
8
+ @expires_at = expires_at
9
+ end
10
+
11
+ def get(id)
12
+ raise "#{self.class}.get() passed a blank id!" if id.to_s == ''
13
+ url = "#{@base_url}/api/blueprints/#{id}"
14
+ headers = { params: {}, authorization: "Bearer #{@access_token}" }
15
+ execute(method: :get, url: url, headers: headers)
16
+ end
17
+
18
+ def list(options={})
19
+ url = "#{@base_url}/api/blueprints"
20
+ headers = { params: {}, authorization: "Bearer #{@access_token}" }
21
+ headers[:params].merge!(options)
22
+ execute(method: :get, url: url, headers: headers)
23
+ end
24
+
25
+ def create(options)
26
+ url = "#{@base_url}/api/blueprints"
27
+ headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
28
+ payload = options
29
+ execute(method: :post, url: url, headers: headers, payload: payload.to_json)
30
+ end
31
+
32
+ def update(id, options)
33
+ url = "#{@base_url}/api/blueprints/#{id}"
34
+ headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
35
+ payload = options
36
+ execute(method: :put, url: url, headers: headers, payload: payload.to_json)
37
+ end
38
+
39
+ def update_permissions(id, options)
40
+ url = "#{@base_url}/api/blueprints/#{id}/update-permissions"
41
+ headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
42
+ payload = options
43
+ execute(method: :post, url: url, headers: headers, payload: payload.to_json)
44
+ end
45
+
46
+ # multipart image upload
47
+ def save_image(id, image_file, params={})
48
+ url = "#{@base_url}/api/blueprints/#{id}/image"
49
+ headers = { :params => params, :authorization => "Bearer #{@access_token}"}
50
+ payload = {}
51
+ payload[:templateImage] = image_file
52
+ payload[:multipart] = true
53
+ execute(method: :post, url: url, headers: headers, payload: payload)
54
+ end
55
+
56
+ def duplicate(id, options)
57
+ url = "#{@base_url}/api/blueprints/#{id}/duplicate"
58
+ headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
59
+ payload = options
60
+ execute(method: :post, url: url, headers: headers, payload: payload.to_json)
61
+ end
62
+
63
+ def destroy(id)
64
+ url = "#{@base_url}/api/blueprints/#{id}"
65
+ headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
66
+ execute(method: :delete, url: url, headers: headers)
67
+ end
68
+
69
+ def list_tiers(options={})
70
+ url = "#{@base_url}/api/blueprints/tiers"
71
+ headers = { params: {}, authorization: "Bearer #{@access_token}" }
72
+ headers[:params].merge!(options)
73
+ execute(method: :get, url: url, headers: headers)
74
+ end
75
+
76
+ # unused, prefer /options/instanceTypes
77
+ # def list_types(options={})
78
+ # url = "#{@base_url}/api/blueprints/types"
79
+ # headers = { params: {}, authorization: "Bearer #{@access_token}" }
80
+ # headers[:params].merge!(options)
81
+ # execute(method: :get, url: url, headers: headers)
82
+ # end
83
+
84
+ end
@@ -0,0 +1,33 @@
1
+ require 'morpheus/api/api_client'
2
+
3
+ class Morpheus::ExecutionRequestInterface < Morpheus::APIClient
4
+ def initialize(access_token, refresh_token, expires_at = nil, base_url=nil)
5
+ @access_token = access_token
6
+ @refresh_token = refresh_token
7
+ @base_url = base_url
8
+ @expires_at = expires_at
9
+ end
10
+
11
+ def get(id, params={})
12
+ raise "#{self.class}.get() passed a blank id!" if id.to_s == ''
13
+ url = "#{@base_url}/api/execution-request/#{id}"
14
+ headers = { :params => params, authorization: "Bearer #{@access_token}"}
15
+ opts = {method: :get, url: url, headers: headers}
16
+ execute(opts)
17
+ end
18
+
19
+ def create(params, payload)
20
+ url = "#{@base_url}/api/execution-request/execute"
21
+ headers = { :params => params, :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json'}
22
+ opts = {method: :post, url: url, headers: headers, payload: payload.to_json}
23
+ execute(opts)
24
+ end
25
+
26
+ def execute_against_lease(id, params, payload)
27
+ url = "#{@base_url}/api/execution-request/#{id}"
28
+ headers = { :params => params, :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json'}
29
+ opts = {method: :put, url: url, headers: headers, payload: payload.to_json}
30
+ execute(opts)
31
+ end
32
+
33
+ end
@@ -262,4 +262,25 @@ class Morpheus::InstancesInterface < Morpheus::APIClient
262
262
  execute(opts)
263
263
  end
264
264
 
265
+ def history(id, params={})
266
+ url = "#{@base_url}/api/instances/#{id}/history"
267
+ headers = { params: params, authorization: "Bearer #{@access_token}" }
268
+ opts = {method: :get, url: url, headers: headers}
269
+ execute(opts)
270
+ end
271
+
272
+ def history_details(id, process_id, params={})
273
+ url = "#{@base_url}/api/instances/#{id}/history/#{process_id}"
274
+ headers = { params: params, authorization: "Bearer #{@access_token}" }
275
+ opts = {method: :get, url: url, headers: headers}
276
+ execute(opts)
277
+ end
278
+
279
+ def history_event_details(id, process_event_id, params={})
280
+ url = "#{@base_url}/api/instances/#{id}/history/events/#{process_event_id}"
281
+ headers = { params: params, authorization: "Bearer #{@access_token}" }
282
+ opts = {method: :get, url: url, headers: headers}
283
+ execute(opts)
284
+ end
285
+
265
286
  end
@@ -32,18 +32,38 @@ class Morpheus::PackagesInterface < Morpheus::APIClient
32
32
  execute(opts)
33
33
  end
34
34
 
35
- def install(payload)
35
+ def info(params={})
36
+ url = "#{@base_url}/api/packages/info"
37
+ headers = { params: {}, authorization: "Bearer #{@access_token}" }
38
+ headers[:params].merge!(params)
39
+ opts = {method: :get, url: url, headers: headers}
40
+ execute(opts)
41
+ end
42
+
43
+ def install(params={}, payload={})
36
44
  url = "#{@base_url}/api/packages/install"
37
- headers = { :params => {}, :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
45
+ headers = { :params => params, :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
38
46
  opts = {method: :post, url: url, headers: headers, payload: payload.to_json}
39
47
  execute(opts)
40
48
  end
41
49
 
42
- def install_file(package_file, params={})
50
+ # def install_file(package_file, params={})
51
+ # url = "#{@base_url}/api/packages/install-file"
52
+ # headers = { :params => params, :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/octet-stream'}
53
+ # payload = package_file
54
+ # execute(method: :post, url: url, headers: headers, payload: payload, timeout: 36000)
55
+ # end
56
+
57
+ def install_file(local_file, params={})
43
58
  url = "#{@base_url}/api/packages/install-file"
44
59
  headers = { :params => params, :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/octet-stream'}
45
- payload = package_file
46
- execute(method: :post, url: url, headers: headers, payload: payload, timeout: 36000)
60
+ if !local_file.kind_of?(File)
61
+ local_file = File.new(local_file, 'rb')
62
+ end
63
+ payload = local_file
64
+ headers['Content-Length'] = local_file.size # File.size(local_file)
65
+ opts = {method: :post, url: url, headers: headers, payload: payload}
66
+ execute(opts)
47
67
  end
48
68
 
49
69
  def update(id, payload)
@@ -0,0 +1,34 @@
1
+ require 'morpheus/api/api_client'
2
+
3
+ class Morpheus::ProcessesInterface < Morpheus::APIClient
4
+ def initialize(access_token, refresh_token,expires_at = nil, base_url=nil)
5
+ @access_token = access_token
6
+ @refresh_token = refresh_token
7
+ @base_url = base_url
8
+ @expires_at = expires_at
9
+ end
10
+
11
+ def list(params={})
12
+ url = "#{@base_url}/api/processes"
13
+ headers = { params: params, authorization: "Bearer #{@access_token}" }
14
+ opts = {method: :get, url: url, headers: headers}
15
+ execute(opts)
16
+ end
17
+
18
+ def get(id, params={})
19
+ raise "#{self.class}.get() passed a blank id!" if id.to_s == ''
20
+ url = "#{@base_url}/api/processes/#{id}"
21
+ headers = { params: params, authorization: "Bearer #{@access_token}" }
22
+ opts = {method: :get, url: url, headers: headers}
23
+ execute(opts)
24
+ end
25
+
26
+ def get_event(id, params={})
27
+ raise "#{self.class}.get() passed a blank id!" if id.to_s == ''
28
+ url = "#{@base_url}/api/processes/events/#{id}"
29
+ headers = { params: params, authorization: "Bearer #{@access_token}" }
30
+ opts = {method: :get, url: url, headers: headers}
31
+ execute(opts)
32
+ end
33
+
34
+ end
@@ -56,6 +56,13 @@ class Morpheus::RolesInterface < Morpheus::APIClient
56
56
  execute(method: :put, url: url, headers: headers, payload: payload.to_json)
57
57
  end
58
58
 
59
+ def update_blueprint(account_id, id, options)
60
+ url = build_url(account_id, id) + "/update-blueprint"
61
+ headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
62
+ payload = options
63
+ execute(method: :put, url: url, headers: headers, payload: payload.to_json)
64
+ end
65
+
59
66
  def update_group(account_id, id, options)
60
67
  url = build_url(account_id, id) + "/update-group"
61
68
  headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
@@ -34,6 +34,14 @@ class Morpheus::ServersInterface < Morpheus::APIClient
34
34
  execute(opts)
35
35
  end
36
36
 
37
+ def update(serverId, options)
38
+ url = "#{@base_url}/api/servers/#{serverId}"
39
+ headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
40
+ payload = options
41
+ opts = {method: :put, url: url, headers: headers, payload: payload.to_json}
42
+ execute(opts)
43
+ end
44
+
37
45
  def stop(serverId,payload = {})
38
46
  url = "#{@base_url}/api/servers/#{serverId}/stop"
39
47
  headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
@@ -0,0 +1,76 @@
1
+ require 'morpheus/api/api_client'
2
+
3
+ class Morpheus::UserSettingsInterface < Morpheus::APIClient
4
+ def initialize(access_token, refresh_token, expires_at = nil, base_url=nil)
5
+ @access_token = access_token
6
+ @refresh_token = refresh_token
7
+ @base_url = base_url
8
+ @expires_at = expires_at
9
+ end
10
+
11
+ def get(params={})
12
+ url = "#{@base_url}/api/user-settings"
13
+ headers = { :params => params, authorization: "Bearer #{@access_token}"}
14
+ opts = {method: :get, url: url, headers: headers}
15
+ execute(opts)
16
+ end
17
+
18
+ def update(params, payload)
19
+ url = "#{@base_url}/api/user-settings"
20
+ headers = { :params => params, :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json'}
21
+ opts = {method: :put, url: url, headers: headers, payload: payload.to_json}
22
+ execute(opts)
23
+ end
24
+
25
+ # NOT json, download file as attachment
26
+ def download_avatar(params, outfile)
27
+ url = "#{@base_url}/api/user-settings/avatar"
28
+ headers = { :params => params, :authorization => "Bearer #{@access_token}"}
29
+ opts = {method: :get, url: url, headers: headers, payload: payload}
30
+ execute(opts)
31
+ end
32
+
33
+ # NOT json, multipart file upload
34
+ def update_avatar(avatar_file, params={})
35
+ url = "#{@base_url}/api/user-settings/avatar"
36
+ headers = { :params => params, :authorization => "Bearer #{@access_token}"}
37
+ payload = {}
38
+ #payload['user'] ||= {}
39
+ #payload['user']['avatar'] = avatar_file
40
+ payload['user.avatar'] = avatar_file
41
+ payload[:multipart] = true
42
+ opts = {method: :post, url: url, headers: headers, payload: payload}
43
+ execute(opts)
44
+ end
45
+
46
+ def remove_avatar(params={})
47
+ url = "#{@base_url}/api/user-settings/avatar"
48
+ headers = { :params => params, :authorization => "Bearer #{@access_token}"}
49
+ # POST empty payload will do
50
+ payload = {}
51
+ opts = {method: :delete, url: url, headers: headers, payload: payload}
52
+ execute(opts)
53
+ end
54
+
55
+ def regenerate_access_token(params, payload={})
56
+ url = "#{@base_url}/api/user-settings/regenerate-access-token"
57
+ headers = { :params => params, :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json'}
58
+ opts = {method: :put, url: url, headers: headers, payload: payload.to_json}
59
+ execute(opts)
60
+ end
61
+
62
+ def clear_access_token(params, payload={})
63
+ url = "#{@base_url}/api/user-settings/clear-access-token"
64
+ headers = { :params => params, :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json'}
65
+ opts = {method: :put, url: url, headers: headers, payload: payload.to_json}
66
+ execute(opts)
67
+ end
68
+
69
+ def available_clients(params={})
70
+ url = "#{@base_url}/api/user-settings/api-clients"
71
+ headers = { :params => params, authorization: "Bearer #{@access_token}"}
72
+ opts = {method: :get, url: url, headers: headers}
73
+ execute(opts)
74
+ end
75
+
76
+ end
@@ -79,6 +79,7 @@ module Morpheus
79
79
  load 'morpheus/cli/login.rb'
80
80
  load 'morpheus/cli/logout.rb'
81
81
  load 'morpheus/cli/whoami.rb'
82
+ load 'morpheus/cli/user_settings_command.rb'
82
83
  load 'morpheus/cli/dashboard_command.rb'
83
84
  load 'morpheus/cli/power_schedules_command.rb'
84
85
  load 'morpheus/cli/execute_schedules_command.rb'
@@ -95,7 +96,8 @@ module Morpheus
95
96
  load 'morpheus/cli/instances.rb'
96
97
  load 'morpheus/cli/containers_command.rb'
97
98
  load 'morpheus/cli/apps.rb'
98
- load 'morpheus/cli/app_templates.rb'
99
+ load 'morpheus/cli/blueprints_command.rb'
100
+ load 'morpheus/cli/app_templates.rb' # deprecated
99
101
  load 'morpheus/cli/deploys.rb'
100
102
  load 'morpheus/cli/license.rb'
101
103
  load 'morpheus/cli/instance_types.rb'
@@ -145,6 +147,8 @@ module Morpheus
145
147
  load 'morpheus/cli/boot_scripts_command.rb'
146
148
  load 'morpheus/cli/archives_command.rb'
147
149
  load 'morpheus/cli/storage_providers_command.rb'
150
+ load 'morpheus/cli/execution_request_command.rb'
151
+ load 'morpheus/cli/processes_command.rb'
148
152
 
149
153
  # nice to have commands
150
154
  load 'morpheus/cli/curl_command.rb'
@@ -255,7 +255,7 @@ class Morpheus::Cli::AliasCommand
255
255
  out << "\n"
256
256
  out << reset
257
257
  my_aliases.each do |it|
258
- out << "\t#{cyan}#{it[:name]}#{reset}='#{it[:command_string]}'"
258
+ out << " #{cyan}#{it[:name]}#{reset}='#{it[:command_string]}'"
259
259
  out << "\n"
260
260
  end
261
261
  out << reset
@@ -5,11 +5,12 @@ require 'morpheus/cli/cli_command'
5
5
  require 'morpheus/cli/option_types'
6
6
  require 'json'
7
7
 
8
+ # deprecated and replaced with blueprints, hidden for now
8
9
  class Morpheus::Cli::AppTemplates
9
10
  include Morpheus::Cli::CliCommand
10
11
  include Morpheus::Cli::ProvisioningHelper
11
12
 
12
- #set_command_name :templates # instead of app-templates
13
+ set_command_hidden
13
14
 
14
15
  register_subcommands :list, :get, :add, :update, :remove
15
16
  register_subcommands :duplicate
@@ -6,12 +6,14 @@ require 'filesize'
6
6
  require 'table_print'
7
7
  require 'morpheus/cli/cli_command'
8
8
  require 'morpheus/cli/mixins/provisioning_helper'
9
+ require 'morpheus/cli/mixins/processes_helper'
9
10
 
10
11
  class Morpheus::Cli::Apps
11
12
  include Morpheus::Cli::CliCommand
12
13
  include Morpheus::Cli::ProvisioningHelper
14
+ include Morpheus::Cli::ProcessesHelper
13
15
 
14
- register_subcommands :list, :get, :add, :update, :remove, :add_instance, :remove_instance, :logs, :firewall_disable, :firewall_enable, :security_groups, :apply_security_groups
16
+ register_subcommands :list, :get, :add, :update, :remove, :add_instance, :remove_instance, :logs, :firewall_disable, :firewall_enable, :security_groups, :apply_security_groups, :history
15
17
  alias_subcommand :details, :get
16
18
  set_default_subcommand :list
17
19
 
@@ -27,6 +29,7 @@ class Morpheus::Cli::Apps
27
29
  @options_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).options
28
30
  @groups_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).groups
29
31
  @logs_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).logs
32
+ @processes_interface = @api_client.processes
30
33
  @active_group_id = Morpheus::Cli::Groups.active_groups[@appliance_name]
31
34
  end
32
35
 
@@ -97,7 +100,7 @@ class Morpheus::Cli::Apps
97
100
  optparse = Morpheus::Cli::OptionParser.new do |opts|
98
101
  opts.banner = subcommand_usage("[name] [options]")
99
102
  build_option_type_options(opts, options, add_app_option_types(false))
100
- # opts.on( '-t', '--template ID', "App Template ID. The app template to use. The default value is 'existing' which means no template, for creating a blank app and adding existing instances." ) do |val|
103
+ # opts.on( '-b', '--blueprint ID', "Blueprint ID. The blueprint to use. The default value is 'existing' which means no blueprint, for creating a blank app and adding existing instances." ) do |val|
101
104
  # options['template'] = val
102
105
  # end
103
106
  # opts.on( '-g', '--group GROUP', "Group Name or ID" ) do |val|
@@ -158,7 +161,7 @@ class Morpheus::Cli::Apps
158
161
  payload = {}
159
162
  params = Morpheus::Cli::OptionTypes.prompt(add_app_option_types, options[:options], @api_client, options[:params])
160
163
  params = params.deep_compact! # remove nulls and blank strings
161
- template_id = params.delete('template')
164
+ template_id = params.delete('blueprint')
162
165
  if template_id.to_s.empty? || template_id == 'existing'
163
166
  # new API parameter
164
167
  payload['templateId'] = 'existing'
@@ -166,9 +169,9 @@ class Morpheus::Cli::Apps
166
169
  payload['id'] = 'existing'
167
170
  payload['templateName'] = 'Existing Instances'
168
171
  else
169
- found_app_template = get_available_app_templates.find {|it| it['id'].to_s == template_id.to_s || it['name'].to_s == template_id.to_s }
172
+ found_app_template = get_available_blueprints.find {|it| it['id'].to_s == template_id.to_s || it['name'].to_s == template_id.to_s }
170
173
  if found_app_template.nil?
171
- print_red_alert "App Template not found by id #{template_id}"
174
+ print_red_alert "Blueprint not found by id #{template_id}"
172
175
  return 1
173
176
  end
174
177
  payload['templateId'] = found_app_template['id']
@@ -218,9 +221,9 @@ class Morpheus::Cli::Apps
218
221
  options = {}
219
222
  optparse = Morpheus::Cli::OptionParser.new do |opts|
220
223
  opts.banner = subcommand_usage("[app]")
221
- opts.on('--refresh-until [status]', String, "Refresh until status is reached. Default status is running.") do |val|
224
+ opts.on('--refresh [status]', String, "Refresh until status is reached. Default status is running.") do |val|
222
225
  if val.to_s.empty?
223
- options[:refresh_until_status] = "running"
226
+ options[:refresh_until_status] = "running,failed"
224
227
  else
225
228
  options[:refresh_until_status] = val.to_s.downcase
226
229
  end
@@ -314,10 +317,13 @@ class Morpheus::Cli::Apps
314
317
  if options[:refresh_interval].nil? || options[:refresh_interval].to_f < 0
315
318
  options[:refresh_interval] = 5
316
319
  end
317
- while app['status'].to_s.downcase != options[:refresh_until_status].to_s.downcase
320
+ statuses = options[:refresh_until_status].to_s.downcase.split(",").collect {|s| s.strip }.select {|s| !s.to_s.empty? }
321
+ if !statuses.include?(app['status'])
318
322
  print cyan
319
- print "Refreshing until status #{options[:refresh_until_status]} ..."
320
- sleep(options[:refresh_interval])
323
+ print "Status is #{app['status'] || 'unknown'}. Refreshing in #{options[:refresh_interval]} seconds"
324
+ #sleep(options[:refresh_interval])
325
+ sleep_with_dots(options[:refresh_interval])
326
+ print "\n"
321
327
  get(args)
322
328
  end
323
329
  end
@@ -865,11 +871,158 @@ class Morpheus::Cli::Apps
865
871
  end
866
872
  end
867
873
 
874
+ def history(args)
875
+ raw_args = args.dup
876
+ options = {}
877
+ #options[:show_output] = true
878
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
879
+ opts.banner = subcommand_usage("[app]")
880
+ # opts.on( '-n', '--node NODE_ID', "Scope history to specific Container or VM" ) do |node_id|
881
+ # options[:node_id] = node_id.to_i
882
+ # end
883
+ opts.on( nil, '--events', "Display sub processes (events)." ) do
884
+ options[:show_events] = true
885
+ end
886
+ opts.on( nil, '--output', "Display process output." ) do
887
+ options[:show_output] = true
888
+ end
889
+ build_common_options(opts, options, [:list, :query, :json, :yaml, :csv, :fields, :dry_run, :remote])
890
+ opts.footer = "List historical processes for a specific app.\n" +
891
+ "[app] is required. This is the name or id of an app."
892
+ end
893
+ optparse.parse!(args)
894
+
895
+ if args.count != 1
896
+ puts optparse
897
+ return 1
898
+ end
899
+ connect(options)
900
+ begin
901
+ app = find_app_by_name_or_id(args[0])
902
+
903
+ instance_ids = []
904
+ app['appTiers'].each do |app_tier|
905
+ app_tier['appInstances'].each do |app_instance|
906
+ instance_ids << app_instance['instance']['id']
907
+ end
908
+ end
909
+
910
+ # container_ids = instance['containers']
911
+ # if options[:node_id] && container_ids.include?(options[:node_id])
912
+ # container_ids = [options[:node_id]]
913
+ # end
914
+ params = {}
915
+ params['instanceIds'] = instance_ids
916
+ params.merge!(parse_list_options(options))
917
+ # params[:query] = params.delete(:phrase) unless params[:phrase].nil?
918
+ if options[:dry_run]
919
+ print_dry_run @processes_interface.dry.list(params)
920
+ return
921
+ end
922
+ json_response = @processes_interface.list(params)
923
+ if options[:json]
924
+ puts as_json(json_response, options, "processes")
925
+ return 0
926
+ elsif options[:yaml]
927
+ puts as_yaml(json_response, options, "processes")
928
+ return 0
929
+ elsif options[:csv]
930
+ puts records_as_csv(json_response['processes'], options)
931
+ return 0
932
+ else
933
+
934
+ title = "App History: #{app['name']}"
935
+ subtitles = []
936
+ if params[:query]
937
+ subtitles << "Search: #{params[:query]}".strip
938
+ end
939
+ subtitles += parse_list_subtitles(options)
940
+ print_h1 title, subtitles
941
+ if json_response['processes'].empty?
942
+ print "#{cyan}No process history found.#{reset}\n\n"
943
+ else
944
+ history_records = []
945
+ json_response["processes"].each do |process|
946
+ row = {
947
+ id: process['id'],
948
+ eventId: nil,
949
+ uniqueId: process['uniqueId'],
950
+ name: process['displayName'],
951
+ description: process['description'],
952
+ processType: process['processType'] ? (process['processType']['name'] || process['processType']['code']) : process['processTypeName'],
953
+ createdBy: process['createdBy'] ? (process['createdBy']['displayName'] || process['createdBy']['username']) : '',
954
+ startDate: format_local_dt(process['startDate']),
955
+ duration: format_process_duration(process),
956
+ status: format_process_status(process),
957
+ error: format_process_error(process),
958
+ output: format_process_output(process)
959
+ }
960
+ history_records << row
961
+ process_events = process['events'] || process['processEvents']
962
+ if options[:show_events]
963
+ if process_events
964
+ process_events.each do |process_event|
965
+ event_row = {
966
+ id: process['id'],
967
+ eventId: process_event['id'],
968
+ uniqueId: process_event['uniqueId'],
969
+ name: process_event['displayName'], # blank like the UI
970
+ description: process_event['description'],
971
+ processType: process_event['processType'] ? (process_event['processType']['name'] || process_event['processType']['code']) : process['processTypeName'],
972
+ createdBy: process_event['createdBy'] ? (process_event['createdBy']['displayName'] || process_event['createdBy']['username']) : '',
973
+ startDate: format_local_dt(process_event['startDate']),
974
+ duration: format_process_duration(process_event),
975
+ status: format_process_status(process_event),
976
+ error: format_process_error(process_event),
977
+ output: format_process_output(process_event)
978
+ }
979
+ history_records << event_row
980
+ end
981
+ else
982
+
983
+ end
984
+ end
985
+ end
986
+ columns = [
987
+ {:id => {:display_name => "PROCESS ID"} },
988
+ :name,
989
+ :description,
990
+ {:processType => {:display_name => "PROCESS TYPE"} },
991
+ {:createdBy => {:display_name => "CREATED BY"} },
992
+ {:startDate => {:display_name => "START DATE"} },
993
+ {:duration => {:display_name => "ETA/DURATION"} },
994
+ :status,
995
+ :error
996
+ ]
997
+ if options[:show_events]
998
+ columns.insert(1, {:eventId => {:display_name => "EVENT ID"} })
999
+ end
1000
+ if options[:show_output]
1001
+ columns << :output
1002
+ end
1003
+ # custom pretty table columns ...
1004
+ if options[:include_fields]
1005
+ columns = options[:include_fields]
1006
+ end
1007
+ print cyan
1008
+ print as_pretty_table(history_records, columns, options)
1009
+ #print_results_pagination(json_response)
1010
+ print_results_pagination(json_response, {:label => "process", :n_label => "processes"})
1011
+ print reset, "\n"
1012
+ return 0
1013
+ end
1014
+ end
1015
+ rescue RestClient::Exception => e
1016
+ print_rest_exception(e, options)
1017
+ exit 1
1018
+ end
1019
+ end
1020
+
868
1021
  private
869
1022
 
870
1023
  def add_app_option_types(connected=true)
871
1024
  [
872
- {'fieldName' => 'template', 'fieldLabel' => 'Template', 'type' => 'select', 'selectOptions' => (connected ? get_available_app_templates() : []), 'required' => true, 'defaultValue' => 'existing', 'description' => "The app template to use. The default value is 'existing' which means no template, for creating a blank app and adding existing instances."},
1025
+ {'fieldName' => 'blueprint', 'fieldLabel' => 'Blueprint', 'type' => 'select', 'selectOptions' => (connected ? get_available_blueprints() : []), 'required' => true, 'defaultValue' => 'existing', 'description' => "The blueprint to use. The default value is 'existing' which means no template, for creating a blank app and adding existing instances."},
873
1026
  {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'description' => 'Enter a name for this app'},
874
1027
  {'fieldName' => 'description', 'fieldLabel' => 'Description', 'type' => 'text', 'required' => false},
875
1028
  {'fieldName' => 'group', 'fieldLabel' => 'Group', 'type' => 'select', 'selectOptions' => (connected ? get_available_groups() : []), 'required' => true},
@@ -879,7 +1032,7 @@ class Morpheus::Cli::Apps
879
1032
 
880
1033
  def update_app_option_types(connected=true)
881
1034
  list = add_app_option_types(connected)
882
- list = list.reject {|it| ["template", "group"].include? it['fieldName'] }
1035
+ list = list.reject {|it| ["blueprint", "group"].include? it['fieldName'] }
883
1036
  list.each {|it| it['required'] = false }
884
1037
  list
885
1038
  end
@@ -999,17 +1152,18 @@ class Morpheus::Cli::Apps
999
1152
  out
1000
1153
  end
1001
1154
 
1002
- def get_available_app_templates(refresh=false)
1003
- if !@available_app_templates || refresh
1004
- results = @options_interface.options_for_source('appTemplates',{})
1005
- @available_app_templates = results['data'].collect {|it|
1155
+ def get_available_blueprints(refresh=false)
1156
+ if !@available_blueprints || refresh
1157
+ results = @options_interface.options_for_source('appTemplates',{}) # still exists
1158
+ #results = @options_interface.options_for_source('blueprints',{})
1159
+ @available_blueprints = results['data'].collect {|it|
1006
1160
  {"id" => it["value"], "name" => it["name"], "value" => it["value"]}
1007
1161
  }
1008
1162
  default_option = {"id" => "existing", "name" => "Existing Instances", "value" => "existing"}
1009
- @available_app_templates.unshift(default_option)
1163
+ @available_blueprints.unshift(default_option)
1010
1164
  end
1011
- #puts "get_available_app_templates() rtn: #{@available_app_templates.inspect}"
1012
- return @available_app_templates
1165
+ #puts "get_available_blueprints() rtn: #{@available_blueprints.inspect}"
1166
+ return @available_blueprints
1013
1167
  end
1014
1168
 
1015
1169
  def get_available_environments(refresh=false)