morpheus-cli 3.5.2 → 3.5.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/morpheus/api/api_client.rb +16 -0
- data/lib/morpheus/api/blueprints_interface.rb +84 -0
- data/lib/morpheus/api/execution_request_interface.rb +33 -0
- data/lib/morpheus/api/instances_interface.rb +21 -0
- data/lib/morpheus/api/packages_interface.rb +25 -5
- data/lib/morpheus/api/processes_interface.rb +34 -0
- data/lib/morpheus/api/roles_interface.rb +7 -0
- data/lib/morpheus/api/servers_interface.rb +8 -0
- data/lib/morpheus/api/user_settings_interface.rb +76 -0
- data/lib/morpheus/cli.rb +5 -1
- data/lib/morpheus/cli/alias_command.rb +1 -1
- data/lib/morpheus/cli/app_templates.rb +2 -1
- data/lib/morpheus/cli/apps.rb +173 -19
- data/lib/morpheus/cli/blueprints_command.rb +2134 -0
- data/lib/morpheus/cli/cli_command.rb +3 -1
- data/lib/morpheus/cli/clouds.rb +4 -10
- data/lib/morpheus/cli/coloring_command.rb +14 -8
- data/lib/morpheus/cli/containers_command.rb +92 -5
- data/lib/morpheus/cli/execution_request_command.rb +313 -0
- data/lib/morpheus/cli/hosts.rb +188 -7
- data/lib/morpheus/cli/instances.rb +472 -9
- data/lib/morpheus/cli/login.rb +1 -1
- data/lib/morpheus/cli/mixins/print_helper.rb +8 -0
- data/lib/morpheus/cli/mixins/processes_helper.rb +134 -0
- data/lib/morpheus/cli/option_types.rb +21 -16
- data/lib/morpheus/cli/packages_command.rb +469 -17
- data/lib/morpheus/cli/processes_command.rb +313 -0
- data/lib/morpheus/cli/remote.rb +20 -9
- data/lib/morpheus/cli/roles.rb +186 -6
- data/lib/morpheus/cli/shell.rb +10 -1
- data/lib/morpheus/cli/tasks.rb +4 -1
- data/lib/morpheus/cli/user_settings_command.rb +431 -0
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/cli/whoami.rb +1 -1
- data/lib/morpheus/formatters.rb +14 -0
- data/lib/morpheus/morpkg.rb +119 -0
- data/morpheus-cli.gemspec +1 -0
- metadata +26 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 23cf1069887e9d9fc379bb4c5d542ffaf746fb045ba394b281f1bcbe2f6979e0
|
4
|
+
data.tar.gz: 544bb68d0fc395fa8d6a76391028641e564d37f9f6f82c515d763420e83230bb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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 =>
|
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
|
-
|
46
|
-
|
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
|
data/lib/morpheus/cli.rb
CHANGED
@@ -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/
|
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 << "
|
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
|
-
|
13
|
+
set_command_hidden
|
13
14
|
|
14
15
|
register_subcommands :list, :get, :add, :update, :remove
|
15
16
|
register_subcommands :duplicate
|
data/lib/morpheus/cli/apps.rb
CHANGED
@@ -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( '-
|
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('
|
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 =
|
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 "
|
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
|
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
|
-
|
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 "
|
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' => '
|
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| ["
|
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
|
1003
|
-
if !@
|
1004
|
-
results = @options_interface.options_for_source('appTemplates',{})
|
1005
|
-
|
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
|
-
@
|
1163
|
+
@available_blueprints.unshift(default_option)
|
1010
1164
|
end
|
1011
|
-
#puts "
|
1012
|
-
return @
|
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)
|