morpheus-cli 4.2.16 → 4.2.17

Sign up to get free protection for your applications and to get access to all the features.
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