nex_client 0.16.0 → 0.17.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 727229b96317d3a2a14803712ad8bc5cc3df368b
4
- data.tar.gz: db3eee696bbee741e2dcb307b4217c033b549c09
3
+ metadata.gz: 08b088941d2119c0e8b7e1e61bdcf74dd622ba60
4
+ data.tar.gz: acf4d046a21edeb0e95873c7dfbeda06e25df751
5
5
  SHA512:
6
- metadata.gz: da2bf4d72a045db4bbb98d6b42c890ad6f767530f562c8a4ee3869e852c5b407f38290be1f55f9a8891318e52de63a62bbfc515aa407d4d30eb0ffc120740008
7
- data.tar.gz: f6baf5690f4d3c8a6dcaecbc706d0fe757cf190052ca5ff585a87654240ebd86b69b01dfe16ad241bb7d73083a6a37a5af5b80e1efac5c58ecba5bd152f5be6e
6
+ metadata.gz: e39b32c047894a572757b5b90317ad1d0dfc9f78f27a4ffe3db123266539ae0924ee5632b0a88c223f778fd4b0c8e97efcf6a64abedd40a3f8434f9982cddcf6
7
+ data.tar.gz: bad64e27e601910f2445c6247f63aa7bddd669bb5409fbc592262e901908dc71030b313c613ad10047d2b1d5e523ddf5f679aee67a9c1c3d22e8300a630aa208
@@ -13,6 +13,7 @@ module NexClient
13
13
  autoload :CubeTemplate, 'nex_client/cube_template'
14
14
  autoload :Domain, 'nex_client/domain'
15
15
  autoload :Event, 'nex_client/event'
16
+ autoload :ExecTask, 'nex_client/exec_task'
16
17
  autoload :GatewayRack, 'nex_client/gateway_rack'
17
18
  autoload :Me, 'nex_client/me'
18
19
  autoload :Organization, 'nex_client/organization'
@@ -24,7 +24,7 @@ module NexClient
24
24
  c.example 'list all including terminated addons', 'nex-cli addons --all'
25
25
  c.option '--all', 'list all addons (no filtering)'
26
26
  c.option '--status <active|terminated>', String, 'list all addons in a given status'
27
- c.option '--service <mysql|redis>', String, 'list all addons for a specific service'
27
+ c.option '--service <mysql|redis|mongo26|kafka|minio>', String, 'list all addons for a specific service'
28
28
  c.action do |args, options|
29
29
  NexClient::Commands::Addons.list(args,options)
30
30
  end
@@ -33,7 +33,7 @@ module NexClient
33
33
  command :'addons:create' do |c|
34
34
  c.syntax = 'nex-cli addons:create SERVICE APP_NAME'
35
35
  c.summary = 'Create addons'
36
- c.description = 'Create addons for your apps. Available addons: mysql | redis | mongo26'
36
+ c.description = 'Create addons for your apps. Available addons: mysql | redis | mongo26 | kafka | minio'
37
37
  c.example 'create mysql addon for myapp', 'nex-cli addons:create mysql myapp'
38
38
  c.example 'create redis addon for myapp', 'nex-cli addons:create redis myapp'
39
39
  c.option '--size SIZE', Integer, 'specify container size (default: 2, min: 1, max: 20). Container will have N shares of CPU and N*128M of memory.'
@@ -332,7 +332,64 @@ module NexClient
332
332
  command :'apps:update' do |c|
333
333
  c.syntax = 'nex-cli apps:update APP_NAME [options]'
334
334
  c.summary = 'Update apps settings'
