morpheus-cli 4.2.16 → 4.2.17

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 (67) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +1 -1
  3. data/README.md +8 -6
  4. data/lib/morpheus/api/api_client.rb +32 -14
  5. data/lib/morpheus/api/auth_interface.rb +4 -2
  6. data/lib/morpheus/api/backup_jobs_interface.rb +9 -0
  7. data/lib/morpheus/api/backups_interface.rb +16 -0
  8. data/lib/morpheus/api/deploy_interface.rb +25 -56
  9. data/lib/morpheus/api/deployments_interface.rb +43 -54
  10. data/lib/morpheus/api/doc_interface.rb +57 -0
  11. data/lib/morpheus/api/instances_interface.rb +5 -0
  12. data/lib/morpheus/api/rest_interface.rb +40 -0
  13. data/lib/morpheus/api/user_sources_interface.rb +0 -15
  14. data/lib/morpheus/api/users_interface.rb +2 -3
  15. data/lib/morpheus/benchmarking.rb +2 -2
  16. data/lib/morpheus/cli.rb +3 -1
  17. data/lib/morpheus/cli/access_token_command.rb +27 -10
  18. data/lib/morpheus/cli/apps.rb +21 -15
  19. data/lib/morpheus/cli/backup_jobs_command.rb +276 -0
  20. data/lib/morpheus/cli/backups_command.rb +271 -0
  21. data/lib/morpheus/cli/boot_scripts_command.rb +1 -1
  22. data/lib/morpheus/cli/cli_command.rb +92 -41
  23. data/lib/morpheus/cli/clusters.rb +0 -18
  24. data/lib/morpheus/cli/commands/standard/benchmark_command.rb +7 -7
  25. data/lib/morpheus/cli/commands/standard/man_command.rb +1 -1
  26. data/lib/morpheus/cli/credentials.rb +13 -9
  27. data/lib/morpheus/cli/deploy.rb +374 -0
  28. data/lib/morpheus/cli/deployments.rb +521 -197
  29. data/lib/morpheus/cli/deploys.rb +271 -126
  30. data/lib/morpheus/cli/doc.rb +182 -0
  31. data/lib/morpheus/cli/error_handler.rb +23 -8
  32. data/lib/morpheus/cli/errors.rb +3 -2
  33. data/lib/morpheus/cli/image_builder_command.rb +2 -2
  34. data/lib/morpheus/cli/instances.rb +136 -17
  35. data/lib/morpheus/cli/invoices_command.rb +51 -38
  36. data/lib/morpheus/cli/library_layouts_command.rb +1 -1
  37. data/lib/morpheus/cli/login.rb +9 -3
  38. data/lib/morpheus/cli/mixins/accounts_helper.rb +158 -100
  39. data/lib/morpheus/cli/mixins/backups_helper.rb +115 -0
  40. data/lib/morpheus/cli/mixins/deployments_helper.rb +135 -0
  41. data/lib/morpheus/cli/mixins/option_source_helper.rb +1 -1
  42. data/lib/morpheus/cli/mixins/print_helper.rb +110 -74
  43. data/lib/morpheus/cli/mixins/provisioning_helper.rb +2 -2
  44. data/lib/morpheus/cli/mixins/whoami_helper.rb +19 -6
  45. data/lib/morpheus/cli/network_routers_command.rb +1 -1
  46. data/lib/morpheus/cli/option_parser.rb +48 -5
  47. data/lib/morpheus/cli/option_types.rb +1 -1
  48. data/lib/morpheus/cli/remote.rb +3 -2
  49. data/lib/morpheus/cli/roles.rb +49 -92
  50. data/lib/morpheus/cli/security_groups.rb +7 -1
  51. data/lib/morpheus/cli/service_plans_command.rb +10 -10
  52. data/lib/morpheus/cli/setup.rb +1 -1
  53. data/lib/morpheus/cli/shell.rb +7 -6
  54. data/lib/morpheus/cli/subnets_command.rb +1 -1
  55. data/lib/morpheus/cli/tenants_command.rb +133 -163
  56. data/lib/morpheus/cli/user_groups_command.rb +20 -65
  57. data/lib/morpheus/cli/user_settings_command.rb +115 -13
  58. data/lib/morpheus/cli/user_sources_command.rb +57 -24
  59. data/lib/morpheus/cli/users.rb +210 -186
  60. data/lib/morpheus/cli/version.rb +1 -1
  61. data/lib/morpheus/cli/whitelabel_settings_command.rb +29 -5
  62. data/lib/morpheus/cli/whoami.rb +113 -6
  63. data/lib/morpheus/cli/workflows.rb +1 -1
  64. data/lib/morpheus/ext/hash.rb +21 -0
  65. data/lib/morpheus/terminal.rb +1 -0
  66. metadata +12 -3
  67. data/lib/morpheus/cli/auth_command.rb +0 -105
