enfcli 4.1.0.pre.beta → 5.0.1

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.
@@ -0,0 +1,95 @@
1
+ #
2
+ # Copyright 2020 Xaptum,Inc
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+ module EnfApi
17
+ class Dns
18
+ include Singleton
19
+
20
+ def initialize
21
+ @version = "v1"
22
+ @xdns_base_url = "/api/xdns/#{@version}"
23
+ end
24
+
25
+ def list_zones(domain)
26
+ EnfApi::API.instance.get "#{@xdns_base_url}/zones?enf_domain=#{domain}"
27
+ end
28
+
29
+ def create_dns_zone(new_zone)
30
+ json = EnfApi::to_json(new_zone)
31
+ EnfApi::API.instance.post "#{@xdns_base_url}/zones", json
32
+ end
33
+
34
+ def update_dns_zone(zone_id, updated_zone)
35
+ json = EnfApi::to_json(updated_zone)
36
+ EnfApi::API.instance.put "#{@xdns_base_url}/zones/#{zone_id}", json
37
+ end
38
+
39
+ def delete_dns_zone(zone_id)
40
+ EnfApi::API.instance.delete "#{@xdns_base_url}/zones/#{zone_id}"
41
+ end
42
+
43
+ def add_networks_to_zone(zone_id, add_networks)
44
+ json = EnfApi::to_json(add_networks)
45
+ EnfApi::API.instance.post "#{@xdns_base_url}/zones/#{zone_id}/networks", json
46
+ end
47
+
48
+ def replace_networks_in_zone(zone_id, replace_networks)
49
+ json = EnfApi::to_json(replace_networks)
50
+ EnfApi::API.instance.put "#{@xdns_base_url}/zones/#{zone_id}/networks", json
51
+ end
52
+
53
+ def list_networks_in_zone(zone_id)
54
+ EnfApi::API.instance.get "#{@xdns_base_url}/zones/#{zone_id}/networks"
55
+ end
56
+
57
+ def delete_networks_from_zone(zone_id, delete_networks)
58
+ EnfApi::API.instance.delete "#{@xdns_base_url}/zones/#{zone_id}/networks?delete=#{delete_networks}"
59
+ end
60
+
61
+ def list_zones_in_network(network)
62
+ EnfApi::API.instance.get "#{@xdns_base_url}/networks/#{network}/zones"
63
+ end
64
+
65
+ def provision_server(network, new_server)
66
+ json = EnfApi::to_json(new_server)
67
+ EnfApi::API.instance.post "#{@xdns_base_url}/networks/#{network}/servers", json
68
+ end
69
+
70
+ def list_servers(network)
71
+ EnfApi::API.instance.get "#{@xdns_base_url}/networks/#{network}/servers"
72
+ end
73
+
74
+ def delete_server(network, server_ipv6)
75
+ EnfApi::API.instance.delete "#{@xdns_base_url}/networks/#{network}/servers/#{server_ipv6}"
76
+ end
77
+
78
+ def create_dns_record(zone_id, new_record)
79
+ json = EnfApi::to_json(new_record)
80
+ EnfApi::API.instance.post "#{@xdns_base_url}/zones/#{zone_id}/records", json
81
+ end
82
+
83
+ def list_dns_records(zone_id)
84
+ EnfApi::API.instance.get "#{@xdns_base_url}/zones/#{zone_id}/records"
85
+ end
86
+
87
+ def query(network, type, name)
88
+ EnfApi::API.instance.get "#{@xdns_base_url}/networks/#{network}/query/#{type}/#{name}"
89
+ end
90
+
91
+ def delete_dns_record(record_id)
92
+ EnfApi::API.instance.delete "#{@xdns_base_url}/records/#{record_id}"
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,37 @@
1
+ #
2
+ # Copyright 2020 Xaptum,Inc
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+
17
+ require "singleton"
18
+
19
+ module EnfApi
20
+ class Firewall
21
+ include Singleton
22
+
23
+ def list_firewall_rules(network)
24
+ EnfApi::API.instance.get "/api/xfw/v2/#{network}/rule"
25
+ end
26
+
27
+ def add_firewall_rule(network, rule)
28
+ rule_json = EnfApi::to_json(rule)
29
+ EnfApi::API.instance.post "/api/xfw/v2/#{network}/rule", rule_json
30
+ end
31
+
32
+ def delete_firewall_rules(network, id = nil)
33
+ # Same method to call to delete all firewall rules in a network. if id is nil
34
+ EnfApi::API.instance.delete "/api/xfw/v2/#{network}/rule/#{id}"
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,75 @@
1
+ #
2
+ # Copyright 2020 Xaptum,Inc
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+ module EnfApi
17
+ class UserManager
18
+ include Singleton
19
+
20
+ def initialize
21
+ @version = "v3"
22
+ @xcr_base_url = "/api/xcr/#{@version}"
23
+ end
24
+
25
+ def list_users(query)
26
+ EnfApi::API.instance.get "#{@xcr_base_url}/users#{query}"
27
+ end
28
+
29
+ def get_user(email)
30
+ EnfApi::API.instance.get "#{@xcr_base_url}/users/#{email}"
31
+ end
32
+
33
+ def list_user_roles(user, network)
34
+ url = "#{@xcr_base_url}/users/#{user}/roles"
35
+ url += "?network=#{network}" if network
36
+ EnfApi::API.instance.get url
37
+ end
38
+
39
+ def delete_user_roles(user_id, roles, network)
40
+ url = "#{@xcr_base_url}/users/#{user_id}/roles?roles=#{roles}"
41
+ url += "&network=#{network}" if network
42
+ EnfApi::API.instance.delete url
43
+ end
44
+
45
+ def add_user_role(user_id, role_hash)
46
+ json = EnfApi::to_json(role_hash)
47
+ url = "#{@xcr_base_url}/users/#{user_id}/roles"
48
+ EnfApi::API.instance.post url, json
49
+ end
50
+
51
+ def list_invites(domain)
52
+ url = "#{@xcr_base_url}/invites"
53
+ url += "?domain=#{domain}" if domain
54
+ EnfApi::API.instance.get url
55
+ end
56
+
57
+ def invite(hash)
58
+ json = EnfApi::to_json(hash)
59
+ EnfApi::API.instance.post "#{@xcr_base_url}/invites", json
60
+ end
61
+
62
+ def delete_invite(invite_id)
63
+ EnfApi::API.instance.delete "#{@xcr_base_url}/invites/#{invite_id}"
64
+ end
65
+
66
+ def resend_invite(invite_id)
67
+ EnfApi::API.instance.put "#{@xcr_base_url}/invites/#{invite_id}", "{}"
68
+ end
69
+
70
+ def update_user_status(user_id, status)
71
+ json = EnfApi::to_json(status)
72
+ EnfApi::API.instance.put "#{@xcr_base_url}/users/#{user_id}/status", json
73
+ end
74
+ end
75
+ end
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright 2018 Xaptum,Inc
2
+ # Copyright 2018-2020 Xaptum,Inc
3
3
  #
