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
@@ -0,0 +1,126 @@
1
+ require 'fileutils'
2
+ require 'time'
3
+ require 'morpheus/cli/cli_registry'
4
+ require 'morpheus/logging'
5
+ require 'term/ansicolor'
6
+
7
+ class Morpheus::Cli::ConfigFile
8
+ include Term::ANSIColor
9
+ class << self
10
+ def init(filename=nil)
11
+ @instance ||= Morpheus::Cli::ConfigFile.new(filename)
12
+ end
13
+
14
+ def instance
15
+ #@instance ||= init(Morpheus::Cli.config_filename)
16
+ @instance or raise "#{self}.init() must be called!"
17
+ end
18
+
19
+ end
20
+
21
+ attr_reader :filename
22
+ attr_reader :config
23
+
24
+ def initialize(fn)
25
+ @config = {}
26
+ # only create the file if we're using the default, otherwise error
27
+ if fn
28
+ @filename = File.expand_path(fn)
29
+ else
30
+ @filename = File.expand_path(Morpheus::Cli.config_filename)
31
+ if !Dir.exists?(File.dirname(@filename))
32
+ FileUtils.mkdir_p(File.dirname(@filename))
33
+ end
34
+ if !File.exists?(@filename)
35
+ print "#{Term::ANSIColor.dark}Initializing default config file#{Term::ANSIColor.reset}\n" if Morpheus::Logging.debug?
36
+ FileUtils.touch(@filename)
37
+ save_file()
38
+ end
39
+ end
40
+ load_file()
41
+ end
42
+
43
+ def load_file
44
+ #puts "loading config #{@filename}"
45
+ @config = {}
46
+ if !@filename
47
+ return false
48
+ end
49
+ if !File.exist?(@filename)
50
+ raise "Morpheus cli config file not found: #{@filename}"
51
+ end
52
+ file_contents = File.read(@filename)
53
+ file_contents.split
54
+ config_text = File.open(@filename).read
55
+ config_lines = config_text.split(/\n/)
56
+ #config_lines = config_lines.reject {|line| line =~ /^\#/} # strip comments
57
+ config_lines.each_with_index do |line, line_index|
58
+ line_num = line_index + 1
59
+ line = line.strip
60
+ #puts "parsing config line #{line_num} : #{line}"
61
+ next if line.empty?
62
+ next if line =~ /^\#/ # skip comments
63
+
64
+ if line =~ /^alias\s+/
65
+ alias_name, command_string = Morpheus::Cli::CliRegistry.parse_alias_definition(line)
66
+ if alias_name.empty? || command_string.empty?
67
+ print "#{dark} #=> bad config line #{line_num} invalid alias definition: #{line}\n" if Morpheus::Logging.debug?
68
+ else
69
+ # @config[:aliases] ||= []
70
+ # @config[:aliases] << {name: alias_name, command: command_string}
71
+ begin
72
+ Morpheus::Cli::CliRegistry.instance.add_alias(alias_name, command_string)
73
+ rescue => err
74
+ print "#{dark} #=> #{err.message}#{reset}\n" if Morpheus::Logging.debug?
75
+ end
76
+ end
77
+ elsif line =~ /^colorize/
78
+ Term::ANSIColor::coloring = true
79
+ elsif line =~ /^uncolorize/
80
+ Term::ANSIColor::coloring = false
81
+ # what else shall we make configurable?
82
+ else
83
+ print "#{dark} #=> config line #{line_num} unrecognized: #{line}#{reset}\n" if Morpheus::Logging.debug?
84
+ end
85
+ end
86
+
87
+ # if @config[:aliases]
88
+ # @config[:aliases].each do |it|
89
+ # Morpheus::Cli::CliRegistry.instance.add_alias(it[:name], it[:command])
90
+ # end
91
+ # end
92
+
93
+ #puts "done loading config from #{}"
94
+
95
+ return @config
96
+ end
97
+
98
+ def save_file
99
+ if !@filename
100
+ print "#{Term::ANSIColor.dark}Skipping config file save because filename has not been set#{Term::ANSIColor.reset}\n" if Morpheus::Logging.debug?
101
+ return false
102
+ end
103
+ print "#{dark} #=> Saving config file #{@filename}#{reset}\n" if Morpheus::Logging.debug?
104
+ out = ""
105
+ out << "# .morpheusrc file #{@filename}"
106
+ out << "\n"
107
+ out << "# Auto-generated by morpheus #{Morpheus::Cli::VERSION} on #{Time.now.iso8601}"
108
+ out << "\n\n"
109
+ out << "# aliases"
110
+ out << "\n"
111
+ Morpheus::Cli::CliRegistry.instance.all_aliases.each do |k, v|
112
+ out << "alias #{k}='#{v}'"
113
+ out << "\n"
114
+ end
115
+ out << "\n"
116
+ File.open(@filename, 'w') {|f| f.write(out) }
117
+ return true
118
+ end
119
+
120
+ # this will load any local changes, and then resave everything in the config (shell)
121
+ def reload_file
122
+ load_file
123
+ save_file
124
+ end
125
+
126
+ end
@@ -1,134 +1,158 @@
1
+ require 'fileutils'
1
2
  require 'yaml'
