morpheus-cli 3.4.1.10 → 3.5.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 546db01c07f0ed59b7d0c6a78f5864e6dc123b00
4
- data.tar.gz: e4965c3651a6396c17a45481e03988cdf0edbb4b
2
+ SHA256:
3
+ metadata.gz: dd3b5e29881772dd9ef4e80eb5226176fa814c4661464f68ffe9249e0ccda99c
4
+ data.tar.gz: cdbca169540925cfa847c48c12aad367bd4626a733e2844323d6078f5d351a44
5
5
  SHA512:
6
- metadata.gz: 83cce232452557026284d972f1f123d7fd0e72e188ae9518913ab746e04964d144bd903b58dc28c4ee175e3d309e491cbedb1efb9c48089785ca90bcf2d1aa86
7
- data.tar.gz: c784eb91e5e4ff851d173c7682de04a7326329e1fc59d6fa8a9caf81abde6758af5915020368a54e3612176300192b94dcf48af653e0f8f4d74691ecb6d45201
6
+ metadata.gz: 1f094793c1f8e11ffc84c9dea26e2e094881efb22d5b0d71b65ed5d206df40b16e6fc80ddbdf6e028c12184749f485113aba555c2d6fd595c2643e1d6f8547cb
7
+ data.tar.gz: 4715322bcc111e6e82fa8fcd98e60b0123ebc50afd6b22a7719cc108cf36e2c02c095456e0fa3dad2800e0fb4b65724c9bbad668eed46e966d2db2389a5dec1d
@@ -295,4 +295,8 @@ class Morpheus::APIClient
295
295
  Morpheus::PackagesInterface.new(@access_token, @refresh_token, @expires_at, @base_url)
296
296
  end
297
297
 
298
+ def cypher
299
+ Morpheus::CypherInterface.new(@access_token, @refresh_token, @expires_at, @base_url)
300
+ end
301
+
298
302
  end