4
4
  # Licensed under the Apache License, Version 2.0 (the "License");
5
5
  # you may not use this file except in compliance with the License.
@@ -112,7 +112,7 @@ module EnfCli
112
112
 
113
113
  def self.ask_password(prompt = nil)
114
114
  begin
115
- prompt = "Enter Password:" unless prompt
115
+ prompt ||= "Enter Password:"
116
116
  print prompt
117
117
  # We hide the entered characters before to ask for the password
118
118
  system "stty -echo"
@@ -134,7 +134,7 @@ module EnfCli
134
134
 
135
135
  # Generate cert
136
136
  cert = OpenSSL::X509::Certificate.new
137
- cert.subject = cert.issuer = OpenSSL::X509::Name.new([["CN", "#{ipv6}"]])
137
+ cert.subject = cert.issuer = OpenSSL::X509::Name.new([["CN", ipv6.to_s]])
138
138
  cert.not_before = Time.now
139
139
  cert.not_after = Time.now + 365 * 24 * 60 * 60
140
140
  cert.public_key = key
@@ -190,15 +190,41 @@ module EnfCli
190
190
  end
191
191
 
192
192
  def xaptum_admin?
193
- self.user_role == "XAPTUM_ADMIN"
193
+ has_role? "XAPTUM_ADMIN"
194
194
  end
195
195
 
