morpheus-cli 2.10.0 → 2.10.1

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 (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
@@ -11,128 +11,142 @@ class Morpheus::Cli::Whoami
11
11
  include Morpheus::Cli::CliCommand
12
12
  include Morpheus::Cli::WhoamiHelper
13
13
  include Morpheus::Cli::AccountsHelper
14
-
15
- def initialize()
16
- @appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
17
- end
14
+ include Morpheus::Cli::InfrastructureHelper
18
15
 
19
- def connect(opts)
20
- @access_token = Morpheus::Cli::Credentials.new(@appliance_name,@appliance_url).load_saved_credentials()
21
- # always try this.. it will 401
22
- # if @access_token.empty?
23
- # print_red_alert "Invalid Credentials. Unable to acquire access token. Please verify your credentials and try again."
24
- # exit 1
25
- # end
26
- @api_client = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url)
27
-
16
+ set_command_name :whoami
28
17
 
29
- end
18
+ # no subcommands, just show()
30
19
 
31
- def usage
32
- "Usage: morpheus whoami"
33
- end
20
+ def initialize()
21
+ # @appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
22
+ end
34
23
 
35
- def handle(args)
36
- show(args)
37
- end
38
-
39
- def show(args)
40
- options = {}
41
- optparse = OptionParser.new do|opts|
42
- opts.banner = usage
43
- opts.on(nil,'--feature-access', "Display Feature Access") do |val|
44
- options[:include_feature_access] = true
45
- end
46
- # opts.on(nil,'--group-access', "Display Group Access") do
47
- # options[:include_group_access] = true
48
- # end
49
- # opts.on(nil,'--cloud-access', "Display Cloud Access") do
50
- # options[:include_cloud_access] = true
51
- # end
52
- # opts.on(nil,'--instance-type-access', "Display Instance Type Access") do
53
- # options[:include_instance_type_access] = true
54
- # end
55
- opts.on(nil,'--all-access', "Display All Access Lists") do
56
- options[:include_feature_access] = true
57
- options[:include_group_access] = true
58
- options[:include_cloud_access] = true
59
- options[:include_instance_type_access] = true
60
- end
61
- build_common_options(opts, options, [:json]) # todo: support :remote too
62
- end
63
- optparse.parse(args)
24
+ def connect(opts)
25
+ @api_client = establish_remote_appliance_connection(opts)
26
+ @groups_interface = @api_client.groups
27
+ @active_group_id = Morpheus::Cli::Groups.active_group
28
+ end
64
29
 
65
- connect(options)
66
- begin
67
-
68
- json_response = load_whoami()
69
-
70
- if options[:json]
71
- print JSON.pretty_generate(json_response)
72
- print "\n"
73
- else
74
- user = @current_user
75
- if !user
76
- puts yellow,"No active session. Please login",reset
77
- exit 1
78
- end
30
+ def handle(args)
31
+ show(args)
32
+ end
79
33
 
80
- # todo: impersonate command and show that info here
34
+ def show(args)
35
+ options = {}
36
+ optparse = OptionParser.new do|opts|
37
+ opts.banner = usage
38
+ opts.on(nil,'--feature-access', "Display Feature Access") do |val|
39
+ options[:include_feature_access] = true
40
+ end
41
+ # opts.on(nil,'--group-access', "Display Group Access") do
42
+ # options[:include_group_access] = true
43
+ # end
44
+ # opts.on(nil,'--cloud-access', "Display Cloud Access") do
45
+ # options[:include_cloud_access] = true
46
+ # end
47
+ # opts.on(nil,'--instance-type-access', "Display Instance Type Access") do
48
+ # options[:include_instance_type_access] = true
49
+ # end
50
+ opts.on(nil,'--all-access', "Display All Access Lists") do
51
+ options[:include_feature_access] = true
52
+ options[:include_group_access] = true
53
+ options[:include_cloud_access] = true
54
+ options[:include_instance_type_access] = true
55
+ end
56
+ build_common_options(opts, options, [:json, :remote]) # todo: support :remote too
57
+ end
58
+ optparse.parse!(args)
59
+ # todo: check to see if they have credentials instead of just trying to connect (and prompting)
60
+ connect(options)
61
+ begin
62
+ json_response = load_whoami()
63
+ group = nil
64
+ begin
65
+ group = @active_group_id ? find_group_by_name_or_id(@active_group_id) : nil # via InfrastructureHelper mixin
66
+ rescue => err
67
+ if options[:debug]
68
+ print red,"Unable to determine active group: #{err}\n",reset
69
+ end
70
+ end
71
+ if options[:json]
72
+ print JSON.pretty_generate(json_response)
73
+ print "\n"
74
+ else
75
+ user = @current_user
76
+ if !user
77
+ puts yellow,"No active session. Please login",reset
78
+ exit 1
79
+ end
81
80
 
