kumonos 0.3.1 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c1fae897610887b93621540db85b472393a017d3
4
- data.tar.gz: df13da5be9a09a42c0cf5a5cb9443aa28e9744b4
3
+ metadata.gz: 3180e4389f67a7973e06cc18560503ebe4606e3a
4
+ data.tar.gz: 5e104c41129d76a4628cd02dcb68df71c3c55e36
5
5
  SHA512:
6
- metadata.gz: c1b80378899957b98c5cdef91af4f420c194155893300b6fd21d14d6cb7b8ed7ae610bc9b049109c29ab5c723111058922935167fb3fb36cca9a2ef3d59e6554
7
- data.tar.gz: cfca16fb8e5693bc26b82fae2f3aee19cf96505410b5802b7768d44ec6b2f31fd9d48aca672f6db881bbac0b902dbd2072a30239b5ac007a60295b3d20814e26
6
+ metadata.gz: 551f54b256647e1b04e9c25e26d774b9a85f2d295b28628999fdc18ace1db1bb299534649382823bda7a5d8bd341d57c62e215fa95d8c464d003112d53e7e6e4
7
+ data.tar.gz: cc933fb394e59ef965612a90f20ed3df3af1f9f12ffe590fed577f38db6c84783952003630d96f9e87491884d424ccd63f0dcd8fa0af4af77cc038d18e883916
data/.rspec CHANGED
@@ -1,3 +1,2 @@
1
- --format documentation
2
1
  --color
3
2
  --require spec_helper
data/example/book.yml CHANGED
@@ -1,9 +1,10 @@
1
- # A definition for book service.
1
+ # A example definition for book service.
2
2
  # The book service uses user service and ab-testing service.
3
3
  version: 1
4
4
  dependencies:
5
5
  - name: 'user'
6
6
  lb: 'user:8080'
7
+ tls: false
7
8
  connect_timeout_ms: 250
8
9
  circuit_breaker:
9
10
  max_connections: 64
@@ -18,6 +19,7 @@ dependencies:
18
19
  per_try_timeout_ms: 1000
19
20
  - name: 'ab-testing'
20
21
  lb: 'ab-testing:8080'
22
+ tls: false
21
23
  connect_timeout_ms: 250
22
24
  circuit_breaker:
23
25
  max_connections: 64
@@ -0,0 +1,18 @@
1
+ # Example for using TLS
2
+ version: 1
3
+ dependencies:
4
+ - name: 'example'
5
+ lb: 'example.com:443'
6
+ tls: true
7
+ connect_timeout_ms: 250
8
+ circuit_breaker:
9
+ max_connections: 64
10
+ max_pending_requests: 128
11
+ max_retries: 3
12
+ routes:
13
+ - prefix: '/'
14
+ timeout_ms: 3000
15
+ retry_policy:
16
+ retry_on: '5xx,connect-failure,refused-stream'
17
+ num_retries: 3
18
+ per_try_timeout_ms: 1000
data/exe/kumonos CHANGED
@@ -3,54 +3,52 @@
3
3
 
4
4
  $LOAD_PATH.unshift(File.expand_path('../lib', __dir__))
5
5
  require 'kumonos'
6
-
7
- require 'pathname'
8
6
  require 'thor'
9
7
 
10
8
  # KumonosCli
11
9
  class KumonosCli < Thor
12
- desc 'envoy SERVIVE_NAME', 'Generate envoy configuration'
13
- method_option :config, aliases: '-c', desc: 'Configuration file for kumonos'
14
- def envoy(service_name)
15
- h = JSON.parse(File.read(options[:config]))
16
- result = Kumonos::Schemas.validate_kumonos_config(h)
17
- unless result.empty?
18
- warn("#{options[:config]} has invalid format:")
19
- warn(result)
20
- warn("A schema file for kumonos-configuration is #{Kumonos::Schemas::CONFIG_SCHEMA_PATH}")
21
- exit 1
22
- end
23
-
24
- config = Kumonos::Configuration.from_hash(h)
25
- puts JSON.dump(Kumonos.generate(config, service_name))
10
+ def self.exit_on_failure?
11
+ true
12
+ end
13
+
14
+ desc 'envoy ENVOY_DEFINITION', 'Generate envoy configuration'
15
+ def envoy(path)
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)
21
+ puts JSON.dump(Kumonos::Envoy.generate(definition))
26
22
  end
27
23
 
28
- desc 'clusters FILEPATH OUT', 'Generate clusters configuration'
29
- def clusters(filepath, output_dir)
30
- name = File.basename(filepath, '.*')
24
+ desc 'clusters SERVIVE_DEFINITION', 'Generate clusters configuration'
25
+ method_option :output, aliases: '-o', desc: 'Output directory', required: true, type: :string
26
+ def clusters(filepath)
27
+ output_dir = options.fetch(:output)
28
+ validate_path!(filepath)
29
+ validate_path!(output_dir)
30
+
31
31
  definition = YAML.load_file(filepath)
