kumonos 0.8.0 → 0.8.1

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: e8bce93ae7e9f596bc9be6c4095b9e743536ff10
4
- data.tar.gz: e3d0d47a86b65f3434e5b10757e543105ead5385
3
+ metadata.gz: afaa277aeea2b85f5bc5620bdb387aa5a9d0a26e
4
+ data.tar.gz: 3819d46ee9f7b0dc92b2509e75661be77212e9ca
5
5
  SHA512:
6
- metadata.gz: cc1a11c5f9762e9eb7463447ed8c4b4b30127c9185e5cad69ba5fe5d73839a67a4d54d8729511b66d68a1f34026261eaf84b74ba9c40bbda9309bb1836ad4324
7
- data.tar.gz: 2384a77f383f890ffdc67c1f1c8a24ac6b36303a4a50a242e87c4251f7b9011b47ee91c5a8510df55312038b31bcd9affd584b2d6311d3e8e0236a6dd9f7a0ab
6
+ metadata.gz: a39107a4642db4fb6129956013e248b2737edc05589025fcaa2afd707f8461fced00bb3c335cec08826aa69e6792b5dd6ff53060088cf0248e208613dca40e3b
7
+ data.tar.gz: deee3de7fdb0e54a86a6902a0ba037a2c5b69d617c07b9141ebb12d40abb43aa8ab8a9783805b9d4efd4eac590210aa3fa8689a6267378152f0d84b5d3782902
data/exe/kumonos CHANGED
@@ -14,10 +14,8 @@ class KumonosCli < Thor
14
14
  desc 'envoy ENVOY_DEFINITION', 'Generate envoy configuration'
15
15
  def envoy(path)
16
16
  validate_path!(path)
17
- h = JSON.parse(File.read(path))
18
- validate_envoy_definition!(h, path)
19
-
20
- definition = Kumonos::EnvoyDefinition.from_hash(h)
17
+ definition = JSON.parse(File.read(path))
18
+ validate_envoy_definition!(definition, path)
21
19
  puts JSON.dump(Kumonos::Envoy.generate(definition))
22
20
  end
23
21
 
@@ -4,25 +4,47 @@ module Kumonos
4
4
  class << self
5
5
  def generate(definition)
6
6
  {
7
- clusters: definition['dependencies'].map { |s| service_to_cluster(s) }
7
+ clusters: definition['dependencies'].map { |s| Cluster.build(s).to_h }
8
8
  }
9
9
  end
10
+ end
10
11
 
11
- private
12
+ Cluster = Struct.new(:name, :connect_timeout_ms, :lb, :tls, :circuit_breaker) do
13
+ class << self
14
+ def build(h)
15
+ new(
16
+ h.fetch('name'),
17
+ h.fetch('connect_timeout_ms'),
18
+ h.fetch('lb'),
19
+ h.fetch('tls'),
20
+ CircuitBreaker.build(h.fetch('circuit_breaker'))
21
+ )
22
+ end
23
+ end
12
24
 
13
- def service_to_cluster(service)
14
- out = {
15
- name: service['name'],
16
- connect_timeout_ms: service['connect_timeout_ms'],
17
- type: 'strict_dns',
18
- lb_type: 'round_robin',
19
- hosts: [{ url: "tcp://#{service['lb']}" }],
20
- circuit_breakers: {
21
- default: service['circuit_breaker']
22
- }
23
- }
24
- out[:ssl_context] = {} if service['tls']
25
- out
25
+ def to_h
26
+ h = super
27
+
28
+ h.delete(:lb)
29
+ h[:type] = 'strict_dns'
30
+ h[:lb_type] = 'round_robin'
31
+ h[:hosts] = [{ url: "tcp://#{lb}" }]
32
+
33
+ h.delete(:tls)
34
+ h[:ssl_context] = {} if tls
35
+
36
+ h.delete(:circuit_breaker)
37
+ h[:circuit_breakers] = { default: circuit_breaker.to_h }
38
+
39
+ h
40
+ end
41
+ end
42
+
43
+ CircuitBreaker = Struct.new(:max_connections, :max_pending_requests, :max_retries) do
44
+ class << self
45
+ def build(h)
46
+ new(h.fetch('max_connections'), h.fetch('max_pending_requests'), h.fetch('max_retries'))
47
+ end
26
48
  end
27
49
  end
28
50
  end
data/lib/kumonos/envoy.rb CHANGED
@@ -2,49 +2,113 @@ module Kumonos
2
2
  # Generate envoy configuration.
3
3
  module Envoy
4
4
  class << self
5
- # @param [Kumonos::EnvoyDefinition] definition
6
- # @return [Hash] envoy configuration hash
7
5
  def generate(definition)