82
- print "\n" ,cyan, bold, "Current User\n","==================", reset, "\n\n"
83
- print cyan
84
- # if @is_master_account
85
- puts "ID: #{user['id']}"
86
- puts "Account: #{user['account'] ? user['account']['name'] : nil}" + (@is_master_account ? " (Master Account)" : "")
87
- # end
88
- puts "First Name: #{user['firstName']}"
89
- puts "Last Name: #{user['lastName']}"
90
- puts "Username: #{user['username']}"
91
- puts "Email: #{user['email']}"
92
- puts "Role: #{format_user_role_names(user)}"
93
- # puts "Date Created: #{format_local_dt(user['dateCreated'])}"
94
- # puts "Last Updated: #{format_local_dt(user['lastUpdated'])}"
95
- # print "\n" ,cyan, bold, "User Instance Limits\n","==================", reset, "\n\n"
96
- # print cyan
97
- # puts "Max Storage (bytes): #{user['instanceLimits'] ? user['instanceLimits']['maxStorage'] : 0}"
98
- # puts "Max Memory (bytes): #{user['instanceLimits'] ? user['instanceLimits']['maxMemory'] : 0}"
99
- # puts "CPU Count: #{user['instanceLimits'] ? user['instanceLimits']['maxCpu'] : 0}"
81
+ # todo: impersonate command and show that info here
100
82
 
101
- if options[:include_feature_access]
102
- if @user_permissions
103
- print "\n" ,cyan, bold, "Feature Permissions\n","==================", reset, "\n\n"
104
- print cyan
105
- rows = @user_permissions.collect do |code, access|
106
- {code: code, access: get_access_string(access) }
107
- end
108
- tp rows, [:code, :access]
109
- else
110
- puts yellow,"No permissions found.",reset
111
- end
112
- end
83
+ print "\n" ,cyan, bold, "Current User\n","==================", reset, "\n\n"
84
+ # print cyan
85
+ # if @is_master_account
86
+ puts "ID: #{user['id']}"
87
+ puts "Account: #{user['account'] ? user['account']['name'] : nil}" + (@is_master_account ? " (Master Account)" : "")
88
+ # end
89
+ puts "First Name: #{user['firstName']}"
90
+ puts "Last Name: #{user['lastName']}"
91
+ puts "Username: #{user['username']}"
92
+ puts "Email: #{user['email']}"
93
+ puts "Role: #{format_user_role_names(user)}"
94
+ # puts "Date Created: #{format_local_dt(user['dateCreated'])}"
95
+ # puts "Last Updated: #{format_local_dt(user['lastUpdated'])}"
96
+ # print "\n" ,cyan, bold, "User Instance Limits\n","==================", reset, "\n\n"
97
+ # print cyan
98
+ # puts "Max Storage (bytes): #{user['instanceLimits'] ? user['instanceLimits']['maxStorage'] : 0}"
99
+ # puts "Max Memory (bytes): #{user['instanceLimits'] ? user['instanceLimits']['maxMemory'] : 0}"
100
+ # puts "CPU Count: #{user['instanceLimits'] ? user['instanceLimits']['maxCpu'] : 0}"
113
101
 
114
- print "\n" ,cyan, bold, "Remote Appliance\n","==================", reset, "\n\n"
115
- print cyan
116
- if @appliance_name
117
- puts "Name: #{@appliance_name}"
118
- end
119
- if @appliance_url
120
- puts "Url: #{@appliance_url}"
121
- end
122
- if @appliance_build_verison
123
- puts "Build Version: #{@appliance_build_verison}"
124
- end
125
- print cyan
102
+ if options[:include_feature_access]
103
+ if @user_permissions
104
+ print "\n" ,cyan, bold, "Feature Permissions\n","==================", reset, "\n\n"
105
+ print cyan
106
+ rows = @user_permissions.collect do |code, access|
107
+ {code: code, access: get_access_string(access) }
108
+ end
109
+ tp rows, [:code, :access]
110
+ else
111
+ puts yellow,"No permissions found.",reset
112
+ end
113
+ end
126
114
 