@@ -1040,7 +1040,7 @@ class Morpheus::Cli::NetworkRoutersCommand
1040
1040
 
1041
1041
  begin
1042
1042
  if !is_master_account
1043
- print_red_alert "Permissions only available for master account"
1043
+ print_red_alert "Permissions only available for master tenant"
1044
1044
  return 1
1045
1045
  end
1046
1046
 
@@ -4,7 +4,11 @@ module Morpheus
4
4
  module Cli
5
5
 
6
6
  # an enhanced OptionParser
7
- # not used yet, maybe ever =o
7
+ # Modifications include
8
+ # * footer property to compliment banner with footer="Get details about a thing by ID."
9
+ # * hidden options with add_hidden_option "--not-in-help"
10
+ # * errors raised from parse! will have a reference to the parser itself.
11
+ # this is useful so you can you print the banner (usage) message in your error handling
8
12
  class Morpheus::Cli::OptionParser < OptionParser
9
13
 
10
14
  attr_accessor :footer
@@ -18,7 +22,7 @@ module Morpheus
18
22
  full_help_message
19
23
  end
20
24
 
21
- def full_help_message
25
+ def full_help_message(opts={})
22
26
  out = ""
23
27
  #out << original_to_s
24
28
  if banner
@@ -40,8 +44,15 @@ module Morpheus
40
44
  opt_description.to_s.strip.start_with?("--#{hidden_switch} ")
41
45
  end
42
46
  }
43
- if !is_hidden
44
- out << opt_description
47
+ if is_hidden
48
+ if opts[:show_hidden_options]
49
+ # out << opt_description + " (hidden)"
50
+ out << opt_description
51
+ else
52
+ # hidden
53
+ end
54
+ else
55
+ out << opt_description
45
56
  end
46
57
  end
47
58
  end
@@ -66,7 +77,39 @@ module Morpheus
66
77
  @hidden_options
67
78
  end
68
79
 
69
- end
80
+ # this needs mods too, but we dont use it...
81
+ # def parse
82
+ # end
70
83
 
84
+ def parse!(*args)
85
+ # it is actually # def parse(argv = default_argv, into: nil)
86
+ argv = [args].flatten() # args[0].flatten
87
+ #help_wanted = argv.find {|arg| arg == "--help" || arg == "-h" }
88
+ help_wanted = (argv.last == "--help" || argv.last == "-h") ? argv.last : nil
89
+ begin
90
+ return super(*args)
91
+ rescue OptionParser::ParseError => e
92
+ # last arg is --help
93
+ # maybe they just got the Try --help message and its on the end
94
+ # so strip all option arguments to avoid OptionParser::InvalidOption, etc.
95
+ # this is not ideal, it means you cannot pass these strings as the last argument to your command.
96
+ if help_wanted
97
+ argv = argv.reject {|arg| arg =~ /^\-+/ }
98
+ argv << help_wanted
99
+ return super(argv)
100
+ else
101
+ e.optparse = self
102
+ raise e
103
+ end
104
+
105
+ end
106
+ end
107
+ end
71
108
  end
72
109
  end
110
+
111
+ # ParseError is overridden to set parser reference.
112
+ # todo: dont monkey patch like this
113
+ class OptionParser::ParseError
114
+ attr_accessor :optparse
115
+ end
@@ -322,7 +322,7 @@ module Morpheus
322
322
  elsif option_type['optionSource']
323
323
  # calculate from inline lambda
324
324
  if option_type['optionSource'].is_a?(Proc)
325
- select_options = option_type['optionSource'].call()
325
+ select_options = option_type['optionSource'].call(api_client, grails_params(api_params || {}))
326
326
  elsif option_type['optionSource'] == 'list'
327
327
  # /api/options/list is a special action for custom OptionTypeLists, just need to pass the optionTypeId parameter
