proxes 0.9.7 → 0.9.8

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.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. metadata +4 -92
  3. data/.codeclimate.yml +0 -24
  4. data/.gitignore +0 -20
  5. data/.pryrc +0 -6
  6. data/.rspec +0 -2
  7. data/.rubocop.yml +0 -15
  8. data/.ruby-version +0 -1
  9. data/.travis.yml +0 -46
  10. data/Dockerfile +0 -42
  11. data/Gemfile +0 -4
  12. data/Gemfile.ci +0 -23
  13. data/Gemfile.deploy +0 -8
  14. data/Gemfile.deploy.lock +0 -147
  15. data/Gemfile.dev +0 -13
  16. data/LICENSE.txt +0 -8
  17. data/README.md +0 -98
  18. data/Rakefile +0 -23
  19. data/Vagrantfile +0 -47
  20. data/config.ru +0 -71
  21. data/config/puma.rb +0 -15
  22. data/config/settings.yml +0 -7
  23. data/deploy_docker.sh +0 -8
  24. data/docker-compose.yml +0 -20
  25. data/gulpfile.js +0 -80
  26. data/lib/ditty/components/proxes.rb +0 -80
  27. data/lib/proxes/controllers/permissions.rb +0 -41
  28. data/lib/proxes/controllers/search.rb +0 -45
  29. data/lib/proxes/controllers/status.rb +0 -115
  30. data/lib/proxes/forwarder.rb +0 -49
  31. data/lib/proxes/helpers/indices.rb +0 -33
  32. data/lib/proxes/loggers/elasticsearch.rb +0 -10
  33. data/lib/proxes/middleware/error_handling.rb +0 -62
  34. data/lib/proxes/middleware/metrics.rb +0 -25
  35. data/lib/proxes/middleware/security.rb +0 -59
  36. data/lib/proxes/models/permission.rb +0 -53
  37. data/lib/proxes/policies/permission_policy.rb +0 -37
  38. data/lib/proxes/policies/request/bulk_policy.rb +0 -24
  39. data/lib/proxes/policies/request/cat_policy.rb +0 -12
  40. data/lib/proxes/policies/request/create_policy.rb +0 -15
  41. data/lib/proxes/policies/request/index_policy.rb +0 -19
  42. data/lib/proxes/policies/request/root_policy.rb +0 -13
  43. data/lib/proxes/policies/request/search_policy.rb +0 -14
  44. data/lib/proxes/policies/request/snapshot_policy.rb +0 -15
  45. data/lib/proxes/policies/request/stats_policy.rb +0 -12
  46. data/lib/proxes/policies/request_policy.rb +0 -65
  47. data/lib/proxes/policies/status_policy.rb +0 -21
  48. data/lib/proxes/request.rb +0 -84
  49. data/lib/proxes/request/bulk.rb +0 -40
  50. data/lib/proxes/request/cat.rb +0 -32
  51. data/lib/proxes/request/create.rb +0 -33
  52. data/lib/proxes/request/index.rb +0 -33
  53. data/lib/proxes/request/root.rb +0 -11
  54. data/lib/proxes/request/search.rb +0 -37
  55. data/lib/proxes/request/snapshot.rb +0 -17
  56. data/lib/proxes/request/stats.rb +0 -35
  57. data/lib/proxes/services/es.rb +0 -34
  58. data/lib/proxes/services/listener.rb +0 -29
  59. data/lib/proxes/services/search.rb +0 -43
  60. data/lib/proxes/version.rb +0 -5
  61. data/migrate/20170209_permissions.rb +0 -13
  62. data/migrate/20170416_user_specific_permissions.rb +0 -9
  63. data/package.json +0 -35
  64. data/proxes.gemspec +0 -53
  65. data/public/browserconfig.xml +0 -9
  66. data/public/css/typeahead.css +0 -94
  67. data/public/images/apple-icon.png +0 -0
  68. data/public/images/favicon-16x16.png +0 -0
  69. data/public/images/favicon-32x32.png +0 -0
  70. data/public/images/launcher-icon-1x.png +0 -0
  71. data/public/images/launcher-icon-2x.png +0 -0
  72. data/public/images/launcher-icon-4x.png +0 -0
  73. data/public/images/mstile-150x150.png +0 -0
  74. data/public/images/safari-pinned-tab.svg +0 -43
  75. data/public/js/bundle.js +0 -43636
  76. data/public/js/typeahead.bundle.min.js +0 -8
  77. data/public/js/vendors.js +0 -1
  78. data/public/manifest.json +0 -25
  79. data/src/scripts/app.js +0 -12
  80. data/startup.sh +0 -19
  81. data/views/index.haml +0 -1
  82. data/views/layout.haml +0 -60
  83. data/views/partials/navbar.haml +0 -25
  84. data/views/permissions/display.haml +0 -27
  85. data/views/permissions/edit.haml +0 -11
  86. data/views/permissions/form.haml +0 -4
  87. data/views/permissions/index.haml +0 -32
  88. data/views/permissions/new.haml +0 -10
  89. data/views/search/index.haml +0 -95
  90. data/views/status/check.haml +0 -12
