morpheus-cli 3.3.1.4 → 3.3.2
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 +28 -0
- data/lib/morpheus/api/instance_types_interface.rb +12 -10
- data/lib/morpheus/api/instances_interface.rb +4 -0
- data/lib/morpheus/api/library_container_scripts_interface.rb +49 -0
- data/lib/morpheus/api/library_container_templates_interface.rb +49 -0
- data/lib/morpheus/api/library_container_types_interface.rb +65 -0
- data/lib/morpheus/api/library_container_upgrades_interface.rb +66 -0
- data/lib/morpheus/api/library_instance_types_interface.rb +59 -0
- data/lib/morpheus/api/library_layouts_interface.rb +65 -0
- data/lib/morpheus/api/servers_interface.rb +4 -0
- data/lib/morpheus/api/user_sources_interface.rb +120 -0
- data/lib/morpheus/api/virtual_images_interface.rb +7 -0
- data/lib/morpheus/cli.rb +12 -1
- data/lib/morpheus/cli/accounts.rb +35 -9
- data/lib/morpheus/cli/cli_command.rb +82 -2
- data/lib/morpheus/cli/curl_command.rb +1 -1
- data/lib/morpheus/cli/echo_command.rb +1 -1
- data/lib/morpheus/cli/hosts.rb +40 -14
- data/lib/morpheus/cli/instance_types.rb +106 -64
- data/lib/morpheus/cli/instances.rb +39 -15
- data/lib/morpheus/cli/library.rb +1 -1184
- data/lib/morpheus/cli/library_container_scripts_command.rb +437 -0
- data/lib/morpheus/cli/library_container_templates_command.rb +397 -0
- data/lib/morpheus/cli/library_container_types_command.rb +653 -0
- data/lib/morpheus/cli/library_instance_types_command.rb +491 -0
- data/lib/morpheus/cli/library_layouts_command.rb +650 -0
- data/lib/morpheus/cli/library_option_lists_command.rb +476 -0
- data/lib/morpheus/cli/library_option_types_command.rb +549 -0
- data/lib/morpheus/cli/library_upgrades_command.rb +604 -0
- data/lib/morpheus/cli/mixins/library_helper.rb +123 -0
- data/lib/morpheus/cli/mixins/print_helper.rb +21 -22
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +56 -11
- data/lib/morpheus/cli/network_services_command.rb +1 -1
- data/lib/morpheus/cli/option_types.rb +12 -2
- data/lib/morpheus/cli/power_scheduling_command.rb +1 -1
- data/lib/morpheus/cli/shell.rb +120 -22
- data/lib/morpheus/cli/sleep_command.rb +45 -0
- data/lib/morpheus/cli/user_sources_command.rb +963 -0
- data/lib/morpheus/cli/users.rb +33 -2
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/cli/version_command.rb +1 -1
- data/lib/morpheus/cli/virtual_images.rb +93 -39
- data/lib/morpheus/formatters.rb +37 -27
- data/lib/morpheus/terminal.rb +1 -1
- metadata +20 -2
@@ -0,0 +1,123 @@
|
|
1
|
+
require 'morpheus/cli/mixins/print_helper'
|
2
|
+
require 'morpheus/cli/option_types'
|
3
|
+
# Mixin for Morpheus::Cli command classes
|
4
|
+
# Provides common methods for library management commands
|
5
|
+
module Morpheus::Cli::LibraryHelper
|
6
|
+
|
7
|
+
def self.included(klass)
|
8
|
+
klass.send :include, Morpheus::Cli::PrintHelper
|
9
|
+
end
|
10
|
+
|
11
|
+
def api_client
|
12
|
+
raise "#{self.class} has not defined @api_client" if @api_client.nil?
|
13
|
+
@api_client
|
14
|
+
end
|
15
|
+
|
16
|
+
def find_instance_type_by_name_or_id(val)
|
17
|
+
if val.to_s =~ /\A\d{1,}\Z/
|
18
|
+
return find_instance_type_by_id(val)
|
19
|
+
else
|
20
|
+
return find_instance_type_by_name(val)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def find_instance_type_by_id(id)
|
25
|
+
begin
|
26
|
+
json_response = @library_instance_types_interface.get(id.to_i)
|
27
|
+
return json_response['instanceType']
|
28
|
+
rescue RestClient::Exception => e
|
29
|
+
if e.response && e.response.code == 404
|
30
|
+
print_red_alert "Instance Type not found by id #{id}"
|
31
|
+
else
|
32
|
+
raise e
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def find_instance_type_by_name(name)
|
38
|
+
json_response = @library_instance_types_interface.list({name: name.to_s})
|
39
|
+
instance_types = json_response['instanceTypes']
|
40
|
+
if instance_types.empty?
|
41
|
+
print_red_alert "Instance Type not found by name #{name}"
|
42
|
+
return nil
|
43
|
+
elsif instance_types.size > 1
|
44
|
+
print_red_alert "#{instance_types.size} instance types found by name #{name}"
|
45
|
+
print_instance_types_table(instance_types, {color: red})
|
46
|
+
print_red_alert "Try using ID instead"
|
47
|
+
print reset,"\n"
|
48
|
+
return nil
|
49
|
+
else
|
50
|
+
return instance_types[0]
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def print_instance_types_table(instance_types, opts={})
|
55
|
+
columns = [
|
56
|
+
{"ID" => lambda {|instance_type| instance_type['id'] } },
|
57
|
+
{"NAME" => lambda {|instance_type| instance_type['name'] } },
|
58
|
+
{"CODE" => lambda {|instance_type| instance_type['code'] } },
|
59
|
+
{"TECHNOLOGY" => lambda {|instance_type| format_instance_type_technology(instance_type) } },
|
60
|
+
{"CATEGORY" => lambda {|instance_type| instance_type['category'].to_s.capitalize } },
|
61
|
+
{"FEATURED" => lambda {|instance_type| format_boolean instance_type['featured'] } },
|
62
|
+
{"OWNER" => lambda {|instance_type| instance_type['account'] ? instance_type['account']['name'] : '' } },
|
63
|
+
]
|
64
|
+
if opts[:include_fields]
|
65
|
+
columns = opts[:include_fields]
|
66
|
+
end
|
67
|
+
print as_pretty_table(instance_types, columns, opts)
|
68
|
+
end
|
69
|
+
|
70
|
+
def format_instance_type_technology(instance_type)
|
71
|
+
if instance_type
|
72
|
+
instance_type['provisionTypeCode'].to_s.capitalize
|
73
|
+
else
|
74
|
+
""
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def load_balance_protocols_dropdown
|
79
|
+
[
|
80
|
+
{'name' => 'None', 'value' => ''},
|
81
|
+
{'name' => 'HTTP', 'value' => 'HTTP'},
|
82
|
+
{'name' => 'HTTPS', 'value' => 'HTTPS'},
|
83
|
+
{'name' => 'TCP', 'value' => 'TCP'}
|
84
|
+
]
|
85
|
+
end
|
86
|
+
|
87
|
+
# Prompts user for exposed ports array
|
88
|
+
# returns array of port objects
|
89
|
+
def prompt_exposed_ports(options={}, api_client=nil, api_params={})
|
90
|
+
#puts "Configure ports:"
|
91
|
+
no_prompt = (options[:no_prompt] || (options[:options] && options[:options][:no_prompt]))
|
92
|
+
|
93
|
+
ports = []
|
94
|
+
port_index = 0
|
95
|
+
has_another_port = options[:options] && options[:options]["exposedPort#{port_index}"]
|
96
|
+
add_another_port = has_another_port || (!no_prompt && Morpheus::Cli::OptionTypes.confirm("Add an exposed port?"))
|
97
|
+
while add_another_port do
|
98
|
+
field_context = "exposedPort#{port_index}"
|
99
|
+
|
100
|
+
port = {}
|
101
|
+
#port['name'] ||= "Port #{port_index}"
|
102
|
+
port_label = port_index == 0 ? "Port" : "Port [#{port_index+1}]"
|
103
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'name', 'type' => 'text', 'fieldLabel' => "#{port_label} Name", 'required' => false, 'description' => 'Choose a name for this port.', 'defaultValue' => port['name']}], options[:options])
|
104
|
+
port['name'] = v_prompt[field_context]['name']
|
105
|
+
|
106
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'port', 'type' => 'number', 'fieldLabel' => "#{port_label} Number", 'required' => true, 'description' => 'A port number. eg. 8001', 'defaultValue' => (port['port'] ? port['port'].to_i : nil)}], options[:options])
|
107
|
+
port['port'] = v_prompt[field_context]['port']
|
108
|
+
|
109
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'loadBalanceProtocol', 'type' => 'select', 'fieldLabel' => "#{port_label} LB", 'selectOptions' => load_balance_protocols_dropdown, 'required' => false, 'skipSingleOption' => true, 'description' => 'Choose a load balance protocol.', 'defaultValue' => port['loadBalanceProtocol']}], options[:options])
|
110
|
+
port['loadBalanceProtocol'] = v_prompt[field_context]['loadBalanceProtocol']
|
111
|
+
|
112
|
+
ports << port
|
113
|
+
port_index += 1
|
114
|
+
has_another_port = options[:options] && options[:options]["exposedPort#{port_index}"]
|
115
|
+
add_another_port = has_another_port || (!no_prompt && Morpheus::Cli::OptionTypes.confirm("Add another exposed port?"))
|
116
|
+
|
117
|
+
end
|
118
|
+
|
119
|
+
|
120
|
+
return ports
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
@@ -58,7 +58,7 @@ module Morpheus::Cli::PrintHelper
|
|
58
58
|
out << "\n"
|
59
59
|
out << "#{color}#{bold}#{title}#{reset}"
|
60
60
|
if !subtitles.empty?
|
61
|
-
out << "#{color}
|
61
|
+
out << "#{color} | #{subtitles.join(', ')}#{reset}"
|
62
62
|
end
|
63
63
|
out << "\n"
|
64
64
|
out << "#{color}#{bold}==================#{reset}"
|
@@ -574,8 +574,15 @@ module Morpheus::Cli::PrintHelper
|
|
574
574
|
columns.each do |col|
|
575
575
|
# determine label
|
576
576
|
if col.is_a?(String)
|
577
|
-
|
578
|
-
|
577
|
+
# supports "field as Label"
|
578
|
+
field_key, field_label = col.split(/\s+as\s+/)
|
579
|
+
if field_key && field_label
|
580
|
+
k = field_label.strip
|
581
|
+
v = field_key.strip
|
582
|
+
else
|
583
|
+
k = col.strip
|
584
|
+
v = col.strip
|
585
|
+
end
|
579
586
|
build_column_definitions([{(k) => v}]).each do |r|
|
580
587
|
results << r if r
|
581
588
|
end
|
@@ -684,15 +691,13 @@ module Morpheus::Cli::PrintHelper
|
|
684
691
|
newline = opts[:csv_newline] || opts[:newline] || "\n"
|
685
692
|
include_header = opts[:csv_no_header] ? false : true
|
686
693
|
do_quotes = opts[:csv_quotes] || opts[:quotes]
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
columns = columns.collect {|k,v| {(k) => v} }
|
691
|
-
end
|
692
|
-
columns = columns.flatten.compact
|
694
|
+
|
695
|
+
column_defs = build_column_definitions(columns)
|
696
|
+
#columns = columns.flatten.compact
|
693
697
|
data_array = [data].flatten.compact
|
698
|
+
|
694
699
|
if include_header
|
695
|
-
headers =
|
700
|
+
headers = column_defs.collect {|column_def| column_def.label }
|
696
701
|
if do_quotes
|
697
702
|
headers = headers.collect {|it| quote_csv_value(it) }
|
698
703
|
end
|
@@ -703,8 +708,10 @@ module Morpheus::Cli::PrintHelper
|
|
703
708
|
data_array.each do |obj|
|
704
709
|
if obj
|
705
710
|
cells = []
|
706
|
-
|
707
|
-
|
711
|
+
column_defs.each do |column_def|
|
712
|
+
label = column_def.label
|
713
|
+
value = column_def.display_method.call(obj)
|
714
|
+
# value = get_object_value(obj, column_def)
|
708
715
|
if do_quotes
|
709
716
|
cells << quote_csv_value(value)
|
710
717
|
else
|
@@ -718,6 +725,7 @@ module Morpheus::Cli::PrintHelper
|
|
718
725
|
out << lines.join(newline)
|
719
726
|
#out << delim
|
720
727
|
out
|
728
|
+
|
721
729
|
end
|
722
730
|
|
723
731
|
def records_as_csv(records, opts={}, default_columns=nil)
|
@@ -748,16 +756,7 @@ module Morpheus::Cli::PrintHelper
|
|
748
756
|
if !data
|
749
757
|
return "null" # "No data"
|
750
758
|
end
|
751
|
-
|
752
|
-
# include_fields = options[:include_fields]
|
753
|
-
# if include_fields
|
754
|
-
# json_fields_for = options[:json_fields_for] || options[:fields_for] || options[:root_field]
|
755
|
-
# if json_fields_for && data[json_fields_for]
|
756
|
-
# data[json_fields_for] = filter_data(data[json_fields_for], include_fields)
|
757
|
-
# else
|
758
|
-
# data = filter_data(data, include_fields)
|
759
|
-
# end
|
760
|
-
# end
|
759
|
+
|
761
760
|
do_pretty = options.key?(:pretty_json) ? options[:pretty_json] : true
|
762
761
|
if do_pretty
|
763
762
|
out << JSON.pretty_generate(data)
|
@@ -117,24 +117,63 @@ module Morpheus::Cli::ProvisioningHelper
|
|
117
117
|
return find_cloud_by_name_for_provisioning(group_id, val)
|
118
118
|
end
|
119
119
|
end
|
120
|
+
|
121
|
+
def find_instance_type_by_id(id)
|
122
|
+
begin
|
123
|
+
json_response = instance_types_interface.get(id.to_i)
|
124
|
+
return json_response['instanceType']
|
125
|
+
rescue RestClient::Exception => e
|
126
|
+
if e.response && e.response.code == 404
|
127
|
+
print_red_alert "Instance Type not found by id #{id}"
|
128
|
+
return nil
|
129
|
+
else
|
130
|
+
raise e
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
120
135
|
def find_instance_type_by_code(code)
|
121
|
-
results = instance_types_interface.
|
122
|
-
|
136
|
+
results = instance_types_interface.list({code: code})
|
137
|
+
instance_types = results['instanceTypes']
|
138
|
+
if instance_types.empty?
|
123
139
|
print_red_alert "Instance Type not found by code #{code}"
|
124
|
-
|
125
|
-
exit 1
|
140
|
+
return nil
|
126
141
|
end
|
127
|
-
|
142
|
+
if instance_types.size() > 1
|
143
|
+
print as_pretty_table(instance_types, [:id,:name,:code], {color:red})
|
144
|
+
print_red_alert "Try using ID instead"
|
145
|
+
return nil
|
146
|
+
end
|
147
|
+
# return instance_types[0]
|
148
|
+
# fetch by ID to get full details
|
149
|
+
# could also use ?details-true with search
|
150
|
+
return find_instance_type_by_id(instance_types[0]['id'])
|
128
151
|
end
|
129
152
|
|
130
153
|
def find_instance_type_by_name(name)
|
131
|
-
results = instance_types_interface.
|
132
|
-
|
154
|
+
results = instance_types_interface.list({name: name})
|
155
|
+
instance_types = results['instanceTypes']
|
156
|
+
if instance_types.empty?
|
133
157
|
print_red_alert "Instance Type not found by name #{name}"
|
134
|
-
|
135
|
-
|
158
|
+
return nil
|
159
|
+
end
|
160
|
+
if instance_types.size() > 1
|
161
|
+
print as_pretty_table(instance_types, [:id,:name,:code], {color:red})
|
162
|
+
print_red_alert "Try using ID instead"
|
163
|
+
return nil
|
164
|
+
end
|
165
|
+
# return instance_types[0]
|
166
|
+
# fetch by ID to get full details
|
167
|
+
# could also use ?details-true with search
|
168
|
+
return find_instance_type_by_id(instance_types[0]['id'])
|
169
|
+
end
|
170
|
+
|
171
|
+
def find_instance_type_by_name_or_id(val)
|
172
|
+
if val.to_s =~ /\A\d{1,}\Z/
|
173
|
+
return find_instance_type_by_id(val)
|
174
|
+
else
|
175
|
+
return find_instance_type_by_name(val)
|
136
176
|
end
|
137
|
-
return results['instanceTypes'][0]
|
138
177
|
end
|
139
178
|
|
140
179
|
def find_instance_by_name_or_id(val)
|
@@ -205,6 +244,7 @@ module Morpheus::Cli::ProvisioningHelper
|
|
205
244
|
instance_type_code = instance_type_prompt['type']
|
206
245
|
end
|
207
246
|
instance_type = find_instance_type_by_code(instance_type_code)
|
247
|
+
exit 1 if !instance_type
|
208
248
|
|
209
249
|
# Instance Name
|
210
250
|
|
@@ -269,7 +309,12 @@ module Morpheus::Cli::ProvisioningHelper
|
|
269
309
|
service_plans = service_plans_json["plans"]
|
270
310
|
service_plans_dropdown = service_plans.collect {|sp| {'name' => sp["name"], 'value' => sp["id"]} } # already sorted
|
271
311
|
plan_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'servicePlan', 'type' => 'select', 'fieldLabel' => 'Plan', 'selectOptions' => service_plans_dropdown, 'required' => true, 'description' => 'Choose the appropriately sized plan for this instance'}],options[:options])
|
272
|
-
|
312
|
+
plan_id = plan_prompt['servicePlan']
|
313
|
+
service_plan = service_plans.find {|sp| sp["id"] == plan_id.to_i }
|
314
|
+
if !service_plan
|
315
|
+
print_red_alert "Plan not found by id #{plan_id}"
|
316
|
+
exit 1
|
317
|
+
end
|
273
318
|
payload['instance']['plan'] = {'id' => service_plan["id"]}
|
274
319
|
|
275
320
|
# prompt for volumes
|
@@ -77,7 +77,7 @@ class Morpheus::Cli::NetworkServicesCommand
|
|
77
77
|
row = {
|
78
78
|
id: network_service['id'],
|
79
79
|
name: network_service['name'],
|
80
|
-
type: network_service['
|
80
|
+
type: network_service['typeName'] || network_service['type'],
|
81
81
|
}
|
82
82
|
row
|
83
83
|
}
|
@@ -233,7 +233,12 @@ module Morpheus
|
|
233
233
|
else
|
234
234
|
print Term::ANSIColor.red, "\nInvalid Option #{option_type['fieldLabel']}: [#{use_value}]\n\n", Term::ANSIColor.reset
|
235
235
|
print Term::ANSIColor.red, " * #{option_type['fieldLabel']} [-O #{option_type['fieldContext'] ? (option_type['fieldContext']+'.') : ''}#{option_type['fieldName']}=] - #{option_type['description']}\n", Term::ANSIColor.reset
|
236
|
-
|
236
|
+
if select_options && select_options.size > 10
|
237
|
+
display_select_options(option_type, select_options.first(10))
|
238
|
+
puts " (#{select_options.size-1} more)"
|
239
|
+
else
|
240
|
+
display_select_options(option_type, select_options)
|
241
|
+
end
|
237
242
|
print "\n"
|
238
243
|
exit 1
|
239
244
|
end
|
@@ -247,7 +252,12 @@ module Morpheus
|
|
247
252
|
if option_type['required']
|
248
253
|
print Term::ANSIColor.red, "\nMissing Required Option\n\n", Term::ANSIColor.reset
|
249
254
|
print Term::ANSIColor.red, " * #{option_type['fieldLabel']} [-O #{option_type['fieldContext'] ? (option_type['fieldContext']+'.') : ''}#{option_type['fieldName']}=] - #{option_type['description']}\n", Term::ANSIColor.reset
|
250
|
-
|
255
|
+
if select_options && select_options.size > 10
|
256
|
+
display_select_options(option_type, select_options.first(10))
|
257
|
+
puts " (#{select_options.size-1} more)"
|
258
|
+
else
|
259
|
+
display_select_options(option_type, select_options)
|
260
|
+
end
|
251
261
|
print "\n"
|
252
262
|
exit 1
|
253
263
|
else
|
@@ -797,7 +797,7 @@ class Morpheus::Cli::PowerSchedulingCommand
|
|
797
797
|
end
|
798
798
|
|
799
799
|
def find_server_by_name(name)
|
800
|
-
servers = @servers_interface.
|
800
|
+
servers = @servers_interface.list({name: name.to_s})['servers']
|
801
801
|
if servers.empty?
|
802
802
|
print_red_alert "Host not found by name #{name}"
|
803
803
|
return nil
|
data/lib/morpheus/cli/shell.rb
CHANGED
@@ -118,7 +118,7 @@ class Morpheus::Cli::Shell
|
|
118
118
|
opts.on('-C','--nocolor', "Disable ANSI coloring") do
|
119
119
|
Term::ANSIColor::coloring = false
|
120
120
|
end
|
121
|
-
opts.on('-V','--debug', "Print extra output for debugging.
|
121
|
+
opts.on('-V','--debug', "Print extra output for debugging.") do |json|
|
122
122
|
Morpheus::Logging.set_log_level(Morpheus::Logging::Logger::DEBUG)
|
123
123
|
::RestClient.log = Morpheus::Logging.debug? ? Morpheus::Logging::DarkPrinter.instance : nil
|
124
124
|
end
|
@@ -174,13 +174,103 @@ class Morpheus::Cli::Shell
|
|
174
174
|
# all_commands = input.gsub(/(\;)(?=(?:[^"]|"[^"]*")*$)/, '__CMDDELIM__').split('__CMDDELIM__').collect {|it| it.to_s.strip }.select {|it| !it.empty? }.compact
|
175
175
|
all_commands = input.gsub(/(\;)(?=(?:[^"']|"[^'"]*")*$)/, '__CMDDELIM__').split('__CMDDELIM__').collect {|it| it.to_s.strip }.select {|it| !it.empty? }.compact
|
176
176
|
#puts "executing #{all_commands.size} commands: #{all_commands}"
|
177
|
+
final_command_result = nil
|
177
178
|
all_commands.each do |cmd|
|
178
|
-
|
179
|
+
flow = parse_commands_and_operators(cmd)
|
180
|
+
if flow.size > 1
|
181
|
+
last_command_result = nil
|
182
|
+
if ['&&','||', '|'].include?(flow.first)
|
183
|
+
puts_error "invalid command format, begins with an operator: #{cmd}"
|
184
|
+
return 9
|
185
|
+
elsif ['&&','||', '|'].include?(flow.last)
|
186
|
+
puts_error "invalid command format, ends with an operator: #{cmd}"
|
187
|
+
return 9
|
188
|
+
# elsif ['&&','||', '|'].include?(flow.last)
|
189
|
+
# puts_error "invalid command format, consecutive operators: #{cmd}"
|
190
|
+
else
|
191
|
+
#Morpheus::Logging::DarkPrinter.puts "Executing command flow: #{flow.inspect}" if Morpheus::Logging.debug?
|
192
|
+
previous_command = nil
|
193
|
+
previous_command_result = nil
|
194
|
+
current_operator = nil
|
195
|
+
still_executing = true
|
196
|
+
flow.each do |flow_cmd|
|
197
|
+
if still_executing
|
198
|
+
if flow_cmd == '&&'
|
199
|
+
# AND operator
|
200
|
+
current_operator = flow_cmd
|
201
|
+
if previous_command_result.to_i != 0
|
202
|
+
still_executing = false
|
203
|
+
end
|
204
|
+
elsif flow_cmd == '||' # or with previous command
|
205
|
+
current_operator = flow_cmd
|
206
|
+
if previous_command_result.to_i == 0
|
207
|
+
still_executing = false
|
208
|
+
end
|
209
|
+
elsif flow_cmd == '|' # or with previous command
|
210
|
+
puts_error "The PIPE (|) operator is not yet supported =["
|
211
|
+
previous_command_result = nil
|
212
|
+
still_executing = false
|
213
|
+
# or just continue?
|
214
|
+
else # it's a command, not an operator
|
215
|
+
current_operator = nil
|
216
|
+
previous_command_result = execute_command(flow_cmd)
|
217
|
+
end
|
218
|
+
previous_command = flow_cmd
|
219
|
+
else
|
220
|
+
#Morpheus::Logging::DarkPrinter.puts "operator skipped command: #{flow_cmd}" if Morpheus::Logging.debug?
|
221
|
+
end
|
222
|
+
# previous_command = flow_cmd
|
223
|
+
end
|
224
|
+
final_command_result = previous_command_result
|
225
|
+
end
|
226
|
+
else
|
227
|
+
# just one command, this else is not needed tho
|
228
|
+
final_command_result = execute_command(cmd)
|
229
|
+
end
|
179
230
|
end
|
180
231
|
# skip logging of exit and !cmd
|
181
232
|
unless input.strip.empty? || (["exit", "history"].include?(input.strip)) || input.strip[0].to_s.chr == "!"
|
182
233
|
log_history_command(input.strip)
|
183
234
|
end
|
235
|
+
return final_command_result
|
236
|
+
end
|
237
|
+
|
238
|
+
# returns Array of strings like [command1, operator, command2, operator, command3]
|
239
|
+
# eg. ["instances get 555", "||", "echo '%redInstance 555 is missing!'"]
|
240
|
+
def parse_commands_and_operators(input)
|
241
|
+
cmd = input
|
242
|
+
cmd_flow = []
|
243
|
+
begin
|
244
|
+
and_regex = /\s+\&\&\s+/
|
245
|
+
or_regex = /\s+\|\|\s+/
|
246
|
+
pipe_regex = /\s+\|\s+/
|
247
|
+
still_parsing = true
|
248
|
+
while still_parsing
|
249
|
+
and_index = cmd.index(and_regex)
|
250
|
+
or_index = cmd.index(or_regex)
|
251
|
+
pipe_index = cmd.index(pipe_regex)
|
252
|
+
if and_index # && (or_index == nil || or_index > and_index) && (pipe_index == nil || pipe_index > and_index)
|
253
|
+
cmd_flow << cmd[0..and_index-1]
|
254
|
+
cmd_flow << "&&"
|
255
|
+
cmd = cmd[and_index..-1].sub(and_regex, '')
|
256
|
+
elsif or_index && (and_index == nil || and_index > or_index) && (pipe_index == nil || pipe_index > or_index)
|
257
|
+
cmd_flow << cmd[0..or_index-1]
|
258
|
+
cmd_flow << "||"
|
259
|
+
cmd = cmd[or_index..-1].sub(or_regex, '')
|
260
|
+
elsif pipe_index && (and_index == nil || and_index > pipe_index) && (or_index == nil || or_index > pipe_index)
|
261
|
+
cmd_flow << cmd[0..pipe_index-1]
|
262
|
+
cmd_flow << "|"
|
263
|
+
cmd = cmd[pipe_index..-1].sub(pipe_regex, '')
|
264
|
+
else
|
265
|
+
cmd_flow << cmd
|
266
|
+
still_parsing = false
|
267
|
+
end
|
268
|
+
end
|
269
|
+
return cmd_flow
|
270
|
+
rescue => ex
|
271
|
+
puts_error "error parsing command flow: #{ex.message}"
|
272
|
+
return [input]
|
273
|
+
end
|
184
274
|
end
|
185
275
|
|
186
276
|
def execute_command(input)
|
@@ -219,21 +309,22 @@ class Morpheus::Cli::Shell
|
|
219
309
|
elsif input =~ /^\s*#/
|
220
310
|
Morpheus::Logging::DarkPrinter.puts "comment ignored" if Morpheus::Logging.debug?
|
221
311
|
return 0
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
312
|
+
# this is a full blown command now
|
313
|
+
# elsif input =~ /^sleep/
|
314
|
+
# sleep_sec = input.sub("sleep ", "").to_f
|
315
|
+
# if (!(sleep_sec > 0))
|
316
|
+
# # raise_command_error "sleep requires the argument [seconds]. eg. sleep 3.14"
|
317
|
+
# puts_error "sleep requires argument [seconds]. eg. sleep 3.14"
|
318
|
+
# return false
|
319
|
+
# end
|
320
|
+
# log_history_command(input)
|
321
|
+
# Morpheus::Logging::DarkPrinter.puts "sleeping for #{sleep_sec}s ... zzzZzzzZ" if Morpheus::Logging.debug?
|
322
|
+
# begin
|
323
|
+
# sleep(sleep_sec)
|
324
|
+
# rescue Interrupt
|
325
|
+
# Morpheus::Logging::DarkPrinter.puts "\nInterrupt. waking up from sleep early"
|
326
|
+
# end
|
327
|
+
# return 0
|
237
328
|
elsif input =~ /^history/
|
238
329
|
n_commands = input.sub(/^history\s?/, '').sub(/\-n\s?/, '')
|
239
330
|
n_commands = n_commands.empty? ? 25 : n_commands.to_i
|
@@ -374,28 +465,30 @@ class Morpheus::Cli::Shell
|
|
374
465
|
log_history_command(input)
|
375
466
|
return Morpheus::Cli::SourceCommand.new.handle(input.split[1..-1])
|
376
467
|
end
|
377
|
-
|
468
|
+
cmd_result = nil
|
378
469
|
begin
|
379
470
|
argv = Shellwords.shellsplit(input)
|
380
471
|
cmd_name = argv[0]
|
381
472
|
cmd_args = argv[1..-1]
|
382
473
|
if Morpheus::Cli::CliRegistry.has_command?(cmd_name) || Morpheus::Cli::CliRegistry.has_alias?(cmd_name)
|
383
474
|
#log_history_command(input)
|
384
|
-
Morpheus::Cli::CliRegistry.exec(cmd_name, cmd_args)
|
475
|
+
cmd_result = Morpheus::Cli::CliRegistry.exec(cmd_name, cmd_args)
|
385
476
|
else
|
386
477
|
puts_error "#{Morpheus::Terminal.angry_prompt}'#{cmd_name}' is not a morpheus command. Use 'help' to see the list of available commands."
|
387
478
|
@history_logger.warn "Unrecognized Command #{cmd_name}" if @history_logger
|
479
|
+
cmd_result = -1
|
388
480
|
end
|
389
481
|
rescue Interrupt
|
390
482
|
# nothing to do
|
391
483
|
@history_logger.warn "shell interrupt" if @history_logger
|
392
484
|
print "\nInterrupt. aborting command '#{input}'\n"
|
393
|
-
rescue SystemExit
|
485
|
+
rescue SystemExit => cmdexit
|
394
486
|
# nothing to do
|
395
487
|
# print "\n"
|
488
|
+
cmd_result = cmdexit.status
|
396
489
|
rescue => e
|
397
490
|
@history_logger.error "#{e.message}" if @history_logger
|
398
|
-
Morpheus::Cli::ErrorHandler.new(my_terminal.stderr).handle_error(e) # lol
|
491
|
+
cmd_result = Morpheus::Cli::ErrorHandler.new(my_terminal.stderr).handle_error(e) # lol
|
399
492
|
# exit 1
|
400
493
|
end
|
401
494
|
|
@@ -404,7 +497,12 @@ class Morpheus::Cli::Shell
|
|
404
497
|
::RestClient.log = Morpheus::Logging.debug? ? Morpheus::Logging::DarkPrinter.instance : nil
|
405
498
|
@return_to_log_level = nil
|
406
499
|
end
|
407
|
-
|
500
|
+
|
501
|
+
# commands should be a number or nil (treated as 0)
|
502
|
+
if cmd_result == true
|
503
|
+
cmd_result = 0
|
504
|
+
end
|
505
|
+
return cmd_result
|
408
506
|
end
|
409
507
|
|
410
508
|
end
|