3
+ require 'json'
2
4
  require 'io/console'
3
5
  require 'rest_client'
4
- #require 'optparse'
6
+ require 'morpheus/logging'
5
7
  require 'morpheus/cli/mixins/print_helper'
6
- require 'json'
7
8
 
8
9
  module Morpheus
9
- module Cli
10
- class Credentials
11
- include Morpheus::Cli::PrintHelper
10
+ module Cli
11
+ class Credentials
12
+ include Morpheus::Cli::PrintHelper
13
+
14
+ @@saved_credentials_map = nil
12
15
 
13
- def initialize(appliance_name, appliance_url)
14
- @appliance_url = appliance_url
15
- @appliance_name = appliance_name
16
- end
17
-
18
- def request_credentials(opts = {})
19
- username = nil
20
- password = nil
21
- creds = nil
22
- skip_save = false
23
- # We should return an access Key for Morpheus CLI Here
24
- if !opts[:remote_username].nil?
25
- username = opts[:remote_username]
26
- password = opts[:remote_password]
27
- skip_save = opts[:remote_url] ? true : false
28
- else
29
- creds = load_saved_credentials
30
- end
31
- if !creds
32
- print "\nEnter Morpheus Credentials for #{@appliance_name} - #{@appliance_url}\n\n",reset
33
- if username.nil? || username.empty?
34
- # print "Username: "
35
- print "Username: #{required_blue_prompt} "
36
- username = $stdin.gets.chomp!
37
- end
38
- if password.nil? || password.empty?
39
- # print "Password: "
40
- print "Password: #{required_blue_prompt} "
41
- password = STDIN.noecho(&:gets).chomp!
42
- print "\n"
43
- end
16
+ def initialize(appliance_name, appliance_url)
17
+ @appliance_url = appliance_url
18
+ @appliance_name = appliance_name
19
+ end
20
+
21
+ def request_credentials(opts = {})
22
+ #puts "request_credentials(#{opts})"
23
+ username = nil
24
+ password = nil
25
+ creds = nil
26
+ skip_save = false
27
+ # We should return an access Key for Morpheus CLI Here
28
+ if !opts[:remote_username].nil?
29
+ username = opts[:remote_username]
30
+ password = opts[:remote_password]
31
+ skip_save = opts[:remote_url] ? true : false
32
+ else
33
+ creds = load_saved_credentials
34
+ end
35
+ if creds
36
+ return creds
37
+ end
38
+ unless opts[:quiet] || opts[:no_prompt]
39
+ # if username.empty? || password.empty?
40
+ print "Enter Morpheus Credentials for #{display_appliance(@appliance_name, @appliance_url)}\n",reset
41
+ # end
42
+ if username.empty?
43
+ print "Username: #{required_blue_prompt} "
44
+ username = $stdin.gets.chomp!
45
+ else
46
+ print "Username: #{required_blue_prompt} #{username}\n"
47
+ end
48
+ if password.empty?
49
+ print "Password: #{required_blue_prompt} "
50
+ password = STDIN.noecho(&:gets).chomp!
51
+ print "\n"
52
+ else
53
+ print "Password: #{required_blue_prompt} \n"
54
+ end
55
+ end
56
+ if username.empty? || password.empty?
57
+ print_red_alert "Username and password are required to login."
58
+ return nil
59
+ end
60
+ begin
61
+ auth_interface = Morpheus::AuthInterface.new(@appliance_url)
62
+ json_response = auth_interface.login(username, password)
63
+ if opts[:json]
64
+ print JSON.pretty_generate(json_response)
65
+ print reset, "\n"
66
+ end
67
+ access_token = json_response['access_token']
68
+ if !access_token.empty?
69
+ unless skip_save
70
+ save_credentials(@appliance_name, access_token)
71
+ end
72
+ return access_token
73
+ else
74
+ print_red_alert "Credentials not verified."
75
+ return nil
76
+ end
77
+ rescue ::RestClient::Exception => e
78
+ #raise e
79
+ if (e.response && e.response.code == 400)
80
+ print_red_alert "Credentials not verified."
81
+ if opts[:json]
82
+ json_response = JSON.parse(e.response.to_s)
83
+ print JSON.pretty_generate(json_response)
84
+ print reset, "\n"
85
+ end
86
+ else
87
+ print_rest_exception(e, opts)
88
+ end
89
+ end
44
90
 