335
- c.description = 'Update application settings'
335
+ c.description = <<~HEREDOC
336
+ Update general application settings and behaviour
337
+
338
+ Log drain:
339
+ ----------
340
+ Use: --http-log-drain DRAIN_URL
341
+ The log drain is a HTTP(s) URL where application logs will be POSTed.
342
+
343
+ Default region:
344
+ ---------------
345
+ Use: --region REGION
346
+ Containers will be deployed in the specified region by default if no region-balancing
347
+ policies have been specified. This is only relevant when the Nex!™ platform has been deployed in multiple regions.
348
+
349
+ Geo-Balancing:
350
+ ---------------
351
+ Use: --region-balancing REGIONS
352
+ Specify how your containers should be distributed across the available Nex!™ regions. This is only relevant when the Nex!™ platform has been deployed
353
+ in multiple regions.
354
+
355
+ Options are the following:
356
+ - evenly distribute across all regions: --region-balancing=all
357
+ - eventy distribute across specified regions: --region-balancing="ap-southeast-1,us-west-2"
358
+ - distribute with relative weights: --region-balancing="ap-southeast-1=1,us-west-2=2"
359
+
360
+ Web Application Firewall (WAF)
361
+ ------------------------------
362
+ Use: --waf-rules [PATH]
363
+ Specify a JSON (.json) or YAML (.yml) file describing the security rules to apply/ignore. If no files are specified you will be prompted to
364
+ paste rules in JSON format in the terminal.
365
+ The WAF always runs in SIMULATE mode by default - this means security events will be logged but no requests will be blocked.
366
+
367
+ The list of base rules applied by default is available here: https://github.com/p0pr0ck5/lua-resty-waf/tree/master/rules
368
+
369
+ The base WAF behaviour can be extended by passing a JSON (or YAML) manifest to '--waf-rules' with the following format:
370
+ {
371
+ // Whether the WAF should be enabled, disabled or do log-only
372
+ // 'ACTIVE', 'INACTIVE' or 'SIMULATE'
373
+ "mode": "SIMULATE",
374
+
375
+ // Array of rule IDs to ignore
376
+ "ignore_rule": [],
377
+
378
+ // Array of rulesets to ignore
379
+ "ignore_ruleset": [],
380
+
381
+ // Array of ['rulename','rule'] objects
382
+ "add_ruleset_string": [],
383
+
384
+ // Rules sieves allow you to apply/ignore rules based on a
385
+ // specific context such as request parameters
386
+ // Array of ['rule_id', [{ sieve_cond }, { sieve_cond }] ] objects
387
+ "sieve_rule": []
388
+ }
389
+ See this for more info: https://github.com/p0pr0ck5/lua-resty-waf
390
+ See this for rule sieves: https://github.com/p0pr0ck5/lua-resty-waf/wiki/Rule-Sieves
391
+
392
+ HEREDOC
336
393
  c.example 'change container size to 4', 'nex-cli apps:update myapp --size 4'
337
394
  c.example 'balance containers equally between regions', 'nex-cli apps:update myapp --region-balancing="ap-southeast-1,us-west-2"'
338
395
  c.example 'deploy more containers in one region', 'nex-cli apps:update myapp --region-balancing="ap-southeast-1=1,us-west-2=2"'
@@ -344,6 +401,7 @@ module NexClient
344
401
  c.option '--tags TAG_LIST', String, 'comma separated list of tags to use to describe the app'
345
402
  c.option '--region REGION', String, 'default region to use deploy/scale this application'
346
403
  c.option '--region-balancing REGIONS', String, 'specify how the app should be proportionally distributed geographically. E.g. "all" or "ap-southeast-1,us-west-2" or "ap-southeast-1=1,us-west-2=2". [restart required]'
404
+ c.option '--waf-rules [PATH]', String, 'specify web application firewall rules using JSON or YAML file (prompt will appear otherwise). [restart required]'
347
405
  c.action do |args, options|
348
406
  NexClient::Commands::Apps.update(args,options)
349
407
  end
@@ -594,6 +652,69 @@ module NexClient
594
652
  end
595
653
  end
596
654
 