127
- print reset,"\n"
115
+ print "\n" ,cyan, bold, "Remote Appliance\n","==================", reset, "\n\n"
116
+ # print cyan
117
+ if @appliance_name
118
+ puts "Name: #{@appliance_name}"
119
+ end
120
+ if @appliance_url
121
+ puts "Url: #{@appliance_url}"
122
+ end
123
+ if @appliance_build_verison
124
+ puts "Build Version: #{@appliance_build_verison}"
125
+ end
126
+ # print cyan
128
127
 
129
- end
130
- rescue RestClient::Exception => e
131
- print_rest_exception(e, options)
132
- exit 1
133
- end
134
- end
128
+ if group
129
+ print "\n" ,cyan, bold, "Active Group\n","==================", reset, "\n\n"
130
+ print "ID: #{group['id']}\n"
131
+ print "Name: #{group['name']}\n"
132
+ else
133
+ print "\n"
134
+ print "No active group. See `groups use`\n",reset
135
+ end
136
+
137
+ print reset,"\n"
138
+ end
139
+ rescue RestClient::Exception => e
140
+ print_rest_exception(e, options)
141
+ if e.response && e.response.code == 401
142
+ puts "It looks like you need to login to the remote appliance [#{@appliance_name}] #{@appliance_url}"
143
+ if Morpheus::Cli::OptionTypes.confirm("Would you like to login now?")
144
+ return Morpheus::Cli::Login.new.login([])
145
+ end
146
+ end
147
+ exit 1
148
+ end
149
+ end
135
150
 
136
-
137
151
 
138
152
  end
@@ -6,189 +6,342 @@ require 'table_print'
6
6
  require 'morpheus/cli/cli_command'
7
7
 
8
8
  class Morpheus::Cli::Workflows
