nex_client 0.16.0 → 0.17.0

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
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