328
328
  select_options = load_source_options(option_type['optionSource'], api_client, {'optionTypeId' => option_type['id']})
@@ -44,7 +44,7 @@ class Morpheus::Cli::Remote
44
44
  current_only = false
45
45
  do_check = false
46
46
  optparse = Morpheus::Cli::OptionParser.new do|opts|
47
- opts.banner = subcommand_usage()
47
+ opts.banner = subcommand_usage("[search]")
48
48
  opts.on("-a",'--all', "Show all the appliance activity details") do
49
49
  show_all_activity = true
50
50
  options[:wrap] = true
@@ -61,8 +61,9 @@ List the configured remote appliances.
61
61
  EOT
62
62
  end
63
63
  optparse.parse!(args)
64
+ # verify_args!(args:args, optparse:optparse, count:0)
64
65
  if args.count > 0
65
- raise_command_error "wrong number of arguments, expected 0 and got (#{args.count}) #{args.join(' ')}\n#{optparse}"
66
+ options[:phrase] = args.join(" ")
66
67
  end
67
68
  #connect(options)
68
69
  params.merge!(parse_list_options(options))
@@ -12,6 +12,7 @@ class Morpheus::Cli::Roles
12
12
  include Morpheus::Cli::CliCommand
13
13
  include Morpheus::Cli::AccountsHelper
14
14
  include Morpheus::Cli::ProvisioningHelper
15
+ include Morpheus::Cli::WhoamiHelper
15
16
  register_subcommands :list, :get, :add, :update, :remove, :'list-permissions', :'update-feature-access', :'update-global-group-access', :'update-group-access', :'update-global-cloud-access', :'update-cloud-access', :'update-global-instance-type-access', :'update-instance-type-access', :'update-global-blueprint-access', :'update-blueprint-access'
16
17
  alias_subcommand :details, :get
17
18
  set_default_subcommand :list
@@ -37,36 +38,28 @@ class Morpheus::Cli::Roles
37
38
  def list(args)
38
39
  options = {}
39
40
  optparse = Morpheus::Cli::OptionParser.new do |opts|
40
- opts.banner = subcommand_usage()
41
- build_common_options(opts, options, [:list, :query, :json, :yaml, :csv, :fields, :dry_run, :remote])
41
+ opts.banner = subcommand_usage("[search phrase]")
42
+ build_standard_list_options(opts, options)
42
43
  opts.footer = "List roles."
43
44
  end
44
45
  optparse.parse!(args)
45
-
46
+ # verify_args!(args:args, optparse:optparse, count:0)
47
+ options[:phrase] = args.join(" ") if args.count > 0
46
48
  connect(options)
47
- begin
48
- account = find_account_from_options(options)
49
- account_id = account ? account['id'] : nil
50
-
51
- params = {}
52
- params.merge!(parse_list_options(options))
53
- @roles_interface.setopts(options)
54
- if options[:dry_run]
55
- print_dry_run @roles_interface.dry.list(account_id, params), options
56
- return
57
- end
58
- load_whoami()
59
- json_response = @roles_interface.list(account_id, params)
60
- if options[:json]
61
- puts as_json(json_response, options, "roles")
62
- return 0
63
- elsif options[:yaml]
64
- puts as_yaml(json_response, options, "roles")
65
- return 0
66
- elsif options[:csv]
67
- puts records_as_csv(json_response['roles'], options)
68
- return 0
69
- end
49
+
50
+ account = find_account_from_options(options)
51
+ account_id = account ? account['id'] : nil
52
+ params = {}
53
+ params.merge!(parse_list_options(options))
54
+ @roles_interface.setopts(options)
55
+ if options[:dry_run]
56
+ print_dry_run @roles_interface.dry.list(account_id, params), options
57
+ return 0, nil
58
+ end
59
+ load_whoami()
60
+ json_response = @roles_interface.list(account_id, params)
61
+
62
+ render_response(json_response, options, "roles") do
70
63
  roles = json_response['roles']
71
64
  title = "Morpheus Roles"
72
65
  subtitles = []
@@ -75,22 +68,20 @@ class Morpheus::Cli::Roles
75
68
  if roles.empty?
76
69
  print cyan,"No roles found.",reset,"\n"
77
70
  else