32
32
  validate_service_definition!(definition, filepath)
33
- out = JSON.dump(Kumonos.generate_clusters(definition))
33
+ json = JSON.dump(Kumonos::Clusters.generate(definition))
34
34
 
35
- output_dir = Pathname.new(output_dir)
36
- target = output_dir.join('v1', 'clusters', name, name)
37
- target.parent.mkpath unless target.parent.exist?
38
- target.write(out)
39
- puts target
35
+ output = Kumonos::Output.new(output_dir, :clusters, File.basename(filepath, '.*'))
36
+ puts output.write(json)
40
37
  end
41
38
 
42
- desc 'routes FILEPATH OUT', 'Generate routes configuration'
43
- def routes(filepath, output_dir)
44
- name = File.basename(filepath, '.*')
39
+ desc 'routes SERVIVE_DEFINITION', 'Generate routes configuration'
40
+ method_option :output, aliases: '-o', desc: 'Output directory', required: true, type: :string
41
+ def routes(filepath)
42
+ output_dir = options.fetch(:output)
43
+ validate_path!(filepath)
44
+ validate_path!(output_dir)
45
+
45
46
  definition = YAML.load_file(filepath)
46
47
  validate_service_definition!(definition, filepath)
47
- out = JSON.dump(Kumonos.generate_routes(definition))
48
+ json = JSON.dump(Kumonos::Routes.generate(definition))
48
49
 
49
- output_dir = Pathname.new(output_dir)
50
- target = output_dir.join('v1', 'routes', name, name, name)
51
- target.parent.mkpath unless target.parent.exist?
52
- target.write(out)
53
- puts target
50
+ output = Kumonos::Output.new(output_dir, :routes, File.basename(filepath, '.*'))
51
+ puts output.write(json)
54
52
  end
55
53
 
56
54
  desc 'init NAME', 'Generate a service definition'
@@ -67,13 +65,29 @@ class KumonosCli < Thor
67
65
 
68
66
  private
69
67
 
70
- def validate_service_definition!(definition, filepath)
71
- result = Kumonos::Schemas.validate_service_definition(definition)
68
+ def validate_path!(path)
69
+ return if File.exist?(path)
70
+
71
+ warn("No such file or directory: #{path}")
72
+ exit 1
73
+ end
74
+
75
+ def validate_envoy_definition!(h, path)
76
+ result = Kumonos::Schemas.validate_envoy_definition(h)
72
77
  return if result.empty?
78
+ warn_and_exit(result, path, Kumonos::Schemas::ENVOY_SCHEMA_PATH)
79
+ end
80
+
81
+ def validate_service_definition!(h, path)
82
+ result = Kumonos::Schemas.validate_service_definition(h)
83
+ return if result.empty?
84
+ warn_and_exit(result, path, Kumonos::Schemas::SERVIVE_DEFINITION_PATH)
85
+ end
73
86
 
74
- warn("#{filepath} has invalid format:")
87
+ def warn_and_exit(result, path, schema_path)
88
+ warn("#{path} has invalid format:")
75
89
  warn(result)
76
- warn("A schema file is #{Kumonos::Schemas::SERVIVE_DEFINITION_PATH}")
90
+ warn("The schema file is #{schema_path}")
77
91
  exit 1
78
92
  end
79
93
  end
data/kumonos.gemspec CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |spec|
8
8
  spec.authors = ['Taiki Ono']
9
9
  spec.email = ['taiks.4559@gmail.com']
10
10
 
11
- spec.summary = 'Manage configuration for Service Mesh.'
11
+ spec.summary = 'A management tool for building Microservices "service mesh".'
12
12
  spec.description = spec.summary
13
13
  spec.homepage = 'https://github.com/taiki45/kumonos'
14
14
  spec.license = 'MIT'
