kumonos 0.8.0 → 0.8.1

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