655
+ command :'exec-tasks' do |c|
656
+ c.syntax = 'nex-cli exec-tasks [EXECUTOR_NAME] [options]'
657
+ c.summary = 'Manage execution tasks'
658
+ c.description = 'List executions tasks (all or for specific resources)'
659
+ c.example 'list all execution tasks', 'nex-cli exec-tasks'
660
+ c.example 'list all execution tasks for cube 111-222-333', 'nex-cli exec-tasks 111-222-333'
661
+ c.action do |args, options|
662
+ NexClient::Commands::ExecTasks.list(args,options)
663
+ end
664
+ end
665
+
666
+ command :'exec-tasks:info' do |c|
667
+ c.syntax = 'nex-cli exec-tasks:info [TASK_ID] [options]'
668
+ c.summary = 'Display an execution task'
669
+ c.description = 'Display an execution task'
670
+ c.example 'Display execution tasks aaaa-2222', 'nex-cli exec-tasks:info aaaa-2222'
671
+ c.action do |args, options|
672
+ NexClient::Commands::ExecTasks.info(args,options)
673
+ end
674
+ end
675
+
676
+ command :'exec-tasks:create' do |c|
677
+ c.syntax = 'nex-cli exec-tasks:create [options]'
678
+ c.summary = 'Create execution task'
679
+ c.description = <<~HEREDOC
680
+ Create execution task for a resource such as a cube, app, addon or rack
681
+
682
+ Crontab Format:
683
+ ----------------
684
+ * * * * *
685
+ - - - - -
686
+ | | | | +-------------------> day of week (0 - 6) (Sunday=0)
687
+ | | | +-----------------> month (1 - 12)
688
+ | | +---------------> day of month (1 - 31)
689
+ | +-------------> hour (0 - 23)
690
+ +-----------> min (0 - 59)
691
+ HEREDOC
692
+ c.example 'Create task for cube 111-222', 'nex-cli exec-tasks:create --cube 111-222'
693
+ c.example 'Create task for app myapp', 'nex-cli exec-tasks:create --app myapp'
694
+ c.example 'Create task for addon myaddon', 'nex-cli exec-tasks:create --addon myaddon'
695
+ c.example 'Create task for rack 10.0.1.1', 'nex-cli exec-tasks:create --rack 10.0.1.1'
696
+ c.option '--app APP_NAME', String, 'name of the app to attach this task to'
697
+ c.option '--addon ADDON_NAME', String, 'name of the addon to attach this task to'
698
+ c.option '--crontab CRON_EXPRESSION', String, 'frequency expressed as cron expression'
699
+ c.option '--cube CUBE_ID', String, 'id of the cube to attach this task to'
700
+ c.option '--name TASK_NAME', String, 'name of this task'
701
+ c.option '--rack RACK_IP', String, 'IP of the rack to attach this task to'
702
+ c.option '--script SCRIPT_PATH', String, 'path to shell script'
703
+ c.action do |args, options|
704
+ NexClient::Commands::ExecTasks.create(args,options)
705
+ end
706
+ end
707
+
708
+ command :'exec-tasks:delete' do |c|
709
+ c.syntax = 'nex-cli exec-tasks:delete CNAME'
710
+ c.summary = 'Delete execution task'
711
+ c.description = 'Permanently delete an execution task'
712
+ c.example 'Delete task aaaa-2222', 'nex-cli exec-tasks:delete aaaa-2222'
713
+ c.action do |args, options|
714
+ NexClient::Commands::ExecTasks.destroy(args,options)
715
+ end
716
+ end
717
+
597
718
  command :organizations do |c|
598
719
  c.syntax = 'nex-cli organizations [options]'
599
720
  c.summary = 'List organizations'
@@ -8,6 +8,7 @@ module NexClient
8
8
  autoload :CubeInstances, 'nex_client/commands/cube_instances'
9
9
  autoload :CubeTemplates, 'nex_client/commands/cube_templates'
10
10
  autoload :Domains, 'nex_client/commands/domains'
11
+ autoload :ExecTasks, 'nex_client/commands/exec_tasks'
11
12
  autoload :Helpers, 'nex_client/commands/helpers'
12
13
  autoload :Organizations, 'nex_client/commands/organizations'
13
14
  autoload :Racks, 'nex_client/commands/racks'