196
- def user_role
197
- @session[:type]
196
+ def domain_admin?
197
+ has_role? "DOMAIN_ADMIN"
198
+ end
199
+
200
+ def domain_user?
201
+ has_role? "DOMAIN_USER"
202
+ end
203
+
204
+ def network_admin?
205
+ has_role? "NETWORK_ADMIN"
206
+ end
207
+
208
+ def network_user?
209
+ has_role? "NETWORK_USER"
210
+ end
211
+
212
+ def edit_domain_role?
213
+ xaptum_admin? || domain_admin?
214
+ end
215
+
216
+ def has_role?(role)
217
+ all_roles = @session[:roles]
218
+ all_roles.each do |cur_role|
219
+ if cur_role[:role] == role
220
+ return true
221
+ end
222
+ end
223
+ false
198
224
  end
199
225
 
200
226
  def host
201
- "#{@host}"
227
+ @host.to_s
202
228
  end
203
229
 
204
230
  def auth_token
@@ -229,8 +255,8 @@ module EnfCli
229
255
  }
230
256
 
231
257
  desc "connect", "Connect to ENF Controller"
232
- method_option :host, :type => :string
233
- method_option :user, :type => :string
258
+ method_option :host, type: :string
259
+ method_option :user, type: :string
234
260
 
235
261
  def connect(*names)
236
262
  host = ""
@@ -278,7 +304,7 @@ module EnfCli
278
304
  puts EnfCli::VERSION
279
305
  end
280
306
 
281
- desc "update", "", :hide => true
307
+ desc "update", "", hide: true
282
308
 
283
309
  def update
284
310
  cmd = Gem::Commands::UpdateCommand.new
@@ -286,7 +312,7 @@ module EnfCli
286
312
  execute_gem_cmd cmd
287
313
  end
288
314
 
289
- desc "search", "", :hide => true
315
+ desc "search", "", hide: true
290
316
 
291
317
  def search
292
318
  cmd = Gem::Commands::SearchCommand.new
@@ -295,14 +321,14 @@ module EnfCli
295
321
  end
296
322
 
297
323
  desc "create-config-file", "Create a Xaptum configuration file in your home directory"
298
- method_option :host, :type => :string, :required => true
299
- method_option :user, :type => :string, :required => true
324
+ method_option :host, type: :string, required: true
325
+ method_option :user, type: :string, required: true
300
326
 
301
327
  def create_config_file
302
328
  host = options[:host]
303
329
  user = options[:user]
304
330
  config_file = File.new(CONFIG_FILE, "w+")
305
- config_file.puts({ :host => host, :user => user }.to_json)
331
+ config_file.puts({ host: host, user: user }.to_json)
306
332
  config_file.close
307
333
  say "Config file created successfully at #{CONFIG_FILE}!", :green
308
334
  end
@@ -349,7 +375,7 @@ module EnfCli
349
375
  trap("INT") { system("stty", stty_save); exit }
350
376
 
351
377
  while input = Readline.readline(EnfCli::CTX.instance.prompt, true)
352
- break if input == "exit" or input == "\\q" or input == "quit"
378
+ break if input == "exit" or input == '\q' or input == "quit"
353
379
 
354
380
  # Remove blank lines from history
355
381
  Readline::HISTORY.pop if input == ""
@@ -362,12 +388,12 @@ module EnfCli
362
388
 
363
389
  # Shell CLI class
364
390
  class CLI < EnfCli::EnfThor
365
- desc "ls [<dir>]", "List files in a directory", :hide => true
366
- method_option :dir, :type => :string, :required => false
391
+ desc "ls [<dir>]", "List files in a directory", hide: true
392
+ method_option :dir, type: :string, required: false
367
393
 
368
394
  def ls(dir = nil)
369
395
  try_with_rescue do
370
- dir = "." unless dir
396
+ dir ||= "."
371
397
  dir = EnfCli::expand_path(dir)
372
398
 