78
- print_roles_table(roles, options.merge({is_master_account: @is_master_account}))
71
+ print cyan
72
+ columns = @is_master_account ? role_column_definitions : subtenant_role_column_definitions
73
+ print as_pretty_table(roles, columns.upcase_keys!, options)
79
74
  print_results_pagination(json_response)
80
75
  end
81
76
  print reset,"\n"
82
- return 0
83
- rescue RestClient::Exception => e
84
- print_rest_exception(e, options)
85
- exit 1
86
77
  end
78
+ return 0, nil
87
79
  end
88
80
 
89
81
  def get(args)
90
82
  options = {}
91
- params = {}
92
83
  optparse = Morpheus::Cli::OptionParser.new do |opts|
93
- opts.banner = subcommand_usage("[name]")
84
+ opts.banner = subcommand_usage("[role]")
94
85
  opts.on('-p','--permissions', "Display Permissions") do |val|
95
86
  options[:include_feature_access] = true
96
87
  end
@@ -117,19 +108,26 @@ class Morpheus::Cli::Roles
117
108
  options[:include_instance_type_access] = true
118
109
  options[:include_blueprint_access] = true
119
110
  end
120
- build_common_options(opts, options, [:list, :query, :json, :yaml, :csv, :fields, :dry_run, :remote])
121
- opts.footer = "Get details about a role.\n" +
122
- "[name] is required. This is the name or id of a role."
111
+ build_standard_get_options(opts, options)
112
+ opts.footer = <<-EOT
113
+ Get details about a role.
114
+ [role] is required. This is the name (authority) or id of a role.
115
+ EOT
123
116
  end
124
117
  optparse.parse!(args)
125
-
126
- if args.count < 1
127
- puts optparse
128
- return 1
118
+ verify_args!(args:args, optparse:optparse, min:1)
119
+ connect(options)
120
+ id_list = parse_id_list(args)
121
+ return run_command_for_each_arg(id_list) do |arg|
122
+ _get(arg, options)
129
123
  end
124
+ end
130
125
 
131
- connect(options)
132
- begin
126
+ def _get(id, options={})
127
+ args = [id] # heh
128
+ params = {}
129
+
130
+
133
131
  account = find_account_from_options(options)
134
132
  account_id = account ? account['id'] : nil
135
133
 
@@ -150,7 +148,7 @@ class Morpheus::Cli::Roles
150
148
  # refetch from show action, argh
151
149
  # json_response = @roles_interface.get(account_id, role['id'])
152
150
  # role = json_response['role']
153
-
151
+ load_whoami()
154
152
  json_response = nil
155
153
  if args[0].to_s =~ /\A\d{1,}\Z/
156
154
  json_response = @roles_interface.get(account_id, args[0].to_i)
@@ -163,27 +161,13 @@ class Morpheus::Cli::Roles
163
161
  role = json_response['role']
164
162
  end
165
163
 
166
- render_result = render_with_format(json_response, options, 'role')
167
- return 0 if render_result
168
-
164
+ render_response(json_response, options, 'role') do
165
+
169
166
  print cyan
170
167
  print_h1 "Role Details", options
171
168
  print cyan
172
- description_cols = {
173
- "ID" => 'id',
174
- "Name" => 'authority',
175
- "Description" => 'description',
176
- "Scope" => lambda {|it| it['scope'] },
177
- "Type" => lambda {|it| format_role_type(it) },
178
- "Multitenant" => lambda {|it|
179
- format_boolean(it['multitenant']).to_s + (it['multitenantLocked'] ? " (LOCKED)" : "")
180
- },
181
- "Owner" => lambda {|it| role['owner'] ? role['owner']['name'] : '' },
182
- #"Account" => lambda {|it| it['account'] ? it['account']['name'] : '' },
183
- "Created" => lambda {|it| format_local_dt(it['dateCreated']) },
184
- "Updated" => lambda {|it| format_local_dt(it['lastUpdated']) }
185
- }
186
- print_description_list(description_cols, role)
169
+ columns = @is_master_account ? role_column_definitions : subtenant_role_column_definitions
170
+ print_description_list(columns, role, options)
187
171
 
188
172
  # print_h2 "Role Instance Limits", options
189
173
  # print cyan
@@ -310,13 +294,9 @@ class Morpheus::Cli::Roles
310
294
  # print "\n"
311
295
  # print cyan,bold,"Blueprint Access: #{get_access_string(json_response['globalAppTemplateAccess'])}",reset,"\n"