@@ -14,7 +14,7 @@ module NexClient
14
14
  OPTS_HEADERS = ['key','value'].map(&:upcase)
15
15
 
16
16
  SCM_TITLE = "Source Control Management".colorize(:yellow)
17
- SCM_HEADERS = ['provider','repo','branch','last commit','webhook'].map(&:upcase)
17
+ SCM_HEADERS = ['key','value'].map(&:upcase)
18
18
 
19
19
  def self.list(args,opts)
20
20
  filters = {}
@@ -203,6 +203,18 @@ module NexClient
203
203
  # Hash#dup is required for the resource to detect changes
204
204
  attrs[:opts] = (e.opts || {}).dup.merge(self.extract_config_options(opts))
205
205
 
206
+ if opts.waf_rules
207
+ waf_rules = begin
208
+ if opts.waf_rules.is_a?(String)
209
+ hash_from_file(opts.waf_rules)
210
+ else
211
+ val = ask("Copy/paste your WAF configuration below in JSON format:") { |q| q.gather = "" }
212
+ JSON.parse(val.join(""))
213
+ end
214
+ end
215
+ attrs[:opts]['waf_rules'] = waf_rules
216
+ end
217
+
206
218
  # Update
207
219
  e.update_attributes(attrs)
208
220
 
@@ -430,25 +442,26 @@ module NexClient
430
442
  end
431
443
 
432
444
  def self.display_options(list)
433
- table = Terminal::Table.new title: OPTS_TITLE, headings: OPTS_HEADERS do |t|
445
+ table = Terminal::Table.new title: OPTS_TITLE, headings: OPTS_HEADERS, style: { all_separators: true} do |t|
434
446
  [list].flatten.compact.each do |e|
435
- e.each { |k,v| t.add_row([k,v]) }
447
+ e.each do |k,v|
448
+ val = v.is_a?(Hash) ? JSON.pretty_generate(v) : v
449
+ t.add_row([k,val])
450
+ end
436
451
  end
437
452
  end
438
453
  puts table
439
454
  puts "\n"
440
455
  end
441
-
456
+
442
457
  def self.display_scm(list)
443
458
  table = Terminal::Table.new title: SCM_TITLE, headings: SCM_HEADERS do |t|
444
459
  [list].flatten.compact.each do |e|
445
- t.add_row([
446
- e['provider'],
447
- e['repo'],
448
- e['branch'],
449
- e['last_commit'] || '- nothing pushed yet -',
450
- e['webhook_enabled'].to_s == 'true' ? e['webhook_url'] : '- Not enabled -'
451
- ])
460
+ t.add_row(['provider',e['provider']])
461
+ t.add_row(['repo',e['repo']])
462
+ t.add_row(['branch',e['branch']])
463
+ t.add_row(['last_commit',e['last_commit'] || '- nothing pushed yet -'])
464
+ t.add_row(['webhook',e['webhook_enabled'].to_s == 'true' ? e['webhook_url'] : '- Not enabled -'])
452
465
  end
453
466
  end
454
467
  puts table