@@ -0,0 +1,29 @@
1
+ module Kumonos
2
+ # Generate clusters configuration.
3
+ module Clusters
4
+ class << self
5
+ def generate(definition)
6
+ {
7
+ clusters: definition['dependencies'].map { |s| service_to_cluster(s) }
8
+ }
9
+ end
10
+
11
+ private
12
+
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
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,45 @@
1
+ module Kumonos
2
+ # Generate envoy configuration.
3
+ module Envoy
4
+ class << self
5
+ # @param [Kumonos::EnvoyDefinition] definition
6
+ # @return [Hash] envoy configuration hash
7
+ def generate(definition)
8
+ {
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(: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
+ statsd_tcp_cluster_name: definition.statsd.fetch(:name),
34
+ cluster_manager: {
35
+ clusters: [definition.statsd],
36
+ cds: {
37
+ cluster: definition.ds.fetch(:cluster),
38
+ refresh_delay_ms: definition.ds.fetch(:refresh_delay_ms)
39
+ }
40
+ }
41
+ }
42
+ end
43
+ end
44
+ end
45
+ end
@@ -1,5 +1,5 @@
1
1
  module Kumonos
2
- Configuration = Struct.new(:version, :ds, :statsd, :listener, :admin) do
2
+ EnvoyDefinition = Struct.new(:version, :ds, :statsd, :listener, :admin) do
3
3
  class << self
4
4
  def from_hash(h)
5
5
  new(
@@ -0,0 +1,27 @@
1
+ require 'pathname'
2
+
3
+ module Kumonos
4
+ # Output manipulation.
5
+ class Output
6
+ def initialize(dir, type, name)
7
+ @dir = Pathname.new(dir)
8
+ @type = type
9
+ @name = name
10
+ end
11
+
12
+ def write(json)
13
+ target =
14
+ case @type
15
+ when :clusters
16
+ @dir.join('v1', 'clusters', @name, @name)
17
+ when :routes
18
+ @dir.join('v1', 'routes', Kumonos::DEFAULT_ROUTE_NAME, @name, @name)
19
+ else
20
+ raise %(Unknown type "#{@type}" given)
21
+ end
22
+ target.parent.mkpath unless target.parent.exist?
23
+ target.write(json)
24
+ target
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,38 @@
1
+ module Kumonos
2
+ # Generate routes configuration
3
+ module Routes
4
+ class << self
5
+ def generate(definition)
6
+ {
7
+ validate_clusters: false,
8
+ virtual_hosts: definition['dependencies'].map { |s| service_to_vhost(s) }
9
+ }
10
+ end
11
+
12
+ private
13
+
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
+ }
21
+ end
22
+
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
+ cluster: name
29
+ }
30
+ with_retry = base.merge(
31
+ retry_policy: route['retry_policy'],
32
+ headers: [{ name: ':method', value: '(GET|HEAD)', regex: true }]
33
+ )
34
+ [with_retry, base]
35
+ end
36
+ end
37
+ end
38
+ end
@@ -5,12 +5,12 @@ module Kumonos
5
5
  # Schemas
6
6
  module Schemas
7
7
  ROOT = Pathname.new(File.expand_path('../schemas', __dir__))
8
- CONFIG_SCHEMA_PATH = ROOT.join('kumonos_config.json')
8
+ ENVOY_SCHEMA_PATH = ROOT.join('envoy.json')
9
9
  SERVIVE_DEFINITION_PATH = ROOT.join('service_definition.json')
10
10
 
11
11
  class << self
12
- def validate_kumonos_config(hash)
13
- schema = load_schema(CONFIG_SCHEMA_PATH)
12
+ def validate_envoy_definition(hash)
13
+ schema = load_schema(ENVOY_SCHEMA_PATH)
14
14
  JSON::Validator.fully_validate(schema, hash)
15
15
  end
16
16
 
@@ -1,3 +1,3 @@
1
1
  module Kumonos
2
- VERSION = '0.3.1'.freeze
2
+ VERSION = '0.4.0'.freeze
3
3
  end
data/lib/kumonos.rb CHANGED
@@ -3,97 +3,13 @@ require 'yaml'
3
3
 
4
4
  require 'kumonos/version'
5
5
  require 'kumonos/schemas'
6
- require 'kumonos/configuration'
6
+ require 'kumonos/envoy_definition'
7
+ require 'kumonos/envoy'
8
+ require 'kumonos/routes'
9
+ require 'kumonos/clusters'
10
+ require 'kumonos/output'
7
11
 
8
12
  # Kumonos
9
13
  module Kumonos