45
- oauth_url = File.join(@appliance_url, "/oauth/token")
46
- begin
47
- authorize_response = Morpheus::RestClient.execute(method: :post, url: oauth_url, headers:{ params: {grant_type: 'password', scope:'write', client_id: 'morph-cli', username: username}}, payload: {password: password},verify_ssl: false, timeout: 10)
91
+ end
48
92
 
49
- json_response = JSON.parse(authorize_response.to_s)
50
- access_token = json_response['access_token']
51
- if !access_token.empty?
52
- save_credentials(access_token) unless skip_save
53
- return access_token
54
- else
55
- print_red_alert "Credentials not verified."
56
- return nil
57
- end
58
- rescue ::RestClient::Exception => e
59
- if (e.response && e.response.code == 400)
60
- print_red_alert "Credentials not verified."
61
- if opts[:json]
62
- json_response = JSON.parse(e.response.to_s)
63
- print JSON.pretty_generate(json_response)
64
- print reset, "\n\n"
65
- end
66
- else
67
- print_rest_exception(e, opts)
68
- end
69
- exit 1
70
- rescue => e
71
- print_red_alert "Error Communicating with the Appliance. #{e}"
72
- exit 1
73
- end
74
- else
75
- return creds
76
- end
77
- end
93
+ def login(opts = {})
94
+ clear_saved_credentials(@appliance_name)
95
+ request_credentials(opts)
96
+ end
78
97
 
79
- def login(opts = {})
80
- clear_saved_credentials
81
- request_credentials(opts)
82
- end
98
+ def logout()
99
+ clear_saved_credentials(@appliance_name)
100
+ end
83
101
 
84
- def logout()
85
- clear_saved_credentials
86
- end
102
+ def clear_saved_credentials(appliance_name)
103
+ @@saved_credentials_map = load_credentials_file || {}
104
+ @@saved_credentials_map.delete(appliance_name)
105
+ print "#{dark} #=> updating credentials file #{credentials_file_path}#{reset}\n" if Morpheus::Logging.debug?
106
+ File.open(credentials_file_path, 'w') {|f| f.write @@saved_credentials_map.to_yaml } #Store
107
+ end
87
108
 
88
- def clear_saved_credentials()
89
- credential_map = load_credential_file
90
- if credential_map.nil?
91
- credential_map = {}
92
- end
93
- credential_map.delete(@appliance_name)
94
- File.open(credentials_file_path, 'w') {|f| f.write credential_map.to_yaml } #Store
95
- end
109
+ def load_saved_credentials(reload=false)
110
+ if saved_credentials_map && !reload
111
+ return saved_credentials_map
112
+ end
113
+ @@saved_credentials_map = load_credentials_file || {}
114
+ return @@saved_credentials_map[@appliance_name]
115
+ end
96
116
 
97
- def load_saved_credentials()
98
- credential_map = load_credential_file
99
- if credential_map.nil?
100
- return nil
101
- else
102
- return credential_map[@appliance_name]
103
- end
104
- end
117
+ # Provides the current credential information, simply :appliance_name => "access_token"
118
+ def saved_credentials_map
119
+ if !defined?(@@saved_credentials_map)
120
+ @@saved_credentials_map = load_credentials_file
121
+ end
122
+ return @@saved_credentials_map ? @@saved_credentials_map[@appliance_name.to_sym] : nil
123
+ end
105
124
 
106
- def load_credential_file
107
- creds_file = credentials_file_path
108
- if File.exist? creds_file
109
- return YAML.load_file(creds_file)
110
- else
111
- return nil
112
- end
113
- end
125
+ def load_credentials_file
126
+ fn = credentials_file_path
127
+ if File.exist? fn
128
+ print "#{dark} #=> loading credentials file #{fn}#{reset}\n" if Morpheus::Logging.debug?
129
+ return YAML.load_file(fn)
130
+ else
131
+ return nil
132
+ end
133
+ end
114
134
 
115
- def credentials_file_path
116
- home_dir = Dir.home
117
- morpheus_dir = File.join(home_dir,".morpheus")
118
- if !Dir.exist?(morpheus_dir)
119
- Dir.mkdir(morpheus_dir)
120
- end
121
- return File.join(morpheus_dir,"credentials")
122
- end
135
+ def credentials_file_path
136
+ File.join(Morpheus::Cli.home_directory, "credentials")
137
+ end
123
138
 