@@ -0,0 +1,157 @@
1
+ # frozen_string_literal: true
2
+ module NexClient
3
+ module Commands
4
+ module ExecTasks
5
+ extend Helpers
6
+
7
+ EXEC_TASKS_TITLE = "Execution Tasks".colorize(:magenta)
8
+ EXEC_TASKS_HEADERS = ['id','name','active','crontab','last_run','next_run','executor'].map(&:upcase)
9
+ SCRIPT_TITLE = "Script".colorize(:magenta)
10
+
11
+ def self.list(args,opts)
12
+ filters = {}
13
+ filters[:'executor.name'] = args.first if args.first.present?
14
+
15
+ # Create table
16
+ list = NexClient::ExecTask.includes(:executor).where(filters).order('name')
17
+ self.display_exec_tasks(list)
18
+
19
+ # Loop through results
20
+ while (list.pages.links||{})['next']
21
+ return true if ask("Press enter for next page ('q' to quit)") =~ /q/
22
+ list = list.pages.next
23
+ self.display_exec_tasks(list)
24
+ end
25
+ end
26
+
27
+ def self.info(args,opts)
28
+ id = args.first
29
+ e = NexClient::ExecTask.includes(:executor).find(id).first
30
+
31
+ # Display error
32
+ unless e
33
+ error("Error! Could not find exec_task: #{id}")
34
+ return false
35
+ end
36
+
37
+ # Display task
38
+ self.display_exec_tasks(e)
39
+
40
+ # Display script
41
+ self.format_script(e)
42
+ end
43
+
44
+ # Create a new execution task
45
+ def self.create(args,opts)
46
+ case
47
+ when opts.cube
48
+ executor = NexClient::CubeInstance.find(uuid: opts.cube).first
49
+ when opts.app
50
+ executor = NexClient::App.find(name: opts.app).first
51
+ when opts.addon
52
+ executor ||= NexClient::Addon.find(name: opts.addon).first
53
+ when opts.rack
54
+ [
55
+ NexClient::ComputeRack,
56
+ NexClient::GatewayRack,
57
+ NexClient::RoutingRack,
58
+ NexClient::StorageRack
59
+ ].each do |server_type|
60
+ executor ||= server_type.find(private_ip_address: opts.rack).first
61
+ end
62
+ else
63
+ error("You need to specify an executor. For help: nex-cli exec-tasks:create -h")
64
+ return false
65
+ end
66
+
67
+ # Display error
68
+ unless executor
69
+ error("Error! Could not find executor")
70
+ return false
71
+ end
72
+
73
+ # Ask for additional details
74
+ script = opts.script.present? ? File.read(opts.script) : ask("Copy/paste your script below:") { |q| q.gather = "" }
75
+ name = opts.name.present? ? opts.name : ask("Enter the name of this task: ")
76
+ crontab = opts.crontab.present? ? opts.crontab : ask("Enter a cron expression (m h d M w): ")
77
+
78
+ exec_task = NexClient::ExecTask.new(
79
+ name: name,
80
+ script: script.join("\n"),
81
+ crontab: crontab
82
+ )
83
+ exec_task.relationships.attributes = { executor: { data: { type: executor.type, id: executor.id } } }
84
+ exec_task.save
85
+
86
+ # Display errors if any
87
+ if exec_task.errors.any?
88
+ display_record_errors(exec_task)
89
+ return false
90
+ end
91
+
92
+ # Display task
93
+ e = NexClient::ExecTask.includes(:executor).find(exec_task.id).first
94
+ self.display_exec_tasks(e)
95
+ self.format_script(e)
96
+ end
97
+
98
+ def self.destroy(args,opts)
99
+ id = args.first
100
+ e = NexClient::ExecTask.includes(:executor).find(id).first
101
+
102
+ # Display error
103
+ unless e
104
+ error("Error! Could not find exec_task: #{id}")
105
+ return false
106
+ end
107
+
108
+ # Ask confirmation
109
+ answer = ask("Enter the id of this task to confirm: ")
110
+ unless answer == e.id
111
+ error("Aborting deletion...")
112
+ return false
113
+ end
114
+
115
+ e.destroy
116
+ success("Successfully destroyed task: #{id}")
117
+ end
118
+
119
+ def self.display_exec_tasks(list)
120
+ table = Terminal::Table.new title: EXEC_TASKS_TITLE, headings: EXEC_TASKS_HEADERS do |t|
121
+ [list].flatten.compact.each do |e|
122
+ t.add_row(self.format_record(e))
123
+ end
124
+ end
125
+ puts table
126
+ puts "\n"
127
+ end
128
+
129
+ def self.format_record(record)
130
+ executor = self.format_executor(record)
131
+ [
132
+ record.id,
133
+ record.name,
134
+ record.active,
135
+ record.crontab,
136
+ record.last_run_at,
137
+ record.next_run_at,
138
+ executor
139
+ ]
140
+ end
141
+
142
+ def self.format_script(record)
143
+ table = Terminal::Table.new title: SCRIPT_TITLE do |t|
144
+ t.add_row([record.script])
145
+ end
146
+ puts table
147
+ puts "\n"
148
+ end
149
+
150
+ def self.format_executor(record)
151
+ return '-' unless o = record.executor
152
+ type = o.type.singularize.gsub('_instance','')
153
+ "#{type}:#{o.name}"
154
+ end
155
+ end
156
+ end
157
+ end
@@ -124,6 +124,14 @@ module NexClient
124
124
  end