312
296
  end
313
-
314
297
  print reset,"\n"
315
- return 0
316
- rescue RestClient::Exception => e
317
- print_rest_exception(e, options)
318
- exit 1
319
298
  end
299
+ return 0, nil
320
300
  end
321
301
 
322
302
  def list_permissions(args)
@@ -328,14 +308,9 @@ class Morpheus::Cli::Roles
328
308
  "[role] is required. This is the name or id of a role."
329
309
  end
330
310
  optparse.parse!(args)
331
-
332
- if args.count < 1
333
- puts optparse
334
- return 1
335
- end
336
-
311
+ verify_args!(args:args, optparse:optparse, count:1)
337
312
  connect(options)
338
- begin
313
+
339
314
  account = find_account_from_options(options)
340
315
  account_id = account ? account['id'] : nil
341
316
 
@@ -406,14 +381,10 @@ class Morpheus::Cli::Roles
406
381
 
407
382
  print reset,"\n"
408
383
  return 0
409
- rescue RestClient::Exception => e
410
- print_rest_exception(e, options)
411
- exit 1
412
- end
384
+
413
385
  end
414
386
 
415
387
  def add(args)
416
- usage = "Usage: morpheus roles add [options]"
417
388
  options = {}
418
389
  params = {}
419
390
  optparse = Morpheus::Cli::OptionParser.new do |opts|
@@ -519,7 +490,6 @@ class Morpheus::Cli::Roles
519
490
  end
520
491
 
521
492
  def update(args)
522
- usage = "Usage: morpheus roles update [name] [options]"
523
493
  options = {}
524
494
  params = {}
525
495
  optparse = Morpheus::Cli::OptionParser.new do |opts|
@@ -599,7 +569,6 @@ class Morpheus::Cli::Roles
599
569
  end
600
570
 
601
571
  def remove(args)
602
- usage = "Usage: morpheus roles remove [name]"
603
572
  options = {}
604
573
  optparse = Morpheus::Cli::OptionParser.new do |opts|
605
574
  opts.banner = subcommand_usage("[name]")
@@ -1311,7 +1280,6 @@ class Morpheus::Cli::Roles
1311
1280
  ]
1312
1281
  end
1313
1282
 
1314
- "A Multitenant role is automatically copied into all existing subaccounts as well as placed into a subaccount when created. Useful for providing a set of predefined roles a Customer can use"
1315
1283
  def update_role_option_types
1316
1284
  add_role_option_types.reject {|it| ['roleType', 'baseRole'].include?(it['fieldName']) }
1317
1285
  end
@@ -1328,17 +1296,6 @@ class Morpheus::Cli::Roles
1328
1296
  end
1329
1297
  end
1330
1298
 
1331
-
1332
- def load_whoami
1333
- whoami_response = @whoami_interface.get()
1334
- @current_user = whoami_response["user"]
1335
- if @current_user.empty?
1336
- print_red_alert "Unauthenticated. Please login."
1337
- exit 1
1338
- end
1339
- @is_master_account = whoami_response["isMasterAccount"]
1340
- end
1341
-
1342
1299
  def role_type_options
1343
1300
  [{'name' => 'User Role', 'value' => 'user'}, {'name' => 'Account Role', 'value' => 'account'}]
1344
1301
  end
@@ -156,8 +156,8 @@ class Morpheus::Cli::SecurityGroups
156
156
  "Description" => 'description',
157
157
  "Scoped Cloud" => lambda {|it| it['zone'] ? it['zone']['name'] : 'All' },
158
158
  "Source" => lambda {|it| it['syncSource'] == 'external' ? 'SYNCED' : 'CREATED' },
159
- # "Active" => lambda {|it| format_boolean(it['active']) },
160
159
  "Visibility" => 'visibility',
160
+ "Active" => lambda {|it| format_boolean(it['active']) },
161
161
  "Tenants" => lambda {|it| it['tenants'] ? it['tenants'].collect {|it| it['name'] }.uniq.sort.join(', ') : '' },
162
162
  }
163
163
  print_description_list(description_cols, security_group)
@@ -295,6 +295,9 @@ class Morpheus::Cli::SecurityGroups
295
295
  opts.on('--visibility [private|public]', String, "Visibility") do |val|
296
296
  options['visibility'] = val
297
297
  end
