morpheus-cli 2.10.0 → 2.10.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/bin/morpheus +27 -32
  3. data/lib/morpheus/api/accounts_interface.rb +36 -47
  4. data/lib/morpheus/api/api_client.rb +141 -110
  5. data/lib/morpheus/api/app_templates_interface.rb +56 -72
  6. data/lib/morpheus/api/apps_interface.rb +111 -132
  7. data/lib/morpheus/api/auth_interface.rb +30 -0
  8. data/lib/morpheus/api/clouds_interface.rb +71 -76
  9. data/lib/morpheus/api/custom_instance_types_interface.rb +21 -46
  10. data/lib/morpheus/api/dashboard_interface.rb +10 -17
  11. data/lib/morpheus/api/deploy_interface.rb +60 -72
  12. data/lib/morpheus/api/deployments_interface.rb +53 -71
  13. data/lib/morpheus/api/groups_interface.rb +55 -45
  14. data/lib/morpheus/api/instance_types_interface.rb +19 -23
  15. data/lib/morpheus/api/instances_interface.rb +179 -177
  16. data/lib/morpheus/api/key_pairs_interface.rb +11 -17
  17. data/lib/morpheus/api/license_interface.rb +18 -23
  18. data/lib/morpheus/api/load_balancers_interface.rb +54 -69
  19. data/lib/morpheus/api/logs_interface.rb +25 -29
  20. data/lib/morpheus/api/options_interface.rb +13 -17
  21. data/lib/morpheus/api/provision_types_interface.rb +19 -22
  22. data/lib/morpheus/api/roles_interface.rb +75 -94
  23. data/lib/morpheus/api/security_group_rules_interface.rb +28 -37
  24. data/lib/morpheus/api/security_groups_interface.rb +39 -51
  25. data/lib/morpheus/api/servers_interface.rb +113 -115
  26. data/lib/morpheus/api/setup_interface.rb +31 -0
  27. data/lib/morpheus/api/task_sets_interface.rb +36 -38
  28. data/lib/morpheus/api/tasks_interface.rb +56 -69
  29. data/lib/morpheus/api/users_interface.rb +67 -76
  30. data/lib/morpheus/api/virtual_images_interface.rb +61 -61
  31. data/lib/morpheus/api/whoami_interface.rb +12 -15
  32. data/lib/morpheus/cli.rb +71 -60
  33. data/lib/morpheus/cli/accounts.rb +254 -315
  34. data/lib/morpheus/cli/alias_command.rb +219 -0
  35. data/lib/morpheus/cli/app_templates.rb +264 -272
  36. data/lib/morpheus/cli/apps.rb +608 -671
  37. data/lib/morpheus/cli/cli_command.rb +259 -21
  38. data/lib/morpheus/cli/cli_registry.rb +99 -14
  39. data/lib/morpheus/cli/clouds.rb +599 -372
  40. data/lib/morpheus/cli/config_file.rb +126 -0
  41. data/lib/morpheus/cli/credentials.rb +141 -117
  42. data/lib/morpheus/cli/dashboard_command.rb +48 -56
  43. data/lib/morpheus/cli/deployments.rb +254 -268
  44. data/lib/morpheus/cli/deploys.rb +150 -142
  45. data/lib/morpheus/cli/error_handler.rb +38 -0
  46. data/lib/morpheus/cli/groups.rb +551 -179
  47. data/lib/morpheus/cli/hosts.rb +862 -617
  48. data/lib/morpheus/cli/instance_types.rb +103 -95
  49. data/lib/morpheus/cli/instances.rb +1335 -1009
  50. data/lib/morpheus/cli/key_pairs.rb +82 -90
  51. data/lib/morpheus/cli/library.rb +498 -499
  52. data/lib/morpheus/cli/license.rb +83 -101
  53. data/lib/morpheus/cli/load_balancers.rb +314 -300
  54. data/lib/morpheus/cli/login.rb +66 -44
  55. data/lib/morpheus/cli/logout.rb +47 -46
  56. data/lib/morpheus/cli/mixins/accounts_helper.rb +69 -31
  57. data/lib/morpheus/cli/mixins/infrastructure_helper.rb +106 -0
  58. data/lib/morpheus/cli/mixins/print_helper.rb +181 -17
  59. data/lib/morpheus/cli/mixins/provisioning_helper.rb +535 -458
  60. data/lib/morpheus/cli/mixins/whoami_helper.rb +2 -2
  61. data/lib/morpheus/cli/option_parser.rb +35 -0
  62. data/lib/morpheus/cli/option_types.rb +232 -192
  63. data/lib/morpheus/cli/recent_activity_command.rb +61 -65
  64. data/lib/morpheus/cli/remote.rb +446 -199
  65. data/lib/morpheus/cli/roles.rb +884 -906
  66. data/lib/morpheus/cli/security_group_rules.rb +213 -203
  67. data/lib/morpheus/cli/security_groups.rb +237 -192
  68. data/lib/morpheus/cli/shell.rb +338 -231
  69. data/lib/morpheus/cli/tasks.rb +326 -308
  70. data/lib/morpheus/cli/users.rb +457 -462
  71. data/lib/morpheus/cli/version.rb +1 -1
  72. data/lib/morpheus/cli/version_command.rb +16 -18
  73. data/lib/morpheus/cli/virtual_images.rb +526 -345
  74. data/lib/morpheus/cli/whoami.rb +125 -111
  75. data/lib/morpheus/cli/workflows.rb +338 -185
  76. data/lib/morpheus/formatters.rb +8 -1
  77. data/lib/morpheus/logging.rb +1 -1
  78. data/lib/morpheus/rest_client.rb +17 -8
  79. metadata +9 -3
  80. data/lib/morpheus/api/custom_instance_types.rb +0 -55
@@ -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