10
- class << self
11
- def generate(config, name)
12
- {
13
- listeners: [
14
- {
15
- address: config.listener.fetch(:address),
16
- filters: [
17
- type: 'read',
18
- name: 'http_connection_manager',
19
- config: {
20
- codec_type: 'auto',
21
- stat_prefix: 'ingress_http',
22
- access_log: [{ path: config.listener.fetch(:access_log_path) }],
23
- rds: {
24
- cluster: config.ds.fetch(:name),
25
- route_config_name: name,
26
- refresh_delay_ms: config.ds.fetch(:refresh_delay_ms)
27
- },
28
- filters: [{ type: 'decoder', name: 'router', config: {} }]
29
- }
30
- ]
31
- }
32
- ],
33
- admin: {
34
- access_log_path: config.admin.fetch(:access_log_path),
35
- address: config.admin.fetch(:address)
36
- },
37
- statsd_tcp_cluster_name: config.statsd.fetch(:name),
38
- cluster_manager: {
39
- clusters: [config.statsd],
40
- cds: {
41
- cluster: config.ds.fetch(:cluster),
42
- refresh_delay_ms: config.ds.fetch(:refresh_delay_ms)
43
- }
44
- }
45
- }
46
- end
47
-
48
- def generate_routes(definition)
49
- {
50
- validate_clusters: false,
51
- virtual_hosts: definition['dependencies'].map { |s| service_to_vhost(s) }
52
- }
53
- end
54
-
55
- def generate_clusters(definition)
56
- {
57
- clusters: definition['dependencies'].map { |s| service_to_cluster(s) }
58
- }
59
- end
60
-
61
- private
62
-
63
- def service_to_vhost(service)
64
- name = service['name']
65
- {
66
- name: name,
67
- domains: [name],
68
- routes: service['routes'].flat_map { |r| split_route(r, name) }
69
- }
70
- end
71
-
72
- # Split route definition to apply retry definition only to GET/HEAD requests.
73
- def split_route(route, name)
74
- base = {
75
- prefix: route['prefix'],
76
- timeout_ms: route['timeout_ms'],
77
- cluster: name
78
- }
79
- with_retry = base.merge(
80
- retry_policy: route['retry_policy'],
81
- headers: [{ name: ':method', value: '(GET|HEAD)', regex: true }]
82
- )
83
- [with_retry, base]
84
- end
85
-
86
- def service_to_cluster(service)
87
- {
88
- name: service['name'],
89
- connect_timeout_ms: service['connect_timeout_ms'],
90
- type: 'strict_dns',
91
- lb_type: 'round_robin',
92
- hosts: [{ url: "tcp://#{service['lb']}" }],
93
- circuit_breakers: {
94
- default: service['circuit_breaker']
95
- }
96
- }
97
- end
98
- end
14
+ DEFAULT_ROUTE_NAME = 'default'.freeze
99
15
  end
@@ -24,6 +24,7 @@
24
24
  "required": [
25
25
  "name",
26
26
  "lb",
27
+ "tls",
27
28
  "connect_timeout_ms",
28
29
  "circuit_breaker",
29
30
  "routes"
@@ -39,6 +40,11 @@
39
40
  "id": "/properties/dependencies/items/properties/lb",
40
41
  "default": "host:port"
41
42
  },
43
+ "tls": {
44
+ "type": "boolean",
45
+ "id": "/properties/dependencies/items/properties/tls",
46
+ "default": false
47
+ },
42
48
  "connect_timeout_ms": {
43
49
  "type": "integer",
44
50
  "id": "/properties/dependencies/items/properties/connect_timeout_ms",
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.3.1
4
+ version: 0.4.0
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-06 00:00:00.000000000 Z
11
+ date: 2017-11-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json-schema
@@ -122,7 +122,7 @@ dependencies:
122
122
  - - "~>"
123
123
  - !ruby/object:Gem::Version
124
124
  version: 0.51.0
125
- description: Manage configuration for Service Mesh.
125
+ description: A management tool for building Microservices "service mesh".
126
126
  email:
127
127
  - taiks.4559@gmail.com
128
128
  executables:
@@ -142,14 +142,19 @@ files:
142
142
  - bin/setup
143
143
  - bump
144
144
  - example/book.yml
145
- - example/kumonos.json
145
+ - example/envoy.json
146
+ - example/example-with-tls.yml
146
147
  - exe/kumonos
147
148
  - kumonos.gemspec
148
149
  - lib/kumonos.rb
149
- - lib/kumonos/configuration.rb
150
+ - lib/kumonos/clusters.rb
151
+ - lib/kumonos/envoy.rb
152
+ - lib/kumonos/envoy_definition.rb
153
+ - lib/kumonos/output.rb
154
+ - lib/kumonos/routes.rb
150
155
  - lib/kumonos/schemas.rb
151
156
  - lib/kumonos/version.rb
152
- - lib/schemas/kumonos_config.json
157
+ - lib/schemas/envoy.json
153
158
  - lib/schemas/service_definition.json
154
159
  homepage: https://github.com/taiki45/kumonos
155
160
  licenses:
@@ -174,5 +179,5 @@ rubyforge_project:
174
179
  rubygems_version: 2.5.2.1
175
180
  signing_key:
176
181
  specification_version: 4
177
- summary: Manage configuration for Service Mesh.
182
+ summary: A management tool for building Microservices "service mesh".
178
183
  test_files: []
File without changes
File without changes