9
- include Morpheus::Cli::CliCommand
10
-
11
- def initialize()
12
- @appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
13
- end
14
-
15
- def connect(opts)
16
- if opts[:remote]
17
- @appliance_url = opts[:remote]
18
- @appliance_name = opts[:remote]
19
- @access_token = Morpheus::Cli::Credentials.new(@appliance_name,@appliance_url).request_credentials(opts)
20
- else
21
- @access_token = Morpheus::Cli::Credentials.new(@appliance_name,@appliance_url).request_credentials(opts)
22
- end
23
- @api_client = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url)
24
- @tasks_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).tasks
25
- @task_sets_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).task_sets
26
- if @access_token.empty?
27
- print_red_alert "Invalid Credentials. Unable to acquire access token. Please verify your credentials and try again."
28
- exit 1
29
- end
30
- end
31
-
32
-
33
- def handle(args)
34
- if args.empty?
35
- puts "\nUsage: morpheus workflows [list,add,remove]\n\n"
36
- return
37
- end
38
-
39
- case args[0]
40
- when 'list'
41
- list(args[1..-1])
42
- when 'add'
43
- add(args[1..-1])
44
- when 'remove'
45
- remove(args[1..-1])
46
- when 'update'
47
- update(args[1..-1])
48
- else
49
- puts "\nUsage: morpheus workflows [list,add,remove]\n\n"
50
- exit 127
51
- end
52
- end
53
-
54
- def list(args)
55
- options = {}
56
- optparse = OptionParser.new do|opts|
57
- opts.banner = "Usage: morpheus workflows list [-s] [-o] [-m]"
58
- build_common_options(opts, options, [:list, :json, :remote])
59
- end
60
- optparse.parse(args)
61
- connect(options)
62
- begin
63
- params = {}
64
- [:phrase, :offset, :max, :sort, :direction].each do |k|
65
- params[k] = options[k] unless options[k].nil?
66
- end
67
- json_response = @task_sets_interface.get(params)
68
- if options[:json]
69
- print JSON.pretty_generate(json_response)
70
- else
71
- task_sets = json_response['taskSets']
72
- print "\n" ,cyan, bold, "Morpheus Workflows\n","==================", reset, "\n\n"
73
- if task_sets.empty?
74
- puts yellow,"No workflows currently configured.",reset
75
- else
76
- print cyan
77
- tasks_table_data = task_sets.collect do |task_set|
78
- {name: task_set['name'], id: task_set['id']}
79
- end
80
- tp tasks_table_data, :id, :name
81
- end
82
- print reset,"\n\n"
83
- end
84
- rescue RestClient::Exception => e
85
- print_rest_exception(e, options)
86
- exit 1
87
- end
88
- end
89
-
90
- def add(args)
91
- workflow_name = args[0]
92
- options = {}
93
- optparse = OptionParser.new do|opts|
94
- opts.banner = "Usage: morpheus workflows add [name] "
95
- opts.on("--tasks x,y,z", Array, "List of tasks to run in order") do |list|
96
- options[:task_names]= list
97
- end
98
- build_common_options(opts, options, [:json, :remote])
99
- end
100
- if args.count < 1
101
- puts "\n#{optparse.banner}\n\n"
102
- exit 1
103
- end
104
- optparse.parse(args)
105
- connect(options)
106
- begin
107
- tasks = []
108
- options[:task_names].each do |task_name|
109
- tasks << find_task_by_name_or_code_or_id(task_name)['id']
110
- end
111
-
112
- payload = {taskSet: {name: workflow_name, tasks: tasks}}
113
- json_response = @task_sets_interface.create(payload)
114
- if options[:json]
115
- print JSON.pretty_generate(json_response)
116
- else
117
- print "\n", cyan, "Workflow #{json_response['taskSet']['name']} created successfully", reset, "\n\n"
118
- end
119
- rescue RestClient::Exception => e
120
- print_rest_exception(e, options)
121
- exit 1
122
- end
123
- end
124
-
125
- def update(args)
126
- end
127
-
128
- def remove(args)
129
- workflow_name = args[0]
130
- options = {}
131
- optparse = OptionParser.new do|opts|
132
- opts.banner = "Usage: morpheus workflows remove [name]"
133
- build_common_options(opts, options, [:auto_confirm, :json, :remote])
134
- end
135
- if args.count < 1
136
- puts "\n#{optparse.banner}\n\n"
137
- exit 1
138
- end
139
- optparse.parse(args)
140
- connect(options)
141
- begin
142
- workflow = find_workflow_by_name_or_code_or_id(workflow_name)
143
- exit 1 if workflow.nil?
144
- unless options[:yes] || Morpheus::Cli::OptionTypes.confirm("Are you sure you want to delete the workflow #{workflow['name']}?")
145
- exit 1
146
- end
147
- json_response = @tasks_interface.destroy(task['id'])
148
- if options[:json]
149
- print JSON.pretty_generate(json_response)
150
- else
151
- print "\n", cyan, "Workflow #{workflow['name']} removed", reset, "\n\n"
152
- end
153
- rescue RestClient::Exception => e
154
- print_rest_exception(e, options)
155
- exit 1
156
- end
157
- end
158
-
159
-
160
- private
161
- def find_workflow_by_name_or_code_or_id(val)
162
- raise "find_workflow_by_name_or_code_or_id passed a bad name: #{val.inspect}" if val.to_s == ''
163
- results = @task_sets_interface.get(val)
164
- result = nil
165
- if !results['taskSets'].nil? && !results['taskSets'].empty?
166
- result = results['taskSets'][0]
167
- elsif val.to_i.to_s == val
168
- results = @task_sets_interface.get(val.to_i)
169
- result = results['taskSet']
170
- end
171
- if result.nil?
172
- print red,bold, "\nWorkflow not found by '#{val}'\n\n",reset
173
- return nil
174
- end
175
- return result
176
- end
177
-
178
- def find_task_by_name_or_code_or_id(val)
179
- raise "find_task_by_name_or_code_or_id passed a bad name: #{val.inspect}" if val.to_s == ''
180
- results = @tasks_interface.get(val)
181
- result = nil
182
- if !results['tasks'].nil? && !results['tasks'].empty?
183
- result = results['tasks'][0]
184
- elsif val.to_i.to_s == val
185
- results = @tasks_interface.get(val.to_i)
186
- result = results['task']
187
- end
188
- if result.nil?
189
- print red,bold, "\nTask not found by '#{val}'\n\n",reset
190
- return nil
191
- end
192
- return result
193
- end
9
+ include Morpheus::Cli::CliCommand
10
+
11
+ register_subcommands :list, :get, :add, :update, :remove
12
+ set_default_subcommand :list
13
+
14
+ # def initialize()
15
+ # @appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
16
+ # end
17
+
18
+ def connect(opts)
19
+ @api_client = establish_remote_appliance_connection(opts)
20
+ @tasks_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).tasks
21
+ @task_sets_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).task_sets
22
+ end
23
+
24
+
25
+ def handle(args)
26
+ handle_subcommand(args)
27
+ end
28
+
29
+
30
+ def list(args)
31
+ options = {}
32
+ optparse = OptionParser.new do|opts|
33
+ opts.banner = subcommand_usage()
34
+ build_common_options(opts, options, [:list, :json, :dry_run, :remote])
35
+ end
36
+ optparse.parse!(args)
37
+ connect(options)
38
+ begin
39
+ params = {}
40
+ [:phrase, :offset, :max, :sort, :direction].each do |k|
41
+ params[k] = options[k] unless options[k].nil?
42
+ end
43
+ if options[:dry_run]
44
+ print_dry_run @task_sets_interface.dry.get(params)
45
+ return
46
+ end
47
+ json_response = @task_sets_interface.get(params)
48
+ if options[:json]
49
+ print JSON.pretty_generate(json_response)
50
+ else
51
+ task_sets = json_response['taskSets']
52
+ print "\n" ,cyan, bold, "Morpheus Workflows\n","==================", reset, "\n\n"
53
+ if task_sets.empty?
54
+ puts yellow,"No workflows currently configured.",reset
55
+ else
56
+ print cyan
57
+ print_workflows_table(task_sets)
58
+ print_results_pagination(json_response)
59
+ end
60
+ print reset,"\n"
61
+ end
62
+ rescue RestClient::Exception => e
63
+ print_rest_exception(e, options)
64
+ exit 1
65
+ end
66
+ end
67
+
68
+ def add(args)
69
+ options = {}
70
+ optparse = OptionParser.new do|opts|
71
+ opts.banner = subcommand_usage("[name] --tasks x,y,z")
72
+ opts.on("--tasks x,y,z", Array, "List of tasks to run in order") do |list|
73
+ options[:task_names] = list
74
+ end
75
+ build_common_options(opts, options, [:json, :dry_run, :remote])
76
+ end
77
+ optparse.parse!(args)
78
+ if args.count < 1 || options[:task_names].empty?
79
+ puts optparse
80
+ exit 1
81
+ end
82
+ workflow_name = args[0]
83
+ connect(options)
84
+ begin
85
+ tasks = []
86
+ options[:task_names].each do |task_name|
87
+ tasks << find_task_by_name_or_id(task_name.to_s.strip)['id']
88
+ end
89
+
90
+ payload = {taskSet: {name: workflow_name, tasks: tasks}}
91
+ if options[:dry_run]
92
+ print_dry_run @task_sets_interface.dry.create(payload)
93
+ return
94
+ end
95
+ json_response = @task_sets_interface.create(payload)
96
+ if options[:json]
97
+ print JSON.pretty_generate(json_response)
98
+ else
99
+ print "\n", cyan, "Workflow #{json_response['taskSet']['name']} created successfully", reset, "\n\n"
100
+ end
101
+ rescue RestClient::Exception => e
102
+ print_rest_exception(e, options)
103
+ exit 1
104
+ end
105
+ end
106
+
107
+ def get(args)
108
+ options = {}
109
+ optparse = OptionParser.new do|opts|
110
+ opts.banner = subcommand_usage("[task]")
111
+ build_common_options(opts, options, [:json, :dry_run, :remote])
112
+ end
113
+ optparse.parse!(args)
114
+ if args.count < 1
115
+ puts optparse
116
+ exit 1
117
+ end
118
+ workflow_name = args[0]
119
+ connect(options)
120
+ begin
121
+ if options[:dry_run]
122
+ if workflow_name.to_s =~ /\A\d{1,}\Z/
123
+ print_dry_run @task_sets_interface.dry.get(workflow_name.to_i)
124
+ else
125
+ print_dry_run @task_sets_interface.dry.get({name: workflow_name})
126
+ end
127
+ return
128
+ end
129
+ workflow = find_workflow_by_name_or_id(workflow_name)
130
+ exit 1 if workflow.nil?
131
+ # refetch it..
132
+ json_response = @task_sets_interface.get(workflow['id'])
133
+ workflow = json_response['taskSet']
134
+
135
+ if options[:json]
136
+ #puts JSON.pretty_generate(workflow)
137
+ puts JSON.pretty_generate(json_response)
138
+ print "\n"
139
+ else
140
+ # tasks = []
141
+ # (workflow['tasks'] || []).each do |task_name|
142
+ # tasks << find_task_by_name_or_id(task_name)['id']
143
+ # end
144
+ tasks = workflow['taskSetTasks'].sort { |x,y| x['taskOrder'].to_i <=> y['taskOrder'].to_i }
145
+ print "\n" ,cyan, bold, "Workflow Details\n","==================", reset, "\n\n"
146
+ print cyan
147
+ puts "ID: #{workflow['id']}"
148
+ puts "Name: #{workflow['name']}"
149
+ #puts "Description: #{workflow['description']}"
150
+ #task_names = tasks.collect {|it| it['name'] }
151
+ print "\n", cyan, "Tasks:\n"
152
+ tasks.each_with_index do |taskSetTask, index|
153
+ puts "#{(index+1).to_s.rjust(3, ' ')}. #{taskSetTask['task']['name']}"
154
+ end
155
+ print reset,"\n"
156
+ end
157
+ rescue RestClient::Exception => e
158
+ print_rest_exception(e, options)
159
+ exit 1
160
+ end
161
+ end
162
+
163
+ def update(args)
164
+ options = {}
165
+ optparse = OptionParser.new do|opts|
166
+ opts.banner = subcommand_usage("[name] --tasks x,y,z")
167
+ opts.on("--tasks x,y,z", Array, "New list of tasks to run in order") do |list|
168
+ options[:task_names]= list
169
+ end
170
+ opts.on("--name NAME", String, "New name for workflow") do |val|
171
+ options[:new_name] = val
172
+ end
173
+ build_common_options(opts, options, [:json, :dry_run, :quiet, :remote])
174
+ end
175
+ optparse.parse!(args)
176
+ if args.count < 1 || (options[:new_name].empty? && options[:task_names].empty?)
177
+ puts optparse
178
+ exit 1
179
+ end
180
+ workflow_name = args[0]
181
+ connect(options)
182
+ begin
183
+ workflow = find_workflow_by_name_or_id(workflow_name)
184
+ payload = {taskSet: {id: workflow['id']} }
185
+ tasks = []
186
+ if options[:task_names]
187
+ options[:task_names].each do |task_name|
188
+ tasks << find_task_by_name_or_id(task_name)['id']
189
+ end
190
+ payload[:taskSet][:tasks] = tasks
191
+ else
192
+ payload[:taskSet][:tasks] = workflow['tasks']
193
+ end
194
+ if options[:new_name]
195
+ payload[:taskSet][:name] = options[:new_name]
196
+ end
197
+ if options[:dry_run]
198
+ print_dry_run @task_sets_interface.dry.update(workflow['id'], payload)
199
+ return
200
+ end
201
+ json_response = @task_sets_interface.update(workflow['id'], payload)
202
+ if options[:json]
203
+ print JSON.pretty_generate(json_response)
204
+ elsif !options[:quiet]
205
+ print "\n", cyan, "Workflow #{json_response['taskSet']['name']} updated successfully", reset, "\n\n"
206
+ get([workflow['id']])
207
+ end
208
+ rescue RestClient::Exception => e
209
+ print_rest_exception(e, options)
210
+ exit 1
211
+ end
212
+ end
213
+
214
+ def remove(args)
215
+ options = {}
216
+ optparse = OptionParser.new do|opts|
217
+ opts.banner = "Usage: morpheus workflows remove [name]"
218
+ build_common_options(opts, options, [:auto_confirm, :json, :dry_run, :quiet, :remote])
219
+ end
220
+ optparse.parse!(args)
221
+ if args.count < 1
222
+ puts optparse
223
+ exit 1
224
+ end
225
+ workflow_name = args[0]
226
+ connect(options)
227
+ begin
228
+ workflow = find_workflow_by_name_or_id(workflow_name)
229
+ exit 1 if workflow.nil?
230
+ unless options[:yes] || Morpheus::Cli::OptionTypes.confirm("Are you sure you want to delete the workflow #{workflow['name']}?")
231
+ exit 1
232
+ end
233
+ if options[:dry_run]
234
+ print_dry_run @task_sets_interface.dry.destroy(workflow['id'])
235
+ return
236
+ end
237
+ json_response = @task_sets_interface.destroy(workflow['id'])
238
+ if options[:json]
239
+ print JSON.pretty_generate(json_response)
240
+ elsif !options[:quiet]
241
+ print "\n", cyan, "Workflow #{workflow['name']} removed", reset, "\n\n"
242
+ end
243
+ rescue RestClient::Exception => e
244
+ print_rest_exception(e, options)
245
+ exit 1
246
+ end
247
+ end
248
+
249
+
250
+ private
251
+
252
+ def find_workflow_by_name_or_id(val)
253
+ if val.to_s =~ /\A\d{1,}\Z/
254
+ return find_workflow_by_id(val)
255
+ else
256
+ return find_workflow_by_name(val)
257
+ end
258
+ end
259
+
260
+ def find_workflow_by_id(id)
261
+ begin
262
+ json_response = @task_sets_interface.get(id.to_i)
263
+ return json_response['taskSet']
264
+ rescue RestClient::Exception => e
265
+ if e.response && e.response.code == 404
266
+ print_red_alert "Workflow not found by id #{id}"
267
+ else
268
+ raise e
269
+ end
270
+ end
271
+ end
272
+
273
+ def find_workflow_by_name(name)
274
+ workflows = @task_sets_interface.get({name: name.to_s})['taskSets']
275
+ if workflows.empty?
276
+ print_red_alert "Workflow not found by name #{name}"
277
+ return nil
278
+ elsif workflows.size > 1
279
+ print_red_alert "#{workflows.size} workflows by name #{name}"
280
+ print_workflows_table(workflows, {color: red})
281
+ print reset,"\n\n"
282
+ return nil
283
+ else
284
+ return workflows[0]
285
+ end
286
+ end
287
+
288
+ def find_task_by_name_or_id(val)
289
+ if val.to_s =~ /\A\d{1,}\Z/
290
+ return find_task_by_id(val)
291
+ else
292
+ return find_task_by_name(val)
293
+ end
294
+ end
295
+
296
+ def find_task_by_id(id)
297
+ begin
298
+ json_response = @tasks_interface.get(id.to_i)
299
+ return json_response['task']
300
+ rescue RestClient::Exception => e
301
+ if e.response && e.response.code == 404
302
+ print_red_alert "Task not found by id #{id}"
303
+ else
304
+ raise e
305
+ end
306
+ end
307
+ end
308
+
309
+ def find_task_by_name(name)
310
+ tasks = @tasks_interface.get({name: name.to_s})['tasks']
311
+ if tasks.empty?
312
+ print_red_alert "Task not found by name #{name}"
313
+ return nil
314
+ elsif tasks.size > 1
315
+ print_red_alert "#{tasks.size} tasks by name #{name}"
316
+ print_tasks_table(tasks, {color: red})
317
+ print reset,"\n\n"
318
+ return nil
319
+ else
320
+ return tasks[0]
321
+ end
322
+ end
323
+
324
+ def print_workflows_table(workflows, opts={})
325
+ table_color = opts[:color] || cyan
326
+ rows = workflows.collect do |workflow|
327
+ task_names = []
328
+ workflow['taskSetTasks'].sort { |x,y| x['taskOrder'].to_i <=> y['taskOrder'].to_i }.each do |taskSetTask|
329
+ task_names << taskSetTask['task']['name']
330
+ end
331
+ {
332
+ id: workflow['id'],
333
+ name: workflow['name'],
334
+ tasks: task_names.join(', '),
335
+ dateCreated: format_local_dt(workflow['dateCreated'])
336
+ }
337
+ end
338
+ print table_color
339
+ tp rows, [
340
+ :id,
341
+ :name,
342
+ :tasks
343
+ ]
344
+ print reset
345
+ end
346
+
194
347
  end