125
125
  end
126
126
 
127
+ def hash_from_file(file)
128
+ if file =~ /(\.yml|\.yaml)$/
129
+ YAML.load_file(file)
130
+ else
131
+ JSON.parse(File.read(file))
132
+ end
133
+ end
134
+
127
135
  # Parse plain or yaml file
128
136
  def vars_from_file(file,prefix = nil,&block)
129
137
  # YAML file
@@ -6,5 +6,11 @@ module NexClient
6
6
  property :total_pu, type: :int
7
7
  property :available_pu, type: :int
8
8
  property :used_pu, type: :int
9
+ property :private_ip_address, type: :string
10
+
11
+ # Alias method does not seem to work properly
12
+ def name
13
+ private_ip_address
14
+ end
9
15
  end
10
16
  end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+ module NexClient
3
+ class ExecTask < BaseResource
4
+ property :active, type: :boolean
5
+ property :created_at, type: :time
6
+ property :updated_at, type: :time
7
+ property :last_run_at, type: :time
8
+ property :next_run_at, type: :time
9
+ end
10
+ end
@@ -3,5 +3,11 @@ module NexClient
3
3
  class GatewayRack < BaseResource
4
4
  property :created_at, type: :time
5
5
  property :updated_at, type: :time
6
+ property :private_ip_address, type: :string
7
+
8
+ # Alias method does not seem to work properly
9
+ def name
10
+ private_ip_address
11
+ end
6
12
  end
7
13
  end
@@ -3,5 +3,11 @@ module NexClient
3
3
  class RoutingRack < BaseResource
4
4
  property :created_at, type: :time
5
5
  property :updated_at, type: :time
6
+ property :private_ip_address, type: :string
7
+
8
+ # Alias method does not seem to work properly
9
+ def name
10
+ private_ip_address
11
+ end
6
12
  end
7
13
  end
@@ -6,5 +6,11 @@ module NexClient
6
6
  property :total_su, type: :int
7
7
  property :available_su, type: :int
8
8
  property :used_su, type: :int
9
+ property :private_ip_address, type: :string
10
+
11
+ # Alias method does not seem to work properly
12
+ def name
13
+ private_ip_address
14
+ end
9
15
  end
10
16
  end
@@ -1,3 +1,3 @@
1
1
  module NexClient
2
- VERSION ||= '0.16.0'
2
+ VERSION ||= '0.17.0'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nex_client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.16.0
4
+ version: 0.17.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Arnaud Lachaume
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-05-06 00:00:00.000000000 Z
11
+ date: 2017-12-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json_api_client
@@ -144,6 +144,7 @@ files:
144
144
  - lib/nex_client/commands/cube_instances.rb
145
145
  - lib/nex_client/commands/cube_templates.rb
146
146
  - lib/nex_client/commands/domains.rb
147
+ - lib/nex_client/commands/exec_tasks.rb
147
148
  - lib/nex_client/commands/helpers.rb
148
149
  - lib/nex_client/commands/organizations.rb
149
150
  - lib/nex_client/commands/racks.rb
@@ -154,6 +155,7 @@ files:
154
155
  - lib/nex_client/cube_template.rb
155
156
  - lib/nex_client/domain.rb
156
157
  - lib/nex_client/event.rb
158
+ - lib/nex_client/exec_task.rb
157
159
  - lib/nex_client/gateway_rack.rb
158
160
  - lib/nex_client/me.rb
159
161
  - lib/nex_client/organization.rb