boring_services 0.3.0 → 0.4.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 +4 -4
- data/lib/boring_services/railtie.rb +6 -0
- data/lib/boring_services/service_locator.rb +105 -0
- data/lib/boring_services/services/redis.rb +2 -1
- data/lib/boring_services/version.rb +1 -1
- data/lib/boring_services.rb +62 -7
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 156bb67ea987370602ed678f3d8a525f6eeae09dcbc2a3ae8ac23fa85b474ca4
|
|
4
|
+
data.tar.gz: 8ce1325011cac932711b77afed6a5d0307bebedaa4e52fc2b65d9a153daf2e91
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 72bf5746276b30243a9b75b8091491afd3e58e5e8feac6b3a8f62bc7cafa8f9088d6d1f279f075b6f3f77d0f350017a4bf277e18a3ef4844d273293fb2f3b363
|
|
7
|
+
data.tar.gz: 07ac07fe8b309a06ff23ca77a7681aab03c77d8ecc0fac5e86e6723c999eb05976827e2bafdd072f7dfc0eef700c731329402a627b6ab64d2492983aaf6d125f
|
|
@@ -5,6 +5,12 @@ begin
|
|
|
5
5
|
class Railtie < Rails::Railtie
|
|
6
6
|
railtie_name :boring_services
|
|
7
7
|
|
|
8
|
+
# Initialize service locator after Rails config is loaded
|
|
9
|
+
initializer 'boring_services.initialize' do
|
|
10
|
+
# Reset locator so it picks up the correct Rails environment
|
|
11
|
+
BoringServices.reset_locator!
|
|
12
|
+
end
|
|
13
|
+
|
|
8
14
|
rake_tasks do
|
|
9
15
|
load File.expand_path('../tasks/services.rake', __dir__)
|
|
10
16
|
end
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module BoringServices
|
|
4
|
+
class ServiceLocator
|
|
5
|
+
attr_reader :config
|
|
6
|
+
|
|
7
|
+
def initialize(config = nil)
|
|
8
|
+
@config = config || Configuration.load
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# Get all hosts for a service
|
|
12
|
+
# Returns array of host hashes with :host, :private_ip, :label keys
|
|
13
|
+
def hosts_for(service_name)
|
|
14
|
+
service = config.service_config(service_name.to_s)
|
|
15
|
+
return [] unless service
|
|
16
|
+
|
|
17
|
+
normalize_hosts(service['hosts'] || [])
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Get the connection IP for a service by region/label
|
|
21
|
+
# Prefers private_ip, falls back to host
|
|
22
|
+
# Label matching: "redis-eu" matches region "eu", "redis-us" matches "us"
|
|
23
|
+
def host_for_region(service_name, region)
|
|
24
|
+
return nil if region.to_s.strip.empty?
|
|
25
|
+
|
|
26
|
+
hosts = hosts_for(service_name)
|
|
27
|
+
host_entry = hosts.find do |h|
|
|
28
|
+
label = h[:label].to_s.downcase
|
|
29
|
+
region_str = region.to_s.downcase
|
|
30
|
+
label == region_str || label.end_with?("-#{region_str}") || label.start_with?("#{region_str}-")
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
return nil unless host_entry
|
|
34
|
+
|
|
35
|
+
connection_ip(host_entry)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Get the first available host for a service (prefers private_ip)
|
|
39
|
+
def primary_host(service_name)
|
|
40
|
+
hosts = hosts_for(service_name)
|
|
41
|
+
return nil if hosts.empty?
|
|
42
|
+
|
|
43
|
+
connection_ip(hosts.first)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Get all connection IPs for a service (prefers private_ip for each)
|
|
47
|
+
def all_hosts(service_name)
|
|
48
|
+
hosts_for(service_name).map { |h| connection_ip(h) }
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Get port for a service
|
|
52
|
+
def port_for(service_name)
|
|
53
|
+
service = config.service_config(service_name.to_s)
|
|
54
|
+
service&.dig('port')
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Build a Redis URL for a region
|
|
58
|
+
def redis_url(region: nil, password: nil, db: 0)
|
|
59
|
+
host = region ? host_for_region('redis', region) : primary_host('redis')
|
|
60
|
+
return nil unless host
|
|
61
|
+
|
|
62
|
+
port = port_for('redis') || 6379
|
|
63
|
+
auth = password.to_s.empty? ? '' : ":#{password}@"
|
|
64
|
+
"redis://#{auth}#{host}:#{port}/#{db}"
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Build memcached connection string (host:port,host:port format)
|
|
68
|
+
def memcached_servers(region: nil)
|
|
69
|
+
hosts = if region
|
|
70
|
+
host = host_for_region('memcached', region)
|
|
71
|
+
host ? [host] : []
|
|
72
|
+
else
|
|
73
|
+
all_hosts('memcached')
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
return nil if hosts.empty?
|
|
77
|
+
|
|
78
|
+
port = port_for('memcached') || 11211
|
|
79
|
+
hosts.map { |h| "#{h}:#{port}" }.join(',')
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
private
|
|
83
|
+
|
|
84
|
+
# Normalize hosts array - handles both simple strings and hashes
|
|
85
|
+
def normalize_hosts(hosts)
|
|
86
|
+
hosts.map do |h|
|
|
87
|
+
if h.is_a?(Hash)
|
|
88
|
+
{
|
|
89
|
+
host: h['host'],
|
|
90
|
+
private_ip: h['private_ip'],
|
|
91
|
+
label: h['label']
|
|
92
|
+
}
|
|
93
|
+
else
|
|
94
|
+
{ host: h.to_s, private_ip: nil, label: nil }
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Get connection IP - prefer private_ip if available
|
|
100
|
+
def connection_ip(host_entry)
|
|
101
|
+
ip = host_entry[:private_ip].to_s.strip
|
|
102
|
+
ip.empty? ? host_entry[:host] : ip
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
@@ -33,9 +33,10 @@ module BoringServices
|
|
|
33
33
|
memory = memory_mb || 256
|
|
34
34
|
listen_port = port || 6379
|
|
35
35
|
password = resolve_secret('redis_password') if config.secrets['redis_password']
|
|
36
|
+
bind_address = private_ip.to_s.strip.empty? ? "0.0.0.0" : "127.0.0.1 #{private_ip}"
|
|
36
37
|
|
|
37
38
|
config_content = <<~REDIS
|
|
38
|
-
bind
|
|
39
|
+
bind #{bind_address}
|
|
39
40
|
port #{listen_port}
|
|
40
41
|
dir /var/lib/redis
|
|
41
42
|
maxmemory #{memory}mb
|
data/lib/boring_services.rb
CHANGED
|
@@ -5,6 +5,7 @@ require_relative 'boring_services/cli'
|
|
|
5
5
|
require_relative 'boring_services/installer'
|
|
6
6
|
require_relative 'boring_services/ssh_executor'
|
|
7
7
|
require_relative 'boring_services/health_checker'
|
|
8
|
+
require_relative 'boring_services/service_locator'
|
|
8
9
|
|
|
9
10
|
require_relative 'boring_services/services/base'
|
|
10
11
|
require_relative 'boring_services/services/memcached'
|
|
@@ -15,14 +16,68 @@ require_relative 'boring_services/services/nginx'
|
|
|
15
16
|
module BoringServices
|
|
16
17
|
class Error < StandardError; end
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
class << self
|
|
20
|
+
def root
|
|
21
|
+
File.expand_path('..', __dir__)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def status
|
|
25
|
+
config = Configuration.load
|
|
26
|
+
health_checker = HealthChecker.new(config)
|
|
27
|
+
health_checker.check_all
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Service locator instance (cached)
|
|
31
|
+
def locator
|
|
32
|
+
@locator ||= ServiceLocator.new
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Reset cached locator (useful for testing or config reload)
|
|
36
|
+
def reset_locator!
|
|
37
|
+
@locator = nil
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Convenience methods - delegate to locator
|
|
41
|
+
|
|
42
|
+
# Get Redis host for a region (e.g., "eu", "us")
|
|
43
|
+
def redis_host(region = nil)
|
|
44
|
+
region ? locator.host_for_region('redis', region) : locator.primary_host('redis')
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Get Redis port
|
|
48
|
+
def redis_port
|
|
49
|
+
locator.port_for('redis') || 6379
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Build Redis URL
|
|
53
|
+
def redis_url(region: nil, password: nil, db: 0)
|
|
54
|
+
locator.redis_url(region: region, password: password, db: db)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Get Memcached host for a region
|
|
58
|
+
def memcached_host(region = nil)
|
|
59
|
+
region ? locator.host_for_region('memcached', region) : locator.primary_host('memcached')
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Get Memcached port
|
|
63
|
+
def memcached_port
|
|
64
|
+
locator.port_for('memcached') || 11211
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Get Memcached servers string (host:port,host:port)
|
|
68
|
+
def memcached_servers(region: nil)
|
|
69
|
+
locator.memcached_servers(region: region)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Generic: get host for any service by region
|
|
73
|
+
def host_for(service, region = nil)
|
|
74
|
+
region ? locator.host_for_region(service, region) : locator.primary_host(service)
|
|
75
|
+
end
|
|
21
76
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
77
|
+
# Generic: get port for any service
|
|
78
|
+
def port_for(service)
|
|
79
|
+
locator.port_for(service)
|
|
80
|
+
end
|
|
26
81
|
end
|
|
27
82
|
end
|
|
28
83
|
require 'stringio'
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: boring_services
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- BoringCache
|
|
@@ -127,6 +127,7 @@ files:
|
|
|
127
127
|
- lib/boring_services/installer.rb
|
|
128
128
|
- lib/boring_services/railtie.rb
|
|
129
129
|
- lib/boring_services/secrets.rb
|
|
130
|
+
- lib/boring_services/service_locator.rb
|
|
130
131
|
- lib/boring_services/services/base.rb
|
|
131
132
|
- lib/boring_services/services/haproxy.rb
|
|
132
133
|
- lib/boring_services/services/memcached.rb
|