298
+ opts.on('--active [on|off]', String, "Can be used to disable a security group") do |val|
299
+ options[:options]['active'] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == ''
300
+ end
298
301
  build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
299
302
  opts.footer = "Create a security group." + "\n" +
300
303
  "[name] is required. This is the name of the security group."
@@ -469,6 +472,9 @@ class Morpheus::Cli::SecurityGroups
469
472
  opts.on('--visibility [private|public]', String, "Visibility") do |val|
470
473
  options['visibility'] = val
471
474
  end
475
+ opts.on('--active [on|off]', String, "Can be used to disable a security group") do |val|
476
+ options[:options]['active'] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == ''
477
+ end
472
478
  build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
473
479
  opts.footer = "Update a security group." + "\n" +
474
480
  "[security-group] is required. This is the name or id of the security group."
@@ -650,13 +650,13 @@ class Morpheus::Cli::ServicePlanCommand
650
650
 
651
651
  if !plan
652
652
  print_red_alert "Service plan #{args[0]} not found"
653
- exit 1
653
+ return 1
654
654
  end
655
655
 
656
- if plan['active'] == true
657
- print_green_success "Service plan #{plan['name']} already actived."
658
- return 0
659
- end
656
+ # if plan['active'] == true
657
+ # print_green_success "Service plan #{plan['name']} already actived."
658
+ # return 0
659
+ # end
660
660
 
661
661
  unless options[:yes] || ::Morpheus::Cli::OptionTypes::confirm("Are you sure you would like to activate the service plan '#{plan['name']}'?", options)
662
662
  return 9, "aborted command"
@@ -704,13 +704,13 @@ class Morpheus::Cli::ServicePlanCommand
704
704
 
705
705
  if !plan
706
706
  print_red_alert "Service plan #{args[0]} not found"
707
- exit 1
707
+ return 1
708
708
  end
709
709
 
710
- if plan['active'] == false
711
- print_green_success "Service plan #{plan['name']} already deactived."
712
- return 0
713
- end
710
+ # if plan['active'] == false
711
+ # print_green_success "Service plan #{plan['name']} already deactivated."
712
+ # return 0
713
+ # end
714
714
 
715
715
  unless options[:yes] || ::Morpheus::Cli::OptionTypes::confirm("Are you sure you would like to deactivate the service plan '#{plan['name']}'?", options)
716
716
  return 9, "aborted command"
@@ -281,7 +281,7 @@ EOT
281
281
  #print cyan
282
282
  #puts "Initializing remote appliance at URL: #{@appliance_url}"
283
283
 
284
- # Master Account
284
+ # Master Tenant
285
285
  print_h2 "Create Master Tenant", options
286
286
  account_option_types = [
287
287
  {'fieldName' => 'accountName', 'fieldLabel' => 'Master Tenant Name', 'type' => 'text', 'required' => true, 'defaultValue' => (hub_info ? hub_info['companyName'] : nil), 'description' => 'A unique name for the Master Tenant (account).'},
@@ -507,16 +507,17 @@ class Morpheus::Cli::Shell
507
507
  return 0
508
508
 
509
509
  elsif ["hello","hi","hey","hola"].include?(input.strip.downcase)
510
+ user_msg = input.strip.downcase
510
511
  # need a logged_in? method already damnit
511
- #wallet = @wallet
512
512
  wallet = Morpheus::Cli::Credentials.new(@appliance_name, @appliance_url).load_saved_credentials
513
- if wallet
514
- # my_terminal.echo("#{input} %username!")
515
- # todo: this morning|afternoon|evening would be pleasant
516
- print "#{input} #{green}#{wallet['username']}#{reset}, how may I #{cyan}help#{reset} you?\n"
513
+ help_msg = case user_msg
514
+ when "hola"
515
+ "¿como puedo ayudarte? tratar #{cyan}help#{reset}"
517
516
  else
518
- print "#{input}, how may I #{cyan}help#{reset} you?\n"
517
+ "how may I #{cyan}help#{reset} you?"
519
518
  end
519
+ greeting = "#{user_msg.capitalize}#{wallet ? (' '+green+wallet['username'].to_s+reset) : ''}, #{help_msg}#{reset}"
520
+ puts greeting
520
521
  return 0
521
522
  elsif input.strip =~ /^shell\s*/
522
523
  # just allow shell to fall through