@@ -1,41 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'ditty/controllers/component'
4
- require 'proxes/models/permission'
5
- require 'ditty/policies/user_policy'
6
- require 'ditty/policies/role_policy'
7
- require 'proxes/policies/permission_policy'
8
-
9
- module ProxES
10
- class Permissions < Ditty::Component
11
- set model_class: Permission
12
-
13
- FILTERS = [
14
- { name: :user, field: 'user.email' },
15
- { name: :role, field: 'role.name' },
16
- { name: :verb }
17
- ].freeze
18
-
19
- SEARCHABLE = %i[pattern].freeze
20
-
21
- helpers do
22
- def user_options
23
- policy_scope(::Ditty::User).as_hash(:email, :email)
24
- end
25
-
26
- def role_options
27
- policy_scope(::Ditty::Role).as_hash(:name, :name)
28
- end
29
-
30
- def verb_options
31
- ProxES::Permission.verbs
32
- end
33
- end
34
-
35
- def find_template(views, name, engine, &block)
36
- super(views, name, engine, &block) # Root
37
- super(::Ditty::ProxES.view_folder, name, engine, &block) # This Component
38
- super(::Ditty::App.view_folder, name, engine, &block) # Ditty
39
- end
40
- end
41
- end
@@ -1,45 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'active_support/core_ext/object/blank'
4
- require 'ditty/controllers/application'
5
- require 'proxes/services/search'
6
-
7
- module ProxES
8
- class Search < Ditty::Application
9
- set base_path: "#{settings.map_path}/search"
10
-
11
- get '/' do
12
- page = (params['page'] || 1).to_i
13
- size = (params['count'] || 25).to_i
14
- from = ((page - 1) * size)
15
- params['q'] = '*' if params['q'].blank?
16
- result = ProxES::Services::Search.search(params['q'], index: params['indices'], from: from, size: size)
17
- haml :"#{view_location}/index",
18
- locals: {
19
- title: 'Search',
20
- indices: ProxES::Services::Search.indices,
21
- fields: ProxES::Services::Search.fields(params['indices']),
22
- result: result
23
- }
24
- end
25
-
26
- get '/fields/?:indices?/?' do
27
- json ProxES::Services::Search.fields params['indices']
28
- end
29
-
30
- get '/indices/?' do
31
- json ProxES::Services::Search.indices
32
- end
33
-
34
- get '/values/:field/?:indices?/?' do |field|
35
- size = params['size'] || 25
36
- json ProxES::Services::Search.values(field, size: size, index: params['indices'])
37
- end
38
-
39
- def find_template(views, name, engine, &block)
40
- super(views, name, engine, &block) # Root
41
- super(::Ditty::ProxES.view_folder, name, engine, &block) # This Component
42
- super(::Ditty::App.view_folder, name, engine, &block) # Ditty
43
- end
44
- end
45
- end
@@ -1,115 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'ditty/controllers/application'
4
- require 'proxes/policies/status_policy'
5
- require 'proxes/services/es'
6
-
7
- module ProxES
8
- class Status < Ditty::Application
9
- helpers ProxES::Services::ES
10
-
11
- def find_template(views, name, engine, &block)
12
- super(views, name, engine, &block) # Root
13
- super(::Ditty::ProxES.view_folder, name, engine, &block) # This Component
14
- super(::Ditty::App.view_folder, name, engine, &block) # Ditty
15
- end
16
-
17
- # This provides a URL that can be polled by a monitoring system. It will return
18
- # 200 OK if all the checks pass, or 500 if any of the checks fail.
19
- get '/check' do
20
- checks = []
21
- begin
22
- health = client.cluster.health level: 'cluster'
23
- checks << { text: 'Cluster Reachable', passed: true, value: health['cluster_name'] }
24
- checks << { text: 'Cluster Health', passed: health['status'] == 'green', value: health['status'] }
25
-
26
- node_stats = client.nodes.stats
27
-
28
- master_nodes = []
29
- data_nodes = []
30
- ingestion_nodes = []
31
- node_stats['nodes'].each_value do |node|
32
- if node['roles']
33
- master_nodes << node['name'] if node['roles'].include? 'master'
34
- data_nodes << node['name'] if node['roles'].include? 'data'
35
- ingestion_nodes << node['name'] if node['roles'].include? 'ingest'
36
- elsif node['attributes']
37
- master_nodes << node['name'] unless node['attributes']['master'] == 'false'
38
- data_nodes << node['name'] unless node['attributes']['data'] == 'false'
39
- ingestion_nodes << node['name'] unless node['attributes']['ingest'] == 'false'
40
- elsif node['settings']
41
- master_nodes << node['name'] unless node['settings']['node']['master'] == 'false'
42
- data_nodes << node['name'] unless node['settings']['node']['data'] == 'false'
43
- ingestion_nodes << node['name'] unless node['settings']['node']['ingest'] == 'false'
44
- end
45
- end
46
- checks << {
47
- text: 'Master Nodes',
48
- passed: master_nodes.count > 0,
49
- value: master_nodes.count > 0 ? master_nodes.sort : 'None'
50
- }
51
- checks << {
52
- text: 'Data Nodes',
53
- passed: data_nodes.count > 0,
54
- value: data_nodes.count > 0 ? data_nodes.sort : 'None'
55
- }
56
- checks << {
57
- text: 'Ingestion Nodes',
58
- passed: true,
59
- value: ingestion_nodes.count > 0 ? ingestion_nodes.sort : 'None'
60
- }
61
-
62
- jvm_values = []
63
- jvm_passed = true
64
- node_stats['nodes'].each_value do |node|
65
- jvm_values << "#{node['name']}: #{node['jvm']['mem']['heap_used_percent']}%"
66
- jvm_passed = false if node['jvm']['mem']['heap_used_percent'] > 85
67
- end
68
- checks << { text: 'Node JVM Heap', passed: jvm_passed, value: jvm_values.sort }
69
-
70
- fs_values = []
71
- fs_passed = true
72
- node_stats['nodes'].each_value do |node|
73
- next if node['attributes'] && node['attributes']['data'] == 'false'
74
- next if node['roles'] && node['roles'].include?('data') == false
75
- stats = node['fs']['total']
76
- left = stats['available_in_bytes'] / stats['total_in_bytes'].to_f * 100
77
- fs_values << "#{node['name']}: #{format('%.02f', left)}% Free"
78
- fs_passed = false if left < 10
79
- end
80
- checks << { text: 'Node File Systems', passed: fs_passed, value: fs_values.sort }
81
-
82
- cpu_values = []
83
- cpu_passed = true
84
- node_stats['nodes'].each_value do |node|
85
- value = (node['os']['cpu_percent'] || node['os']['cpu']['percent'])
86
- cpu_values << "#{node['name']}: #{value}"
87
- cpu_passed = false if value.to_i > 70
88
- end
89
- checks << { text: 'Node CPU Usage', passed: cpu_passed, value: cpu_values.sort }
90
-
91
- memory_values = []
92
- memory_sum = 0
93
- node_stats['nodes'].each_value do |node|
94
- memory_sum += node['os']['mem']['used_percent']
95
- memory_values << "#{node['name']}: #{node['os']['mem']['used_percent']}"
96
- end
97
- memory_passed = (memory_sum / memory_values.size).to_i < 100
98
- checks << { text: 'Node Memory Usage', passed: memory_passed, value: memory_values.sort }
99
- rescue Faraday::Error => e
100
- checks << { text: 'Cluster Reachable', passed: false, value: e.message }
101
- end
102
-
103
- status checks.find { |c| c[:passed] == false } ? 500 : 200
104
-
105
- respond_to do |format|
106
- format.html do
107
- haml :'status/check', locals: { title: 'Status Check', checks: checks }
108
- end
109
- format.json do
110
- json checks
111
- end
112
- end
113
- end
114
- end
115
- end
@@ -1,49 +0,0 @@
1
- require 'proxes/services/es'
2
- require 'net/http/persistent'
3
- require 'singleton'
4
- require 'rack'
5
-
6
- module ProxES
7
- # A lot of code in this comes from Rack::Proxy
8
- class Forwarder
9
- include Singleton
10
- include ProxES::Services::ES
11
-
12
- def call(env)
13
- source = Rack::Request.new(env)
14
- response = conn.send(source.request_method.downcase) do |req|
15
- source_body = body_from(source)
16
- req.body = source_body if source_body
17
- req.url source.fullpath == '' ? URI.parse(env['REQUEST_URI']).request_uri : source.fullpath
18
- end
19
- mangle response
20
- end
21
-
22
- def mangle(response)
23
- headers = (response.respond_to?(:headers) && response.headers) || self.class.normalize_headers(response.to_hash)
24
- body = response.body || ['']
25
- body = [body] unless body.respond_to?(:each)
26
-
27
- # Not sure where this is coming from, but it causes timeouts on the client
28
- headers.delete('transfer-encoding')
29
- # Ensure that the content length rack middleware kicks in
30
- headers.delete('content-length')
31
-
32
- [response.status, headers, body]
33
- end
34
-
35
- def body_from(request)
36
- return nil if request.body.nil? || (Kernel.const_defined?('::Puma::NullIO') && request.body.is_a?(Puma::NullIO))
37
- request.body.read.tap { |_r| request.body.rewind }
38
- end
39
-
40
- class << self
41
- def normalize_headers(headers)
42
- mapped = headers.map do |k, v|
43
- [k, v.is_a?(Array) ? v.join("\n") : v]
44
- end
45
- Rack::Utils::HeaderHash.new Hash[mapped]
46
- end
47
- end
48
- end
49
- end
@@ -1,33 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'active_support'
4
- require 'active_support/core_ext/object/blank'
5
-
6
- module ProxES
7
- module Helpers
8
- module Indices
9
- def filter(asked, against)
10
- return against.map { |a| a.gsub(/\.\*/, '*') } if asked == ['*'] || asked.blank?
11
-
12
- answer = []
13
- against.each do |pattern|
14
- answer.concat(asked.select { |idx| idx =~ /#{pattern}/ })
15
- end
16
- answer
17
- end
18
-
19
- def patterns
20
- return [] if user.nil?
21
- patterns_for('INDEX').map do |permission|
22
- return nil if permission.pattern.blank?
23
- permission.pattern.gsub(/\{user.(.*)\}/) { |_match| user.send(Regexp.last_match[1].to_sym) }
24
- end.compact
25
- end
26
-
27
- def patterns_for(action)
28
- return [] if user.nil?
29
- Permission.for_user(user, action)
30
- end
31
- end
32
- end
33
- end
@@ -1,10 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'logger'
4
-
5
- module ProxES
6
- module Loggers
7
- class Elasticsearch < ::Logger
8
- end
9
- end
10
- end
@@ -1,62 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'wisper'
4
- require 'proxes/request'
5
- require 'ditty/services/logger'
6
-
7
- module ProxES
8
- module Middleware
9
- class ErrorHandling
10
- attr_reader :logger
11
-
12
- include Wisper::Publisher
13
-
14
- def initialize(app, logger = nil)
15
- @app = app
16
- @logger = logger || ::Ditty::Services::Logger.instance
17
- end
18
-
19
- def call(env)
20
- request = ProxES::Request.from_env(env)
21
- response = @app.call env
22
- broadcast(:es_request_failed, request, response) unless (200..299).cover?(response[0])
23
- response
24
- rescue Errno::EHOSTUNREACH
25
- error 'Could not reach Elasticsearch at ' + ENV['ELASTICSEARCH_URL']
26
- rescue Errno::ECONNREFUSED, Faraday::ConnectionFailed, SocketError
27
- error 'Elasticsearch not listening at ' + ENV['ELASTICSEARCH_URL']
28
- rescue Pundit::NotAuthorizedError, Ditty::Helpers::NotAuthenticated => e
29
- broadcast(:es_request_denied, request, e)
30
- log_not_authorized request
31
- raise e if env['APP_ENV'] == 'development'
32
- request.html? && request.user.nil? ? login_and_redirect(request) : error('Not Authorized', 401)
33
- rescue StandardError => e
34
- broadcast(:es_request_denied, request, e)
35
- log_not_authorized request
36
- raise e if env['APP_ENV'] == 'development'
37
- error 'Forbidden', 403
38
- end
39
-
40
- def log_not_authorized(request)
41
- user = request.user ? request.user.email : 'unauthenticated request'
42
- logger.error "Access denied for #{user} by security layer: #{request.detail}"
43
- end
44
-
45
- # Response Helpers
46
- def error(message, code = 500)
47
- headers = { 'Content-Type' => 'application/json' }
48
- headers['WWW-Authenticate'] = 'Basic realm="security"' if code == 401
49
- [code, headers, ['{"error":"' + message + '"}']]
50
- end
51
-
52
- def login_and_redirect(request)
53
- request.session['omniauth.origin'] = request.url unless request.url == '/_proxes/auth/identity'
54
- redirect '/_proxes/auth/identity'
55
- end
56
-
57
- def redirect(destination, code = 302)
58
- [code, { 'Location' => destination }, []]
59
- end
60
- end
61
- end
62
- end
@@ -1,25 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'wisper'
4
-
5
- module ProxES
6
- module Middleware
7
- class Metrics
8
- include Wisper::Publisher
9
-
10
- def initialize(app)
11
- @app = app
12
- end
13
-
14
- def call(env)
15
- request = Request.from_env(env)
16
- broadcast(:call_started, request)
17
-
18
- result = @app.call request.env
19
-
20
- broadcast(:call_completed, request) if result[0].to_i >= 200 && result[0].to_i < 300
21
- result
22
- end
23
- end
24
- end
25
- end
@@ -1,59 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'proxes/request'
4
- require 'proxes/policies/request_policy'
5
- require 'ditty/services/logger'
6
- require 'ditty/helpers/pundit'
7
- require 'ditty/helpers/authentication'
8
-
9
- module ProxES
10
- module Middleware
11
- class Security
12
- attr_reader :env, :logger
13
-
14
- include Ditty::Helpers::Authentication
15
- include Ditty::Helpers::Pundit
16
-
17
- def initialize(app, logger = nil)
18
- @app = app
19
- @logger = logger || ::Ditty::Services::Logger.instance
20
- end
21
-
22
- def call(env)
23
- @env = env
24
- request = ProxES::Request.from_env(env)
25
- log(request, 'BEFORE')
26
-
27
- check_basic request
28
- authorize request
29
-
30
- request.index = policy_scope(request) if request.indices?
31
- log(request, 'AFTER')
32
-
33
- @app.call env
34
- end
35
-
36
- def check_basic(request)
37
- auth = Rack::Auth::Basic::Request.new(request.env)
38
- return false unless auth.provided? && auth.basic?
39
-
40
- identity = ::Ditty::Identity.find(username: auth.credentials[0])
41
- identity ||= ::Ditty::Identity.find(username: CGI.unescape(auth.credentials[0]))
42
- return false unless identity && identity.authenticate(auth.credentials[1])
43
- request.env['rack.session'] ||= {}
44
- request.env['rack.session']['user_id'] = identity.user_id
45
- end
46
-
47
- def authorize(request)
48
- Pundit.authorize(request.user, request, request.request_method.downcase + '?')
49
- end
50
-
51
- def log(request, stage)
52
- logger.debug '============' + stage.ljust(56) + '============'
53
- logger.debug '= ' + "Request: #{request.detail}".ljust(76) + ' ='
54
- logger.debug '= ' + "Endpoint: #{request.endpoint}".ljust(76) + ' ='
55
- logger.debug '================================================================================'
56
- end
57
- end
58
- end
59
- end