8
- out = {
9
- listeners: [
10
- {
11
- address: definition.listener.fetch(:address),
12
- filters: [
13
- type: 'read',
14
- name: 'http_connection_manager',
15
- config: {
16
- codec_type: 'auto',
17
- stat_prefix: 'ingress_http',
18
- access_log: [{ path: definition.listener.fetch(:access_log_path) }],
19
- rds: {
20
- cluster: definition.ds.fetch(:cluster).fetch(:name),
21
- route_config_name: DEFAULT_ROUTE_NAME,
22
- refresh_delay_ms: definition.ds.fetch(:refresh_delay_ms)
23
- },
24
- filters: [{ type: 'decoder', name: 'router', config: {} }]
25
- }
26
- ]
27
- }
28
- ],
29
- admin: {
30
- access_log_path: definition.admin.fetch(:access_log_path),
31
- address: definition.admin.fetch(:address)
32
- },
33
- cluster_manager: {
34
- clusters: [],
35
- cds: {
36
- cluster: definition.ds.fetch(:cluster),
37
- refresh_delay_ms: definition.ds.fetch(:refresh_delay_ms)
6
+ EnvoyConfig.build(definition).to_h
7
+ end
8
+ end
9
+
10
+ EnvoyConfig = Struct.new(:version, :ds, :statsd, :listener, :admin) do
11
+ class << self
12
+ def build(h)
13
+ ds = DiscoverService.build(h.fetch('ds'))
14
+ new(
15
+ h.fetch('version'),
16
+ ds,
17
+ h['statsd'] ? Cluster.build(h['statsd']) : nil,
18
+ Listener.build(h.fetch('listener'), ds),
19
+ Admin.build(h.fetch('admin'))
20
+ )
21
+ end
22
+ end
23
+
24
+ def to_h
25
+ h = super
26
+ h.delete(:version)
27
+ h.delete(:ds)
28
+ h.delete(:statsd)
29
+ h.delete(:listener)
30
+ h[:admin] = admin.to_h
31
+ h[:listeners] = [listener.to_h]
32
+ h[:cluster_manager] = { cds: ds.to_h, clusters: [] }
33
+
34
+ if statsd
35
+ h[:statsd_tcp_cluster_name] = statsd.name
36
+ h[:cluster_manager][:clusters] << statsd.to_h
37
+ end
38
+
39
+ h
40
+ end
41
+ end
42
+
43
+ Listener = Struct.new(:address, :access_log_path, :ds) do
44
+ class << self
45
+ def build(h, ds)
46
+ new(h.fetch('address'), h.fetch('access_log_path'), ds)
47
+ end
48
+ end
49
+
50
+ def to_h
51
+ h = super
52
+ h.delete(:ds)
53
+ h.delete(:access_log_path)
54
+ h[:filters] = [
55
+ {
56
+ type: 'read',
57
+ name: 'http_connection_manager',
58
+ config: {
59
+ codec_type: 'auto',
60
+ stat_prefix: 'ingress_http',
61
+ access_log: [{ path: access_log_path }],
62
+ rds: {
63
+ cluster: ds.cluster.name,
64
+ route_config_name: DEFAULT_ROUTE_NAME,
65
+ refresh_delay_ms: ds.refresh_delay_ms
66
+ },
67
+ filters: [{ type: 'decoder', name: 'router', config: {} }]
38
68
  }
39
69
  }
40
- }
70
+ ]
71
+ h
72
+ end
73
+ end
41
74
 
42
- unless definition.statsd.empty?
43
- out[:statsd_tcp_cluster_name] = definition.statsd.fetch(:name)
44
- out[:cluster_manager][:clusters] << definition.statsd
75
+ DiscoverService = Struct.new(:refresh_delay_ms, :cluster) do
76
+ class << self
77
+ def build(h)
78
+ new(h.fetch('refresh_delay_ms'), Cluster.build(h.fetch('cluster')))
45
79
  end
80
+ end
46
81
 
47
- out
82
+ def to_h
83
+ h = super
84
+ h[:cluster] = cluster.to_h
85
+ h
86
+ end
87
+ end
88
+
89
+ Cluster = Struct.new(:name, :type, :tls, :connect_timeout_ms, :lb_type, :hosts) do
90
+ class << self
91
+ def build(h)
92
+ new(h.fetch('name'), h.fetch('type'), h.fetch('tls'), h.fetch('connect_timeout_ms'), h.fetch('lb_type'), h.fetch('hosts'))
93
+ end
94
+ end
95
+
96
+ def to_h
97
+ h = super
98
+ if tls
99
+ cluster[:ssl_context] = {}
100
+ else
101
+ h.delete(:tls)
102
+ end
103
+ h
104
+ end
105
+ end
106
+
107
+ Admin = Struct.new(:address, :access_log_path) do
108
+ class << self
109
+ def build(h)
110
+ new(h.fetch('address'), h.fetch('access_log_path'))
111
+ end
48
112
  end
49
113
  end
50
114
  end
@@ -5,34 +5,54 @@ module Kumonos
5
5
  def generate(definition)
6
6
  {
7
7
  validate_clusters: false,
8
- virtual_hosts: definition['dependencies'].map { |s| service_to_vhost(s) }
8
+ virtual_hosts: definition['dependencies'].map { |s| Vhost.build(s).to_h }
9
9
  }
10
10
  end
11
+ end
11
12
 
12
- private
13
+ Vhost = Struct.new(:name, :domains, :routes) do
14
+ class << self
15
+ def build(h)
16
+ name = h.fetch('name')
17
+ routes = h.fetch('routes').map { |r| Route.build(r, name) }
18
+ new(name, [name], routes)
19
+ end
20
+ end
13
21
 
14
- def service_to_vhost(service)
15
- name = service['name']
16
- {
17
- name: name,
18
- domains: [name],
19
- routes: service['routes'].flat_map { |r| split_route(r, name) }
20
- }
22
+ def to_h
23
+ h = super
24
+ h[:routes] = routes.flat_map { |r| [r.to_h_with_retry, r.to_h] }
25
+ h
21
26
  end
27
+ end
22
28
 
23
- # Split route definition to apply retry definition only to GET/HEAD requests.
24
- def split_route(route, name)
25
- base = {
26
- prefix: route['prefix'],
27
- timeout_ms: route['timeout_ms'],
28
- auto_host_rewrite: true,
29
- cluster: name
30
- }
31
- with_retry = base.merge(
32
- retry_policy: route['retry_policy'],
33
- headers: [{ name: ':method', value: '(GET|HEAD)', regex: true }]
34
- )
35
- [with_retry, base]
29
+ Route = Struct.new(:prefix, :cluster, :timeout_ms, :retry_policy) do
30
+ class << self
31
+ def build(h, cluster)
32
+ new(h.fetch('prefix'), cluster, h.fetch('timeout_ms'), RetryPolicy.build(h.fetch('retry_policy')))
33
+ end
34
+ end
35
+
36
+ def to_h
37
+ h = super
38
+ h.delete(:retry_policy)
39
+ h[:auto_host_rewrite] = true
40
+ h
41
+ end
42
+
43
+ def to_h_with_retry
44
+ h = to_h
45
+ h[:retry_policy] = retry_policy.to_h
46
+ h[:headers] = [{ name: ':method', value: '(GET|HEAD)', regex: true }]
47
+ h
48
+ end
49
+ end
50
+
51
+ RetryPolicy = Struct.new(:retry_on, :num_retries, :per_try_timeout_ms) do
52
+ class << self
53
+ def build(h)
54
+ new(h.fetch('retry_on'), h.fetch('num_retries'), h.fetch('per_try_timeout_ms'))
55
+ end
36
56
  end
37
57
  end
38
58
  end
@@ -1,3 +1,3 @@
1
1
  module Kumonos
2
- VERSION = '0.8.0'.freeze
2
+ VERSION = '0.8.1'.freeze
3
3
  end
data/lib/kumonos.rb CHANGED
@@ -3,7 +3,6 @@ require 'yaml'
3
3
 
4
4
  require 'kumonos/version'
5
5
  require 'kumonos/schemas'
6
- require 'kumonos/envoy_definition'
7
6
  require 'kumonos/envoy'
8
7
  require 'kumonos/routes'
9
8
  require 'kumonos/clusters'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kumonos
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.8.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Taiki Ono
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-11-12 00:00:00.000000000 Z
11
+ date: 2017-11-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json-schema
@@ -167,7 +167,6 @@ files:
167
167
  - lib/kumonos.rb
168
168
  - lib/kumonos/clusters.rb
169
169
  - lib/kumonos/envoy.rb
170
- - lib/kumonos/envoy_definition.rb
171
170
  - lib/kumonos/output.rb
172
171
  - lib/kumonos/routes.rb
173
172
  - lib/kumonos/schemas.rb
@@ -194,7 +193,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
194
193
  version: '0'
195
194
  requirements: []
196
195
  rubyforge_project:
197
- rubygems_version: 2.5.2.1
196
+ rubygems_version: 2.6.13
198
197
  signing_key:
199
198
  specification_version: 4
200
199
  summary: A "control plane" for Microservices "service mesh".
@@ -1,36 +0,0 @@
1
- module Kumonos
2
- EnvoyDefinition = Struct.new(:version, :ds, :statsd, :listener, :admin) do
3
- class << self
4
- def from_hash(h)
5
- ds = symbolize_keys(h.fetch('ds'))
6
- convert_tls_option!(ds.fetch(:cluster))
7
-
8
- new(
9
- h.fetch('version'),
10
- ds,
11
- convert_tls_option!(symbolize_keys(h.fetch('statsd', {}))),
12
- symbolize_keys(h.fetch('listener')),
13
- symbolize_keys(h.fetch('admin'))
14
- )
15
- end
16
-
17
- private
18
-
19
- def convert_tls_option!(cluster)
20
- tls = cluster.delete(:tls)
21
- cluster[:ssl_context] = {} if tls
22
- cluster
23
- end
24
-
25
- def symbolize_keys(hash)
26
- new = hash.map do |k, v|
27
- [
28
- k.to_sym,
29
- v.is_a?(Hash) ? symbolize_keys(v) : v
30
- ]
31
- end
32
- new.to_h
33
- end
34
- end
35
- end
36
- end