@@ -0,0 +1,55 @@
1
+ require 'morpheus/api/api_client'
2
+ require 'uri'
3
+
4
+ class Morpheus::CypherInterface < Morpheus::APIClient
5
+ def initialize(access_token, refresh_token,expires_at = nil, base_url=nil)
6
+ @access_token = access_token
7
+ @refresh_token = refresh_token
8
+ @base_url = base_url
9
+ @expires_at = expires_at
10
+ end
11
+
12
+ def get(id, params={})
13
+ raise "#{self.class}.get() passed a blank id!" if id.to_s == ''
14
+ url = "#{@base_url}/api/cypher/#{id}"
15
+ headers = { params: params, authorization: "Bearer #{@access_token}" }
16
+ opts = {method: :get, url: url, headers: headers}
17
+ execute(opts)
18
+ end
19
+
20
+ def list(params={})
21
+ url = "#{@base_url}/api/cypher"
22
+ headers = { params: params, authorization: "Bearer #{@access_token}" }
23
+ opts = {method: :get, url: url, headers: headers}
24
+ execute(opts)
25
+ end
26
+
27
+ def create(payload)
28
+ url = "#{@base_url}/api/cypher"
29
+ headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
30
+ opts = {method: :post, url: url, headers: headers, payload: payload.to_json}
31
+ execute(opts)
32
+ end
33
+
34
+ def update(id, payload)
35
+ url = "#{@base_url}/api/cypher/#{id}"
36
+ headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
37
+ opts = {method: :put, url: url, headers: headers, payload: payload.to_json}
38
+ execute(opts)
39
+ end
40
+
41
+ def destroy(id, params={})
42
+ url = "#{@base_url}/api/cypher/#{id}"
43
+ headers = { :params => params, :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
44
+ opts = {method: :delete, url: url, timeout: 30, headers: headers}
45
+ execute(opts)
46
+ end
47
+
48
+ def decrypt(id, params={})
49
+ url = "#{@base_url}/api/cypher/#{id}/decrypt"
50
+ headers = { params: params, authorization: "Bearer #{@access_token}" }
51
+ opts = {method: :get, url: url, headers: headers}
52
+ execute(opts)
53
+ end
54
+
55
+ end
@@ -1,4 +1,5 @@
1
1
  require 'morpheus/api/api_client'
2
+ require 'uri'
2
3
 
3
4
  class Morpheus::StorageProvidersInterface < Morpheus::APIClient
4
5
  def initialize(access_token, refresh_token,expires_at = nil, base_url=nil)
@@ -44,4 +45,116 @@ class Morpheus::StorageProvidersInterface < Morpheus::APIClient
44
45
  execute(opts)
45
46
  end
46
47
 
48
+ def list_files(id, file_path, params={})
49
+ if file_path.to_s.strip == "/"
50
+ file_path = ""
51
+ end
52
+ url = "#{@base_url}/api/storage/providers/#{URI.escape(id.to_s)}" + "/files/#{URI.escape(file_path)}".squeeze('/')
53
+ headers = { params: params, authorization: "Bearer #{@access_token}" }
54
+ opts = {method: :get, url: url, headers: headers}
55
+ execute(opts)
56
+ end
57
+
58
+ # upload a file without multipart
59
+ def upload_file(id, local_file, destination, params={})
60
+ # puts "upload_file #{local_file} to destination #{destination}"
61
+ # destination should be the full filePath, but the api looks like directory?filename=
62
+ path = destination.to_s.squeeze("/")
63
+ if !path || path == "" || path == "/" || path == "."
64
+ raise "#{self.class}.upload_file() passed a bad destination: '#{destination}'"
65
+ end
66
+ if path[0].chr == "/"
67
+ path = path[1..-1]
68
+ end
69
+ path_chunks = path.split("/")
70
+ filename = path_chunks.pop
71
+ safe_dirname = path_chunks.collect {|it| URI.escape(it) }.join("/")
72
+ # filename = File.basename(destination)
73
+ # dirname = File.dirname(destination)
74
+ # if filename == "" || filename == "/"
75
+ # filename = File.basename(local_file)
76
+ # end
77
+ url = "#{@base_url}/api/storage/providers/#{URI.escape(id.to_s)}" + "/files/#{safe_dirname}".squeeze('/')
78
+ headers = { :params => params, :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/octet-stream'}
79
+ headers[:params][:filename] = filename # File.basename(destination)
80
+ if !local_file.kind_of?(File)
81
+ local_file = File.new(local_file, 'rb')
82
+ end
83
+ payload = local_file
84
+ headers['Content-Length'] = local_file.size # File.size(local_file)
85
+ execute(method: :post, url: url, headers: headers, payload: payload)
86
+ end
87
+
88
+ def download_file(id, file_path, params={})
89
+ raise "#{self.class}.download_file() passed a blank id!" if id.to_s == ''
90
+ raise "#{self.class}.download_file() passed a blank file path!" if file_path.to_s == ''
91
+ escaped_file_path = file_path.split("/").collect {|it| URI.escape(it) }.join("/")
92
+ url = "#{@base_url}/api/storage/providers/#{URI.escape(id.to_s)}" + "/download-file/#{escaped_file_path}".squeeze('/')
93
+ headers = { params: params, authorization: "Bearer #{@access_token}" }
94
+ opts = {method: :get, url: url, headers: headers}
95
+ execute(opts, false)
96
+ end
97
+
98
+ def download_file_chunked(id, file_path, outfile, params={})
99
+ raise "#{self.class}.download_file() passed a blank id!" if id.to_s == ''
100
+ raise "#{self.class}.download_file() passed a blank file path!" if file_path.to_s == ''
101
+ escaped_file_path = file_path.split("/").collect {|it| URI.escape(it) }.join("/")
102
+ url = "#{@base_url}/api/storage/providers/#{URI.escape(id.to_s)}" + "/download-file/#{escaped_file_path}".squeeze('/')
103
+ headers = { params: params, authorization: "Bearer #{@access_token}" }
104
+ opts = {method: :get, url: url, headers: headers}
105
+ # execute(opts, false)
106
+ if Dir.exists?(outfile)
107
+ raise "outfile is invalid. It is the name of an existing directory: #{outfile}"
108
+ end
109
+ # if @verify_ssl == false
110
+ # opts[:verify_ssl] = OpenSSL::SSL::VERIFY_NONE
111
+ # end
112
+ if @dry_run
113
+ return opts
114
+ end
115
+ http_response = nil
116
+ File.open(outfile, 'w') {|f|
117
+ block = proc { |response|
118
+ response.read_body do |chunk|
119
+ # writing to #{outfile} ..."
120
+ f.write chunk
121
+ end
122
+ }
123
+ opts[:block_response] = block
124
+ http_response = RestClient::Request.new(opts).execute
125
+ # RestClient::Request.execute(opts)
126
+ }
127
+ return http_response
128
+ end
129
+
130
+ def download_zip_chunked(id, outfile, params={})
131
+ #url = "#{@base_url}/api/storage/providers/#{URI.escape(id.to_s)}" + ".zip"
132
+ url = "#{@base_url}/api/storage/providers/#{URI.escape(id.to_s)}/download-zip"
133
+ headers = { params: params, authorization: "Bearer #{@access_token}" }
134
+ opts = {method: :get, url: url, headers: headers}
135
+ # execute(opts, false)
136
+ if Dir.exists?(outfile)
137
+ raise "outfile is invalid. It is the name of an existing directory: #{outfile}"
138
+ end
139
+ # if @verify_ssl == false
140
+ # opts[:verify_ssl] = OpenSSL::SSL::VERIFY_NONE
141
+ # end
142
+ if @dry_run
143
+ return opts
144
+ end
145
+ http_response = nil
146
+ File.open(outfile, 'w') {|f|
147
+ block = proc { |response|
148
+ response.read_body do |chunk|
149
+ # writing to #{outfile} ..."
150
+ f.write chunk
151
+ end
152
+ }
153
+ opts[:block_response] = block
154
+ http_response = RestClient::Request.new(opts).execute
155
+ # RestClient::Request.execute(opts)
156
+ }
157
+ return http_response
158
+ end
159
+
47
160
  end
@@ -138,6 +138,7 @@ module Morpheus
138
138
  load 'morpheus/cli/network_pool_servers_command.rb'
139
139
  load 'morpheus/cli/network_domains_command.rb'
140
140
  load 'morpheus/cli/network_proxies_command.rb'
141
+ load 'morpheus/cli/cypher_command.rb'
141
142
  load 'morpheus/cli/image_builder_command.rb'
142
143
  load 'morpheus/cli/preseed_scripts_command.rb'
143
144
  load 'morpheus/cli/boot_scripts_command.rb'
@@ -820,7 +820,6 @@ class Morpheus::Cli::ArchivesCommand
820
820
  groups_str = owner_str
821
821
  end
822
822
  end
823
- groups_str =
824
823
  file_info << truncate_string(groups_str, 15).ljust(15, " ")
825
824
  # File Type
826
825
  content_type = archive_file['contentType'].to_s
@@ -848,7 +847,7 @@ class Morpheus::Cli::ArchivesCommand
848
847
  mtime = format_local_dt(last_updated, {format: "%b %e %Y"})
849
848
  end
850
849
  end
851
- file_info << mtime # .ljust(21, " ")
850
+ file_info << mtime.ljust(12, " ")
852
851
  if params[:fullTree]
853
852
  file_info << file_color + archive_file["filePath"].to_s + cyan
854
853
  else
@@ -871,7 +870,7 @@ class Morpheus::Cli::ArchivesCommand
871
870
  if do_one_file_per_line
872
871
  print file_names.join("\n")
873
872
  else
874
- print file_names.join(" ")
873
+ print file_names.join("\t")
875
874
  end
876
875
  print "\n"
877
876
  end
@@ -1287,11 +1286,11 @@ class Morpheus::Cli::ArchivesCommand
1287
1286
  if options[:dry_run]
1288
1287
  # print_dry_run @archive_files_interface.dry.download_file_by_path(full_file_path), full_command_string
1289
1288
  if use_public_url
1290
- print_dry_run @archive_files_interface.dry.download_file_by_path_chunked(full_file_path, outfile), full_command_string
1291
- else
1292
1289
  print_dry_run @archive_files_interface.dry.download_public_file_by_path_chunked(full_file_path, outfile), full_command_string
1290
+ else
1291
+ print_dry_run @archive_files_interface.dry.download_file_by_path_chunked(full_file_path, outfile), full_command_string
1293
1292
  end
1294
- return 1
1293
+ return 0
1295
1294
  end
1296
1295
  if !options[:quiet]
1297
1296
  print cyan + "Downloading archive file #{bucket_id}:#{file_path} to #{outfile} ... "
@@ -318,7 +318,16 @@ module Morpheus
318
318
  k, v = k.split(":")
319
319
  end
320
320
  if (!k.to_s.empty?)
321
- options[:query_filters][k.to_s.strip] = v.to_s.strip
321
+ if options[:query_filters].key?(k.to_s.strip)
322
+ cur_val = options[:query_filters][k.to_s.strip]
323
+ if cur_val.instance_of?(Array)
324
+ options[:query_filters][k.to_s.strip] << v.to_s.strip
325
+ else
326
+ options[:query_filters][k.to_s.strip] = [cur_val, v.to_s.strip]
327
+ end
328
+ else
329
+ options[:query_filters][k.to_s.strip] = v.to_s.strip
330
+ end
322
331
  end
323
332
  end
324
333
  end
@@ -198,6 +198,7 @@ class Morpheus::Cli::Clouds
198
198
  "Location" => 'location',
199
199
  "Visibility" => lambda {|it| it['visibility'].to_s.capitalize },
200
200
  "Groups" => lambda {|it| it['groups'].collect {|g| g.instance_of?(Hash) ? g['name'] : g.to_s }.join(', ') },
201
+ "Enabled" => lambda {|it| format_boolean(it['enabled']) },
201
202
  "Status" => lambda {|it| format_cloud_status(it) }
202
203
  }
203
204
  print_description_list(description_cols, cloud)
@@ -0,0 +1,412 @@
1
+ require 'json'
2
+ require 'yaml'
3
+ require 'table_print'
4
+ require 'morpheus/cli/cli_command'
5
+
6
+ class Morpheus::Cli::CypherCommand
7
+ include Morpheus::Cli::CliCommand
8
+
9
+ set_command_name :cypher
10
+
11
+ register_subcommands :list, :get, :add, :remove, :decrypt
12
+
13
+ def initialize()
14
+ # @appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
15
+ end
16
+
17
+ def connect(opts)
18
+ @api_client = establish_remote_appliance_connection(opts)
19
+ @cypher_interface = @api_client.cypher
20
+ end
21
+
22
+ def handle(args)
23
+ handle_subcommand(args)
24
+ end
25
+
26
+ def list(args)
27
+ options = {}
28
+ params = {}
29
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
30
+ opts.banner = subcommand_usage()
31
+ build_common_options(opts, options, [:list, :query, :json, :yaml, :csv, :fields, :json, :dry_run, :remote])
32
+ opts.footer = "List cypher items."
33
+ end
34
+ optparse.parse!(args)
35
+ connect(options)
36
+ begin
37
+ params.merge!(parse_list_options(options))
38
+ if options[:dry_run]
39
+ print_dry_run @cypher_interface.dry.list(params)
40
+ return 0
41
+ end
42
+ json_response = @cypher_interface.list(params)
43
+ cypher_items = json_response["cyphers"]
44
+ if options[:json]
45
+ puts as_json(json_response, options, "cyphers")
46
+ return 0
47
+ elsif options[:yaml]
48
+ puts as_yaml(json_response, options, "cyphers")
49
+ return 0
50
+ elsif options[:csv]
51
+ puts records_as_csv(cypher_items, options)
52
+ return 0
53
+ end
54
+ title = "Morpheus Cypher List"
55
+ subtitles = []
56
+ subtitles += parse_list_subtitles(options)
57
+ print_h1 title, subtitles
58
+ if cypher_items.empty?
59
+ print cyan,"No cypher items found.",reset,"\n"
60
+ else
61
+ cypher_columns = {
62
+ "ID" => 'id',
63
+ "KEY" => lambda {|it| it["itemKey"] || it["key"] },
64
+ "LEASE REMAINING" => lambda {|it| it['expireDate'] ? format_local_dt(it['expireDate']) : "" },
65
+ "DATED CREATED" => lambda {|it| format_local_dt(it["dateCreated"]) },
66
+ "LAST ACCESSED" => lambda {|it| format_local_dt(it["lastAccessed"]) }
67
+ }
68
+ if options[:include_fields]
69
+ cypher_columns = options[:include_fields]
70
+ end
71
+ print cyan
72
+ print as_pretty_table(cypher_items, cypher_columns, options)
73
+ print reset
74
+ print_results_pagination(json_response)
75
+ end
76
+ print reset,"\n"
77
+ return 0
78
+ rescue RestClient::Exception => e
79
+ print_rest_exception(e, options)
80
+ exit 1
81
+ end
82
+ end
83
+
84
+ def get(args)
85
+ options = {}
86
+ do_decrypt = false
87
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
88
+ opts.banner = subcommand_usage("[id]")
89
+ opts.on(nil, '--decrypt', 'Display the decrypted value') do
90
+ do_decrypt = true
91
+ end
92
+ build_common_options(opts, options, [:json, :yaml, :csv, :fields, :dry_run, :remote])
93
+ opts.footer = "Get details about a cypher." + "\n" +
94
+ "[id] is required. This is the id or key of a cypher."
95
+ end
96
+ optparse.parse!(args)
97
+ if args.count != 1
98
+ print_error Morpheus::Terminal.angry_prompt
99
+ puts_error "wrong number of arguments, expected 1 and got #{args.count}\n#{optparse}"
100
+ return 1
101
+ end
102
+ connect(options)
103
+ begin
104
+ if options[:dry_run]
105
+ if args[0].to_s =~ /\A\d{1,}\Z/
106
+ print_dry_run @cypher_interface.dry.get(args[0].to_i)
107
+ else
108
+ print_dry_run @cypher_interface.dry.list({name:args[0]})
109
+ end
110
+ return
111
+ end
112
+ cypher_item = find_cypher_by_name_or_id(args[0])
113
+ return 1 if cypher_item.nil?
114
+ json_response = {'cypher' => cypher_item} # skip redundant request
115
+ decrypt_json_response = nil
116
+ if do_decrypt
117
+ decrypt_json_response = @cypher_interface.decrypt(cypher_item["id"])
118
+ end
119
+ # json_response = @cypher_interface.get(cypher_item['id'])
120
+ cypher_item = json_response['cypher']
121
+ if options[:json]
122
+ puts as_json(json_response, options, "cypher")
123
+ return 0
124
+ elsif options[:yaml]
125
+ puts as_yaml(json_response, options, "cypher")
126
+ return 0
127
+ elsif options[:csv]
128
+ puts records_as_csv([cypher_item], options)
129
+ return 0
130
+ end
131
+ print_h1 "Cypher Details"
132
+ print cyan
133
+ description_cols = {
134
+ "ID" => 'id',
135
+ # what here
136
+ "Key" => lambda {|it| it["itemKey"] },
137
+ #"Value" => lambda {|it| it["value"] || "************" },
138
+ "Lease Remaining" => lambda {|it| format_local_dt(it["expireDate"]) },
139
+ "Date Created" => lambda {|it| format_local_dt(it["dateCreated"]) },
140
+ "Last Accessed" => lambda {|it| format_local_dt(it["lastAccessed"]) }
141
+ }
142
+ print_description_list(description_cols, cypher_item)
143
+ if decrypt_json_response
144
+ print_h2 "Decrypted Value"
145
+ print cyan
146
+ puts decrypt_json_response["cypher"] ? decrypt_json_response["cypher"]["itemValue"] : ""
147
+ end
148
+ print reset, "\n"
149
+
150
+ return 0
151
+ rescue RestClient::Exception => e
152
+ print_rest_exception(e, options)
153
+ return 1
154
+ end
155
+ end
156
+
157
+ def decrypt(args)
158
+ params = {}
159
+ options = {}
160
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
161
+ opts.banner = subcommand_usage("[id]")
162
+ build_common_options(opts, options, [:json, :yaml, :csv, :fields, :dry_run, :remote])
163
+ opts.footer = "Decrypt the value of a cypher." + "\n" +
164
+ "[id] is required. This is the id or key of a cypher."
165
+ end
166
+ optparse.parse!(args)
167
+ if args.count != 1
168
+ print_error Morpheus::Terminal.angry_prompt
169
+ puts_error "wrong number of arguments, expected 1 and got #{args.count}\n#{optparse}"
170
+ return 1
171
+ end
172
+ connect(options)
173
+ begin
174
+ cypher_item = find_cypher_by_name_or_id(args[0])
175
+ return 1 if cypher_item.nil?
176
+ if options[:dry_run]
177
+ print_dry_run @cypher_interface.dry.decrypt(cypher_item["id"], params)
178
+ return
179
+ end
180
+
181
+ cypher_item = find_cypher_by_name_or_id(args[0])
182
+ return 1 if cypher_item.nil?
183
+
184
+ json_response = @cypher_interface.decrypt(cypher_item["id"], params)
185
+ if options[:json]
186
+ puts as_json(json_response, options, "cypher")
187
+ return 0
188
+ elsif options[:yaml]
189
+ puts as_yaml(json_response, options, "cypher")
190
+ return 0
191
+ elsif options[:csv]
192
+ puts records_as_csv([json_response["crypt"]], options)
193
+ return 0
194
+ end
195
+ print_h1 "Cypher Decrypt"
196
+ print cyan
197
+ print_description_list({
198
+ "ID" => 'id',
199
+ "Key" => lambda {|it| it["itemKey"] },
200
+ "Value" => lambda {|it| it["itemValue"] }
201
+ }, json_response["cypher"])
202
+ print reset, "\n"
203
+ return 0
204
+ rescue RestClient::Exception => e
205
+ print_rest_exception(e, options)
206
+ return 1
207
+ end
208
+ end
209
+
210
+ def add(args)
211
+ options = {}
212
+ params = {}
213
+
214
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
215
+ opts.banner = subcommand_usage()
216
+ opts.on('--key VALUE', String, "Key for this cypher") do |val|
217
+ params['itemKey'] = val
218
+ end
219
+ build_common_options(opts, options, [:options, :payload, :json, :dry_run, :quiet, :remote])
220
+ opts.footer = "Create a new cypher."
221
+ end
222
+ optparse.parse!(args)
223
+ if args.count > 1
224
+ print_error Morpheus::Terminal.angry_prompt
225
+ puts_error "wrong number of arguments, expected 0-1 and got #{args.count}\n#{optparse}"
226
+ return 1
227
+ end
228
+ connect(options)
229
+ begin
230
+ payload = nil
231
+ if options[:payload]
232
+ payload = options[:payload]
233
+ else
234
+ # merge -O options into normally parsed options
235
+ params.deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol) }) if options[:options] && options[:options].keys.size > 0
236
+
237
+ # support [key] as first argument
238
+ if args[0]
239
+ params['itemKey'] = args[0]
240
+ end
241
+ # Key
242
+ if !params['itemKey']
243
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'itemKey', 'fieldLabel' => 'Key', 'type' => 'text', 'required' => true, 'description' => cypher_key_help}], options)
244
+ params['itemKey'] = v_prompt['itemKey']
245
+ end
246
+
247
+ # Value
248
+ value_is_required = false
249
+ cypher_mount_type = params['itemKey'].split("/").first
250
+ if cypher_mount_type == ["secret", "password"].include?(cypher_mount_type)
251
+ value_is_required = true
252
+ end
253
+
254
+ if !params['itemValue']
255
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'itemValue', 'fieldLabel' => 'Value', 'type' => 'text', 'required' => value_is_required, 'description' => "Value for this cypher"}], options)
256
+ params['itemValue'] = v_prompt['itemValue']
257
+ end
258
+
259
+ # Lease
260
+ if !params['leaseTimeout']
261
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'leaseTimeout', 'fieldLabel' => 'Lease', 'type' => 'text', 'required' => false, 'description' => cypher_lease_help}], options)
262
+ params['leaseTimeout'] = v_prompt['leaseTimeout']
263
+ end
264
+ if !params['leaseTimeout'].to_s.empty?
265
+ params['leaseTimeout'] = params['leaseTimeout'].to_i
266
+ end
267
+
268
+ # construct payload
269
+ payload = {
270
+ 'cypher' => params
271
+ }
272
+ end
273
+
274
+ if options[:dry_run]
275
+ print_dry_run @cypher_interface.dry.create(payload)
276
+ return
277
+ end
278
+ json_response = @cypher_interface.create(payload)
279
+ if options[:json]
280
+ print JSON.pretty_generate(json_response)
281
+ print "\n"
282
+ elsif !options[:quiet]
283
+ print_green_success "Added cypher"
284
+ # list([])
285
+ cypher_item = json_response['cypher']
286
+ get([cypher_item['id']])
287
+ end
288
+ return 0
289
+ rescue RestClient::Exception => e
290
+ print_rest_exception(e, options)
291
+ exit 1
292
+ end
293
+ end
294
+
295
+ # def update(args)
296
+ # end
297
+
298
+ # def decrypt(args)
299
+ # end
300
+
301
+ def remove(args)
302
+ options = {}
303
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
304
+ opts.banner = subcommand_usage("[id]")
305
+ build_common_options(opts, options, [:account, :auto_confirm, :json, :dry_run, :quiet, :remote])
306
+ opts.footer = "Delete a cypher." + "\n" +
307
+ "[id] is required. This is the id or key of a cypher."
308
+ end
309
+ optparse.parse!(args)
310
+
311
+ if args.count != 1
312
+ print_error Morpheus::Terminal.angry_prompt
313
+ puts_error "wrong number of arguments, expected 1 and got #{args.count}\n#{optparse}"
314
+ return 1
315
+ end
316
+
317
+ connect(options)
318
+ begin
319
+ cypher_item = find_cypher_by_name_or_id(args[0])
320
+ return 1 if cypher_item.nil?
321
+ unless options[:yes] || Morpheus::Cli::OptionTypes.confirm("Are you sure you want to delete the cypher #{cypher_item['itemKey']}?")
322
+ return 9, "aborted command"
323
+ end
324
+ if options[:dry_run]
325
+ print_dry_run @cypher_interface.dry.destroy(cypher_item["id"])
326
+ return
327
+ end
328
+ json_response = @cypher_interface.destroy(cypher_item["id"])
329
+ if options[:json]
330
+ print JSON.pretty_generate(json_response)
331
+ print "\n"
332
+ elsif !options[:quiet]
333
+ print_green_success "Deleted cypher #{cypher_item['itemKey']}"
334
+ # list([])
335
+ end
336
+ return 0
337
+ rescue RestClient::Exception => e
338
+ print_rest_exception(e, options)
339
+ return 1
340
+ end
341
+ end
342
+
343
+ private
344
+
345
+ def find_cypher_by_name_or_id(val)
346
+ if val.to_s =~ /\A\d{1,}\Z/
347
+ return find_cypher_by_id(val)
348
+ else
349
+ return find_cypher_by_name(val)
350
+ end
351
+ end
352
+
353
+ def find_cypher_by_id(id)
354
+ begin
355
+
356
+ json_response = @cypher_interface.get(id.to_i)
357
+ return json_response['cypher']
358
+ rescue RestClient::Exception => e
359
+ if e.response && e.response.code == 404
360
+ print_red_alert "Cypher not found by id #{id}"
361
+ return nil
362
+ else
363
+ raise e
364
+ end
365
+ end
366
+ end
367
+
368
+ def find_cypher_by_name(name)
369
+ # api supports name as alias for itemKey
370
+ json_response = @cypher_interface.list({name: name.to_s})
371
+
372
+ cypher_items = json_response['cyphers']
373
+ if cypher_items.empty?
374
+ print_red_alert "Cypher not found by name #{name}"
375
+ return nil
376
+ elsif cypher_items.size > 1
377
+ print_red_alert "#{cypher_items.size} cyphers found by name #{name}"
378
+ rows = cypher_items.collect do |cypher_item|
379
+ {id: cypher_item['id'], name: cypher_item['name']}
380
+ end
381
+ print red
382
+ print as_pretty_table(rows, [:id, :name])
383
+ print reset,"\n"
384
+ return nil
385
+ else
386
+ return cypher_items[0]
387
+ end
388
+ end
389
+
390
+ def cypher_key_help
391
+ """
392
+ Keys can have different behaviors depending on the specified mountpoint.
393
+ Available Mountpoints:
394
+ password - Generates a secure password of specified character length in the key pattern (or 15) with symbols, numbers, upper case, and lower case letters (i.e. password/15/mypass generates a 15 character password).
395
+ tfvars - This is a module to store a tfvars file for terraform.
396
+ secret - This is the standard secret module that stores a key/value in encrypted form.
397
+ uuid - Returns a new UUID by key name when requested and stores the generated UUID by key name for a given lease timeout period.
398
+ key - Generates a Base 64 encoded AES Key of specified bit length in the key pattern (i.e. key/128/mykey generates a 128-bit key)"""
399
+ end
400
+
401
+ def cypher_lease_help
402
+ """
403
+ Lease time in MS (defaults to 32 days)
404
+ Quick MS Time Reference:
405
+ Day: 86400000
406
+ Week: 604800000
407
+ Month (30 days): 2592000000
408
+ Year: 31536000000"""
409
+ end
410
+
411
+ end
412
+