373
399
  Dir.entries(dir).each { |f|
@@ -376,7 +402,7 @@ module EnfCli
376
402
  end
377
403
  end
378
404
 
379
- desc "cat <file>", "Display contents of a file", :hide => true
405
+ desc "cat <file>", "Display contents of a file", hide: true
380
406
 
381
407
  def cat(file)
382
408
  try_with_rescue do
@@ -390,7 +416,7 @@ module EnfCli
390
416
  end
391
417
  end
392
418
 
393
- desc "pwd", "Current Working Directory", :hide => true
419
+ desc "pwd", "Current Working Directory", hide: true
394
420
 
395
421
  def pwd
396
422
  try_with_rescue do
@@ -398,17 +424,18 @@ module EnfCli
398
424
  end
399
425
  end
400
426
 
401
- desc "cd [<dir>]", "Change working directory", :hide => true
427
+ desc "cd [<dir>]", "Change working directory", hide: true
402
428
 
403
429
  def cd(dir = "~")
404
430
  try_with_rescue do
405
431
  dir = EnfCli::expand_path(dir)
406
432
  raise EnfCli::ERROR, "No such directory #{dir}" unless Dir.exist?(dir)
433
+
407
434
  Dir.chdir(dir)
408
435
  end
409
436
  end
410
437
 
411
- desc "host", "Display ENF Controller host", :hide => true
438
+ desc "host", "Display ENF Controller host", hide: true
412
439
 
413
440
  def host
414
441
  try_with_rescue do
@@ -416,7 +443,7 @@ module EnfCli
416
443
  end
417
444
  end
418
445
 
419
- desc "clear", "Clear Terminal Screen", :hide => true
446
+ desc "clear", "Clear Terminal Screen", hide: true
420
447
 
421
448
  def clear
422
449
  try_with_rescue do
@@ -429,7 +456,7 @@ module EnfCli
429
456
 
430
457
  def display_session_token
431
458
  try_with_rescue_in_session do
432
- say "#{EnfCli::CTX.instance.auth_token}"
459
+ say EnfCli::CTX.instance.auth_token.to_s
433
460
  end
434
461
  end
435
462
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  #
4
- # Copyright 2018-2019 Xaptum,Inc
4
+ # Copyright 2018-2020 Xaptum,Inc
5
5
  #
6
6
  # Licensed under the Apache License, Version 2.0 (the "License");
7
7
  # you may not use this file except in compliance with the License.
@@ -278,6 +278,10 @@ module EnfCli
278
278
  desc: "secure-host or passthrough"
279
279
  method_option :'wifi-id', type: :string, default: nil, banner: "WIFI-ID",
280
280
  desc: "WIFI-ID is the UUID of the wifi record that the profile will use. wifi record must already exist"
281
+ method_option :'update-id', type: :string, default: nil,
282
+ banner: "UPDATE-ID",
283
+ desc: "UPDATE-ID is the UUID of the firmware update record. " \
284
+ "The firmware-update record must already exist."
281
285
 
282
286
  def create_profile
283
287
  try_with_rescue_in_session do
@@ -293,6 +297,12 @@ module EnfCli
293
297
  new_profile_hash[:config][:wifi][:id] = wifi
294
298
  end
295
299
 
300
+ fw_update = options[:'update-id']
301
+ if fw_update
302
+ new_profile_hash[:config][:firmware] = {}
303
+ new_profile_hash[:config][:firmware][:id] = fw_update if fw_update
304
+ end
305
+
296
306
  # send the POST to create a new profile
297
307
  profile = EnfApi::Captive.instance.create_profile new_profile_hash
298
308
  display_profile profile
@@ -341,6 +351,10 @@ module EnfCli
341
351
  desc: "secure-host or passthrough"
342
352
  method_option :'wifi-id', type: :string, default: nil, banner: "WIFI-ID",
343
353
  desc: "WIFI-ID is the UUID of the wifi record that the profile will use. wifi record must already exist"
354
+ method_option :'update-id', type: :string, default: nil,
355
+ banner: "UPDATE-ID",
356
+ desc: "UPDATE-ID is the UUID of the firmware update record. " \
357
+ "The firmware-update record must already exist."
344
358
 
345
359
  def update_profile
346
360
  try_with_rescue_in_session do
@@ -348,23 +362,250 @@ module EnfCli
348
362
  name = options[:'profile-name']
349
363
  mode = options[:'device-mode']
350
364
  wifi_id = options[:'wifi-id']
365
+ fw_update = options[:'update-id']
351
366
 
352
- raise "At least one option needs to change." if name == nil && mode == nil && wifi_id == nil
367
+ raise "At least one option needs to change." if name == nil && mode == nil && wifi_id == nil && fw_update == nil
353
368
 
354
369
  update_hash = {}
355
370
  update_hash[:name] = name if name
356
- update_hash[:config] = {} if wifi_id || mode
371
+ update_hash[:config] = {} if wifi_id || mode || fw_update
357
372
  update_hash[:config][:mode] = mode if mode
358
373
  if wifi_id
359
374
  update_hash[:config][:wifi] = {}
360
375
  update_hash[:config][:wifi][:id] = wifi_id
361
376
  end
362
377
 
378
+ if fw_update
379
+ update_hash[:config][:firmware] = {}
380
+ update_hash[:config][:firmware][:id] = fw_update
381
+ end
363
382
  profile = EnfApi::Captive.instance.update_profile id, update_hash
364
383
  display_profile profile
365
384
  end
366
385
  end
367
386
 
387
+ desc "list-firmware-images",
388
+ "Lists all of the available versions of the firmware"
389
+
390
+ def list_firmware_images
391
+ try_with_rescue_in_session do
392
+ data = EnfApi::Captive.instance.list_firmware_images
393
+ display_firmware_image_list data
394
+ end
395
+ end
396
+
397
+ desc "upload-firmware-image",
398
+ "Uploads a new firmware image. Each version will have multiple " \
399
+ "images -- one for each type of hardware. \nNOTE: This version " \
400
+ "doesn't actually upload the file, it merely informs the server of " \
401
+ "its existance."
402
+ method_option :'image-file', required: true, type: :string,
403
+ banner: "<file>", desc: "<file> is the firmware binary image."
404
+ method_option :version, required: true, type: :string,
405
+ banner: "VERSION",
406
+ desc: "VERSION is the release version."
407
+ method_option :'image-name', type: :string, default: nil, banner: "NAME",
408
+ desc: "NAME is the name to associate with the firmware " \
409
+ "image. This is usually the generated filename. " \
410
+ "Defaults to the base name of <file>"
411
+
412
+ def upload_firmware_image
413
+ try_with_rescue_in_session do
414
+ filename = options[:'image-file']
415
+ version = options[:version]
416
+ image_name = options[:'image-name']
417
+
418
+ temp_img_name = File.basename(filename)
419
+ image_name ||= temp_img_name
420
+
421
+ raise "image-name does not match image-file" if temp_img_name != image_name
422
+
423
+ # This version PUTs an empty body
424
+ resp = EnfApi::Captive.instance.upload_firmware_image version, image_name
425
+
426
+ if (resp.code == 200)
427
+ say "Upload complete."
428
+ else
429
+ say "Upload failed with code #{resp.code}"
430
+ end
431
+ end
432
+ end
433
+
434
+ desc "get-firmware-info",
435
+ "Prints details of an existing firmware version."
436
+ method_option :version, required: true, type: :string,
437
+ banner: "VERSION", desc: "VERSION is the release version."
438
+
439
+ def get_firmware_info
440
+ try_with_rescue_in_session do
441
+ version = options[:version]
442
+
443
+ fw_info = EnfApi::Captive.instance.get_firmware_info version
444
+
445
+ display_firmware_detail fw_info
446
+ end
447
+ end
448
+
449
+ desc "create-schedule",
450
+ "Creates a schedule object that will be used to determine when a " \
451
+ "device or group of devices may be upgraded. The schedule will be " \
452
+ "uploaded from a JSON-formatted file."
453
+ method_option :schedule, required: true, type: :string,
454
+ banner: "<file>",
455
+ desc: "<file> is a JSON file containing the desired schedule."
456
+
457
+ def create_schedule
458
+ try_with_rescue_in_session do
459
+ filename = options[:schedule]
460
+
461
+ # reading the whole file - shouldn't get more than a few KB
462
+ content = File.read filename
463
+ sched_hash = JSON.parse(content)
464
+
465
+ resp_data = EnfApi::Captive.instance.create_schedule sched_hash
466
+ display_schedule_detail resp_data
467
+ end
468
+ end
469
+
470
+ desc "list-schedules",
471
+ "Prints a summary list of all existing schedules."
472
+
473
+ def list_schedules
474
+ try_with_rescue_in_session do
475
+ sched_list = EnfApi::Captive.instance.list_schedules
476
+ display_schedule_list sched_list
477
+ end
478
+ end
479
+
480
+ desc "get-schedule",
481
+ "Prints the detail of a specific, existing schedule."
482
+ method_option :'schedule-id', type: :string, required: true, banner: "ID",
483
+ desc: "ID is the system-assigned UUID of the schedule " \
484
+ "to retrieve."
485
+
486
+ def get_schedule
487
+ try_with_rescue_in_session do
488
+ sched_id = options[:'schedule-id']
489
+ sched_data = EnfApi::Captive.instance.get_schedule sched_id
490
+ display_schedule_detail sched_data
491
+ end
492
+ end
493
+
494
+ desc "update-schedule",
495
+ "Modifies an existing schedule by uploading an updated schedule in " \
496
+ "the form of a JSON file."
497
+ method_option :'schedule-id', type: :string, required: true, banner: "ID",
498
+ desc: "ID is the UUID of the schedule to update."
499
+ method_option :schedule, type: :string, required: true, bannder: "<file>",
500
+ desc: "<file> is a JSON file containing the desired schedule."
501
+
502
+ def update_schedule
503
+ try_with_rescue_in_session do
504
+ sched_id = options[:'schedule-id']
505
+ filename = options[:schedule]
506
+
507
+ # read in whole schedule file
508
+ content = File.read filename
509
+ sched_hash = JSON.parse(content)
510
+
511
+ resp_data = EnfApi::Captive.instance.update_schedule sched_id, sched_hash
512
+ display_schedule_detail resp_data
513
+ end
514
+ end
515
+
516
+ desc "delete-schedule",
517
+ "Deletes the specified, existing schedule."
518
+ method_option :'schedule-id', type: :string, required: true, banner: "ID",
519
+ desc: "ID is the system-assigned UUID of the schedule " \
520
+ "to delete."
521
+
522
+ def delete_schedule
523
+ try_with_rescue_in_session do
524
+ sched_id = options[:'schedule-id']
525
+
526
+ # get the name of the schedule
527
+ resp = EnfApi::Captive.instance.get_schedule(sched_id)
528
+ name = resp[:name]
529
+
530
+ resp = EnfApi::Captive.instance.delete_schedule sched_id
531
+
532
+ if (resp.code == 200)
533
+ say "Successfully deleted schedule named: #{name}"
534
+ elsif (resp.code == 409)
535
+ say "Schedule #{name} is being used by pending updates and cannot be deleted."
536
+ else
537
+ say "Failed to delete schedule #{name} with code #{resp.code}"
538
+ end
539
+ end
540
+ end
541
+
542
+ desc "list-firmware-updates",
543
+ "Lists the existing firmware update tasks."
544
+
545
+ def list_firmware_updates
546
+ try_with_rescue_in_session do
547
+ updates_list = EnfApi::Captive.instance.list_firmware_updates
548
+ display_updates_list updates_list
549
+ end
550
+ end
551
+
552
+ desc "get-firmware-update",
553
+ "Prints the details of the specified firmware update task."
554
+ method_option :'update-id', type: :string, required: true, banner: "ID",
555
+ desc: "ID is the UUID of the firmware update task"
556
+
557
+ def get_firmware_update
558
+ try_with_rescue_in_session do
559
+ update_id = options[:'update-id']
560
+
561
+ update_data = EnfApi::Captive.instance.get_firmware_update update_id
562
+ display_update_detail update_data
563
+ end
564
+ end
565
+
566
+ desc "create-firmware-update",
567
+ "Creates a firmware-update task that the system will use to update " \
568
+ "router-card firmware as prescribed in the specified JSON file."
569
+ method_option :update, type: :string, required: true, banner: "<file>",
570
+ desc: "<file> is a JSON file containing the details of " \
571
+ "the update task."
572
+
573
+ def create_firmware_update
574
+ try_with_rescue_in_session do
575
+ filename = options[:update]
576
+
577
+ # reading the whole file - shouldn't get more than a few KB
578
+ content = File.read filename
579
+ update_hash = JSON.parse(content)
580
+
581
+ resp_data = EnfApi::Captive.instance.create_firmware_update update_hash
582
+ display_update_detail resp_data
583
+ end
584
+ end
585
+
586
+ desc "modify-firmware-update",
587
+ "Modifies an existing firmware-update task with the information " \
588
+ "contained in the specified JSON file"
589
+ method_option :'update-id', type: :string, required: true, banner: "ID",
590
+ desc: "ID is the UUID of the firmware update task to be modified."
591
+ method_option :update, type: :string, required: true, banner: "<file>",
592
+ desc: "<file> is a JSON file containing the details of " \
593
+ "the update task."
594
+
595
+ def modify_firmware_update
596
+ try_with_rescue_in_session do
597
+ update_id = options[:'update-id']
598
+ filename = options[:update]
599
+
600
+ # reading the whole file - shouldn't get more than a few KB
601
+ content = File.read filename
602
+ update_hash = JSON.parse(content)
603
+
604
+ resp_data = EnfApi::Captive.instance.modify_firmware_update update_id, update_hash
605
+ display_update_detail resp_data
606
+ end
607
+ end
608
+
368
609
  #########################################################################
369
610
  #
370
611
  # Helper functions
@@ -383,20 +624,21 @@ module EnfCli
383
624
  end
384
625
 
385
626
  # Display a single wifi configuration in detail
386
- def display_wifi_detail(wifi_data, full_listing = true)
627
+ def display_wifi_detail(wifi_data, full_listing = true, tabs = 0)
628
+ indent = " " * tabs
387
629
  name = wifi_data[:name]
388
630
  wifi_id = wifi_data[:id]
389
631
  desc = wifi_data[:description]
390
632
  nets = wifi_data[:networks]
391
633
 
392
- say "Wifi ID : #{wifi_id}", nil, true
393
- say "Name : #{name}", nil, true
394
- say "Description : #{desc}", nil, true if desc
634
+ say indent + "Name : #{name}", nil, true
635
+ say indent + "Wifi ID : #{wifi_id}", nil, true
636
+ say indent + "Description : #{desc}", nil, true if desc
395
637
  if full_listing
396
638
  say "WiFi Networks :"
397
639
  if nets
398
640
  nets.each do |wifi_net|
399
- display_wifi_net(wifi_net, 1)
641
+ display_wifi_net(wifi_net, tabs + 1)
400
642
  end
401
643
  end
402
644
  end
@@ -567,7 +809,7 @@ module EnfCli
567
809
  say "Router Mode : #{mode}", nil, true
568
810
  say "Uptime (in seconds) : #{uptime}", nil, true
569
811
  say "Status refresh time : #{refresh}", nil, true
570
- say "WIFI :"
812
+ say "WIFI status :"
571
813
  say " connected : #{connected}", nil, true
572
814
  say " SSID : #{ssid}" if ssid
573
815
  if ipv4 && !ipv4.empty?
@@ -584,7 +826,17 @@ module EnfCli
584
826
  end
585
827
  end
586
828
 
587
- display_wifi_detail(wifi_config, false) if wifi_config
829
+ say "WIFI configuration :"
830
+ display_wifi_detail(wifi_config, false, 1) if wifi_config
831
+
832
+ fw_status = device_status[:firmware]
833
+ if fw_status
834
+ image_name = fw_status[:image_name] || "< not available >"
835
+ image_state = fw_status[:state] || " < not available >"
836
+ say "Firmware Status :"
837
+ say " image name : #{image_name}", nil, true
838
+ say " operating state : #{image_state}", nil, true
839
+ end
588
840
 
589
841
  say " ", nil, true
590
842
  end
@@ -613,7 +865,6 @@ module EnfCli
613
865
  # [hash[:serial_number], hash[:device_name], hash[:device_address],
614
866
  # hash[:status][:router_mode], hash[:status][:wifi][:connected],
615
867
  # hash[:status][:wifi][:SSID]]
616
-
617
868
  render_table(headings, rows)
618
869
  end
619
870
 
@@ -623,11 +874,20 @@ module EnfCli
623
874
  def display_profile(profile, summary = false)
624
875
  indent = summary ? " " : ""
625
876
 
877
+ firmware = profile[:config][:firmware]
878
+ fw_id = "< not configured >"
879
+ if firmware
880
+ fw_id = firmware[:id]
881
+ fw_version = firmware[:version]
882
+ end
883
+
626
884
  say indent + "Name : #{profile[:name]}", nil, true
627
885
  say indent + "Profile ID : #{profile[:id]}", nil, true
628
886
  say indent + "Configuration version : #{profile[:config][:version]}", nil, true
887
+ say indent + "Firmware Update ID : #{fw_id}", nil, true
629
888
  unless summary
630
- say "Mode : #{profile[:config][:mode]}", nil, true
889
+ say indent + " Update version : #{fw_version}", nil, true if fw_version
890
+ say indent + "Mode : #{profile[:config][:mode]}", nil, true
631
891
  display_wifi_summary profile[:config][:wifi]
632
892
  end
633
893
  end
@@ -654,13 +914,114 @@ module EnfCli
654
914
  # display the profile summary list
655
915
  #
656
916
  def display_profile_list(profiles)
657
- headings = ["Profile Name", "Profile ID", "Version"]
917
+ headings = ["Profile Name", "Profile ID", "Version", "Mode", "Wifi ID", "Firmware Update ID"]
658
918
  rows = profiles.map do |hash|
659
- [hash[:name], hash[:id], hash[:config][:version]]
919
+ config = hash[:config]
920
+ fw_id = config[:firmware] ? config[:firmware][:id] : "none"
921
+ [hash[:name], hash[:id], config[:version], config[:mode],
922
+ config[:wifi][:id], fw_id]
660
923
  end
924
+ render_table(headings, rows)
925
+ end
661
926
 
927
+ #
928
+ # Displays the list of firmware releases
929
+ #
930
+ def display_firmware_image_list(images)
931
+ headings = ["Firmware Version"]
932
+ rows = images.map do |element|
933
+ [element[:version]]
934
+ end
662
935
  render_table(headings, rows)
663
936
  end
937
+
938
+ #
939
+ # Displays firmware detail
940
+ #
941
+ def display_firmware_detail(fw_info)
942
+ version = fw_info[:version] || "< not available >"
943
+ images = fw_info[:images]
944
+
945
+ say "Release version: #{version}"
946
+ display_image_list images
947
+ end
948
+
949
+ #
950
+ # Displays the list of images available for a release version.
951
+ #
952
+ def display_image_list(images)
953
+ headings = ["Image Name", "Hardware Model", "Update Type", "SHA256"]
954
+ rows = images.map do |hash|
955
+ [hash[:name], hash[:model], hash[:type], hash[:sha256]]
956
+ end
957
+ render_table(headings, rows)
958
+ end
959
+
960
+ #
961
+ # Displays the full SCHEDULE object detail
962
+ #
963
+ def display_schedule_detail(sched_data)
964
+ name = sched_data[:name]
965
+ id = sched_data[:id]
966
+ domain = sched_data[:domain]
967
+ times = sched_data[:times]
968
+
969
+ say "Schedule Name : #{name}", nil, true
970
+ say "Shedule ID : #{id}", nil, true
971
+ say "domain : #{domain}", nil, true
972
+ say "Times:", nil, true
973
+ display_time_list(times)
974
+ end
975
+
976
+ #
977
+ # Displays the list of times in a schedule as a table
978
+ #
979
+ def display_time_list(times)
980
+ headings = ["Name", "year", "Month", "Date", "Weekday", "Hour",
981
+ "Minute", "id"]
982
+ rows = times.map do |hash|
983
+ [hash[:name], hash[:year], hash[:month], hash[:day_of_month],
984
+ hash[:day_of_week], hash[:hour], hash[:minute], hash[:id]]
985
+ end
986
+ render_table(headings, rows)
987
+ end
988
+
989
+ #
990
+ # Displays a list of schedules
991
+ #
992
+ def display_schedule_list(sched_list)
993
+ headings = ["Name", "ID"]
994
+ rows = sched_list.map do |hash|
995
+ [hash[:name], hash[:id]]
996
+ end
997
+ render_table(headings, rows)
998
+ end
999
+
1000
+ #
1001
+ # Displays a list of firmware updates
1002
+ #
1003
+ def display_updates_list(updates_list)
1004
+ headings = ["Update ID", "Update Version"]
1005
+ rows = updates_list.map do |hash|
1006
+ [hash[:id], hash[:version]]
1007
+ end
1008
+ render_table(headings, rows)
1009
+ end
1010
+
1011
+ #
1012
+ # Displays detail of a specific firmware update task
1013
+ #
1014
+ def display_update_detail(update_data)
1015
+ id = update_data[:id]
1016
+ sched_id = update_data[:schedule_id]
1017
+ version = update_data[:version]
1018
+ percent = update_data[:update_percentage]
1019
+
1020
+ say "Update Task ID : #{id}"
1021
+ say "Schedule ID : #{sched_id}"
1022
+ say "Firmware Version : #{version}"
1023
+ say "Percent of devices to update : #{percent}"
1024
+ end
664
1025
  end
665
1026
  end
666
1027
  end