124
- def save_credentials(token)
125
- credential_map = load_credential_file
126
- if credential_map.nil?
127
- credential_map = {}
128
- end
129
- credential_map[@appliance_name] = token
130
- File.open(credentials_file_path, 'w') {|f| f.write credential_map.to_yaml } #Store
131
- end
132
- end
133
- end
139
+ def save_credentials(app_name, token)
140
+ # credential_map = saved_credentials_map
141
+ # reloading file is better for now, otherwise you can lose credentials with multiple shells.
142
+ credential_map = load_credentials_file || {}
143
+ if credential_map.nil?
144
+ credential_map = {}
145
+ end
146
+ credential_map[app_name] = token
147
+ begin
148
+ fn = credentials_file_path
149
+ print "#{dark} #=> adding credentials to #{fn}#{reset}\n" if Morpheus::Logging.debug?
150
+ File.open(fn, 'w') {|f| f.write credential_map.to_yaml } #Store
151
+ FileUtils.chmod(0600, fn)
152
+ rescue => e
153
+ puts "failed to save #{fn}. #{e}" if Morpheus::Logging.debug?
154
+ end
155
+ end
156
+ end
157
+ end
134
158
  end
@@ -4,70 +4,62 @@ require 'json'
4
4
 
5
5
  class Morpheus::Cli::DashboardCommand
6
6
  include Morpheus::Cli::CliCommand
7
-
8
- cli_command_name :dashboard
9
- cli_command_hidden # remove once this is done
10
-
11
- def initialize()
12
- @appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
13
- end
7
+ set_command_name :dashboard
8
+ set_command_hidden # remove once this is done
14
9
 
15
- def connect(opts)
16
- @access_token = Morpheus::Cli::Credentials.new(@appliance_name,@appliance_url).load_saved_credentials()
17
- if @access_token.empty?
18
- print_red_alert "Invalid Credentials. Unable to acquire access token. Please verify your credentials and try again."
19
- exit 1
20
- end
21
- @api_client = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url)
22
- @dashboard_interface = @api_client.dashboard
23
- end
10
+ def initialize()
11
+ # @appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
12
+ end
24
13
 
25
- def usage
26
- "Usage: morpheus dashboard"
27
- end
14
+ def connect(opts)
15
+ @api_client = establish_remote_appliance_connection(opts)
16
+ @dashboard_interface = @api_client.dashboard
17
+ end
28
18
 
29
- def handle(args)
30
- show(args)
31
- end
32
-
33
- def show(args)
34
- options = {}
35
- optparse = OptionParser.new do|opts|
36
- opts.banner = usage
37
- build_common_options(opts, options, [:json]) # todo: support :account
38
- end
39
- optparse.parse(args)
19
+ def usage
20
+ "Usage: morpheus #{command_name}"
21
+ end
40
22
 
41
- connect(options)
42
- begin
43
-
44
- params = {}
23
+ def handle(args)
24
+ show(args)
25
+ end
26
+
27
+ def show(args)
28
+ options = {}
29
+ optparse = OptionParser.new do|opts|
30
+ opts.banner = usage
31
+ build_common_options(opts, options, [:json, :dry_run]) # todo: support :account
32
+ end
33
+ optparse.parse!(args)
45
34
 
46
- json_response = @dashboard_interface.get(params)
47
-
48
- if options[:json]
49
- print JSON.pretty_generate(json_response)
50
- print "\n"
51
- else
52
-
35
+ connect(options)
36
+ begin
37
+ params = {}
38
+ if options[:dry_run]
39
+ print_dry_run @dashboard_interface.dry.get(params)
40
+ return
41
+ end
42
+ json_response = @dashboard_interface.get(params)
43
+ if options[:json]
44
+ print JSON.pretty_generate(json_response)
45
+ print "\n"
46
+ else
53
47
 
54
- # todo: impersonate command and show that info here
48
+ # todo: impersonate command and show that info here
55
49
 
56
- print "\n" ,cyan, bold, "Dashboard\n","==================", reset, "\n\n"
57
- print cyan
58
-
59
- print "\n"
60
- puts "Coming soon.... see --json"
61
- print "\n"
50
+ print "\n" ,cyan, bold, "Dashboard\n","==================", reset, "\n\n"
51
+ print cyan
52
+ print "\n"
53
+ puts "Coming soon.... see --json"
54
+ print "\n"
62
55
 
63
- print reset,"\n"
56
+ print reset,"\n"
64
57
 
65
- end
66
- rescue RestClient::Exception => e
67
- print_rest_exception(e, options)
68
- exit 1
69
- end
70
- end
71
-
58
+ end
59
+ rescue RestClient::Exception => e
60
+ print_rest_exception(e, options)
61
+ exit 1
62
+ end
63
+ end
72
64
 
73
65
  end