istox_gruf 2.7.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +246 -0
  3. data/CODE_OF_CONDUCT.md +46 -0
  4. data/README.md +544 -0
  5. data/bin/gruf +29 -0
  6. data/lib/gruf.rb +50 -0
  7. data/lib/gruf/cli/executor.rb +99 -0
  8. data/lib/gruf/client.rb +217 -0
  9. data/lib/gruf/client/error.rb +66 -0
  10. data/lib/gruf/client/error_factory.rb +105 -0
  11. data/lib/gruf/configuration.rb +137 -0
  12. data/lib/gruf/controllers/base.rb +102 -0
  13. data/lib/gruf/controllers/request.rb +121 -0
  14. data/lib/gruf/controllers/service_binder.rb +117 -0
  15. data/lib/gruf/error.rb +230 -0
  16. data/lib/gruf/errors/debug_info.rb +56 -0
  17. data/lib/gruf/errors/field.rb +56 -0
  18. data/lib/gruf/errors/helpers.rb +44 -0
  19. data/lib/gruf/hooks/base.rb +34 -0
  20. data/lib/gruf/hooks/executor.rb +47 -0
  21. data/lib/gruf/hooks/registry.rb +159 -0
  22. data/lib/gruf/instrumentable_grpc_server.rb +64 -0
  23. data/lib/gruf/integrations/rails/railtie.rb +10 -0
  24. data/lib/gruf/interceptors/active_record/connection_reset.rb +48 -0
  25. data/lib/gruf/interceptors/authentication/basic.rb +87 -0
  26. data/lib/gruf/interceptors/base.rb +53 -0
  27. data/lib/gruf/interceptors/client_interceptor.rb +125 -0
  28. data/lib/gruf/interceptors/context.rb +56 -0
  29. data/lib/gruf/interceptors/instrumentation/output_metadata_timer.rb +61 -0
  30. data/lib/gruf/interceptors/instrumentation/request_logging/formatters/base.rb +41 -0
  31. data/lib/gruf/interceptors/instrumentation/request_logging/formatters/logstash.rb +43 -0
  32. data/lib/gruf/interceptors/instrumentation/request_logging/formatters/plain.rb +48 -0
  33. data/lib/gruf/interceptors/instrumentation/request_logging/interceptor.rb +225 -0
  34. data/lib/gruf/interceptors/instrumentation/statsd.rb +82 -0
  35. data/lib/gruf/interceptors/registry.rb +161 -0
  36. data/lib/gruf/interceptors/server_interceptor.rb +34 -0
  37. data/lib/gruf/interceptors/timer.rb +85 -0
  38. data/lib/gruf/loggable.rb +30 -0
  39. data/lib/gruf/logging.rb +53 -0
  40. data/lib/gruf/outbound/request_context.rb +71 -0
  41. data/lib/gruf/response.rb +71 -0
  42. data/lib/gruf/serializers/errors/base.rb +57 -0
  43. data/lib/gruf/serializers/errors/json.rb +43 -0
  44. data/lib/gruf/server.rb +294 -0
  45. data/lib/gruf/synchronized_client.rb +97 -0
  46. data/lib/gruf/timer.rb +78 -0
  47. data/lib/gruf/version.rb +20 -0
  48. metadata +203 -0
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # coding: utf-8
3
+ # Copyright (c) 2017-present, BigCommerce Pty. Ltd. All rights reserved
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
6
+ # documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
7
+ # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
8
+ # persons to whom the Software is furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
11
+ # Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
14
+ # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
15
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
16
+ # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
17
+ #
18
+ require 'rubygems'
19
+ require 'bundler/setup'
20
+ begin
21
+ require 'rails'
22
+ rescue LoadError
23
+ nil
24
+ end
25
+ load 'config/environment.rb' if defined?(Rails)
26
+ require 'gruf'
27
+
28
+ cli = Gruf::Cli::Executor.new
29
+ cli.run
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (c) 2017-present, BigCommerce Pty. Ltd. All rights reserved
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
6
+ # documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
7
+ # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
8
+ # persons to whom the Software is furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
11
+ # Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
14
+ # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
15
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
16
+ # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
17
+ #
18
+ require 'grpc'
19
+ require 'active_support/core_ext/module/delegation'
20
+ require 'active_support/concern'
21
+ require 'active_support/inflector'
22
+ require 'base64'
23
+ require_relative 'gruf/version'
24
+ require_relative 'gruf/logging'
25
+ require_relative 'gruf/loggable'
26
+ require_relative 'gruf/configuration'
27
+ require_relative 'gruf/errors/helpers'
28
+ require_relative 'gruf/cli/executor'
29
+ require_relative 'gruf/controllers/base'
30
+ require_relative 'gruf/outbound/request_context'
31
+ require_relative 'gruf/interceptors/registry'
32
+ require_relative 'gruf/interceptors/base'
33
+ require_relative 'gruf/hooks/registry'
34
+ require_relative 'gruf/hooks/executor'
35
+ require_relative 'gruf/hooks/base'
36
+ require_relative 'gruf/timer'
37
+ require_relative 'gruf/response'
38
+ require_relative 'gruf/error'
39
+ require_relative 'gruf/client'
40
+ require_relative 'gruf/synchronized_client'
41
+ require_relative 'gruf/instrumentable_grpc_server'
42
+ require_relative 'gruf/server'
43
+ require_relative 'gruf/integrations/rails/railtie' if defined?(Rails)
44
+
45
+ ##
46
+ # Initializes configuration of gruf core module
47
+ #
48
+ module Gruf
49
+ extend Configuration
50
+ end
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (c) 2017-present, BigCommerce Pty. Ltd. All rights reserved
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
6
+ # documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
7
+ # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
8
+ # persons to whom the Software is furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
11
+ # Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
14
+ # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
15
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
16
+ # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
17
+ #
18
+ require 'slop'
19
+
20
+ module Gruf
21
+ module Cli
22
+ ##
23
+ # Handles execution of the gruf binstub, along with command-line arguments
24
+ #
25
+ class Executor
26
+ ##
27
+ # @param [Hash|ARGV]
28
+ #
29
+ def initialize(
30
+ args = ARGV,
31
+ server: nil,
32
+ services: nil,
33
+ hook_executor: nil,
34
+ logger: nil
35
+ )
36
+ @args = args
37
+ setup! # ensure we set some defaults from CLI here so we can allow configuration
38
+ @services = services || Gruf.services
39
+ @hook_executor = hook_executor || Gruf::Hooks::Executor.new(hooks: Gruf.hooks&.prepare)
40
+ @server = server || Gruf::Server.new(Gruf.server_options)
41
+ @logger = logger || Gruf.logger || ::Logger.new(STDERR)
42
+ end
43
+
44
+ ##
45
+ # Run the server
46
+ #
47
+ def run
48
+ exception = nil
49
+ begin
50
+ @services.each { |s| @server.add_service(s) }
51
+ @hook_executor.call(:before_server_start, server: @server)
52
+ @server.start!
53
+ rescue StandardError => e
54
+ exception = e
55
+ # Catch the exception here so that we always ensure the post hook runs
56
+ # This allows systems wanting to provide external server instrumentation
57
+ # the ability to properly handle server failures
58
+ @logger.fatal("FATAL ERROR: #{e.message} #{e.backtrace.join("\n")}")
59
+ end
60
+ @hook_executor.call(:after_server_stop, server: @server)
61
+ raise exception if exception
62
+
63
+ if @server.required_restart
64
+ restart
65
+ end
66
+ end
67
+
68
+ def restart
69
+ @server = Gruf::Server.new(Gruf.server_options)
70
+ run
71
+ end
72
+
73
+ private
74
+
75
+ ##
76
+ # Setup options for CLI execution and configure Gruf based on inputs
77
+ #
78
+ def setup!
79
+ opts = Slop.parse(@args) do |o|
80
+ o.null '-h', '--help', 'Display help message' do
81
+ puts o
82
+ exit(0)
83
+ end
84
+ o.string '--host', 'Specify the binding url for the gRPC service'
85
+ o.bool '--suppress-default-interceptors', 'Do not use the default interceptors'
86
+ o.bool '--backtrace-on-error', 'Push backtraces on exceptions to the error serializer'
87
+ o.null '-v', '--version', 'print gruf version' do
88
+ puts Gruf::VERSION
89
+ exit(0)
90
+ end
91
+ end
92
+
93
+ Gruf.server_binding_url = opts[:host] if opts[:host]
94
+ Gruf.use_default_interceptors = false if opts.suppress_default_interceptors?
95
+ Gruf.backtrace_on_error = true if opts.backtrace_on_error?
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,217 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (c) 2017-present, BigCommerce Pty. Ltd. All rights reserved
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
6
+ # documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
7
+ # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
8
+ # persons to whom the Software is furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
11
+ # Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
14
+ # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
15
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
16
+ # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
17
+ #
18
+ require_relative 'client/error'
19
+ require_relative 'client/error_factory'
20
+
21
+ module Gruf
22
+ ##
23
+ # Abstracts out the calling interface for interacting with gRPC clients. Streamlines calling and provides
24
+ # instrumented response objects that also can contain deserialized error messages via serialized objects transported
25
+ # via the service's trailing metadata.
26
+ #
27
+ # begin
28
+ # client = ::Gruf::Client.new(service: ::Demo::ThingService)
29
+ # response = client.call(:GetMyThing, id: 123)
30
+ # puts response.message.inspect
31
+ # rescue Gruf::Client::Error => e
32
+ # puts e.error.inspect
33
+ # end
34
+ #
35
+ # Utilizes SimpleDelegator to wrap the given service that the client is connecting to, which allows a clean interface
36
+ # to the underlying RPC descriptors and methods.
37
+ #
38
+ class Client < SimpleDelegator
39
+ include Gruf::Loggable
40
+
41
+ # @return [Class] The base, friendly name of the service being requested
42
+ attr_reader :base_klass
43
+ # @return [Class] The class name of the gRPC service being requested
44
+ attr_reader :service_klass
45
+ # @return [Hash] A hash of options for the client
46
+ attr_reader :opts
47
+
48
+ ##
49
+ # Initialize the client and setup the stub
50
+ #
51
+ # @param [Module] service The namespace of the client Stub that is desired to load
52
+ # @param [Hash] options A hash of options for the client
53
+ # @option options [String] :password The password for basic authentication for the service.
54
+ # @option options [String] :hostname The hostname of the service. Defaults to linkerd.
55
+ # @param [Hash] client_options A hash of options to pass to the gRPC client stub
56
+ #
57
+ def initialize(service:, options: {}, client_options: {})
58
+ @base_klass = service
59
+ @service_klass = "#{base_klass}::Service".constantize
60
+ @opts = options || {}
61
+ @opts[:password] = @opts.fetch(:password, '').to_s
62
+ @opts[:hostname] = @opts.fetch(:hostname, Gruf.default_client_host)
63
+ @error_factory = Gruf::Client::ErrorFactory.new
64
+ client_options[:timeout] = client_options[:timeout].to_i if client_options.key?(:timeout)
65
+ client = "#{service}::Stub".constantize.new(@opts[:hostname], build_ssl_credentials, client_options)
66
+ super(client)
67
+ end
68
+
69
+ ##
70
+ # Call the client's method with given params
71
+ #
72
+ # @param [String|Symbol] request_method The method that is being requested on the service
73
+ # @param [Hash] params (Optional) A hash of parameters that will be inserted into the gRPC request message that is
74
+ # required for the given above call
75
+ # @param [Hash] metadata (Optional) A hash of metadata key/values that are transported with the client request
76
+ # @param [Hash] opts (Optional) A hash of options to send to the gRPC request_response method
77
+ # @return [Gruf::Response] The response from the server
78
+ # @raise [Gruf::Client::Error|GRPC::BadStatus] If an error occurs, an exception will be raised according to the
79
+ # error type that was returned
80
+ #
81
+ def call(request_method, params = {}, metadata = {}, opts = {}, &block)
82
+ request_method = request_method.to_sym
83
+ req = streaming_request?(request_method) ? params : request_object(request_method, params)
84
+ md = build_metadata(metadata)
85
+ call_sig = call_signature(request_method)
86
+
87
+ unless call_sig
88
+ raise NotImplementedError, "The method #{request_method} has not been implemented in this service."
89
+ end
90
+
91
+ resp, operation = execute(call_sig, req, md, opts, &block)
92
+
93
+ raise @error_factory.from_exception(resp.result) unless resp.success?
94
+
95
+ Gruf::Response.new(operation: operation, message: resp.result, execution_time: resp.time)
96
+ end
97
+
98
+ ##
99
+ # Returns the currently set timeout on the client stub
100
+ #
101
+ # @return [Integer|NilClass]
102
+ #
103
+ def timeout
104
+ __getobj__.instance_variable_get(:@timeout)
105
+ end
106
+
107
+ private
108
+
109
+ ##
110
+ # @param [Symbol] request_method
111
+ # @return [Boolean]
112
+ #
113
+ def streaming_request?(request_method)
114
+ desc = rpc_desc(request_method)
115
+ desc && (desc.client_streamer? || desc.bidi_streamer?)
116
+ end
117
+
118
+ ##
119
+ # Execute the given request to the service
120
+ #
121
+ # @param [Symbol] call_sig The call signature being executed
122
+ # @param [Object] req (Optional) The protobuf request message to send
123
+ # @param [Hash] metadata (Optional) A hash of metadata key/values that are transported with the client request
124
+ # @param [Hash] opts (Optional) A hash of options to send to the gRPC request_response method
125
+ # @return [Array<Gruf::Timer::Result, GRPC::ActiveCall::Operation>]
126
+ #
127
+ def execute(call_sig, req, metadata, opts = {}, &block)
128
+ operation = nil
129
+ result = Gruf::Timer.time do
130
+ opts[:return_op] = true
131
+ opts[:metadata] = metadata
132
+ operation = send(call_sig, req, opts, &block)
133
+ operation.execute
134
+ end
135
+ [result, operation]
136
+ end
137
+
138
+ ##
139
+ # Get the appropriate RPC descriptor given the method on the service being called
140
+ #
141
+ # @param [Symbol] request_method The method name being called on the remote service
142
+ # @return [Struct<GRPC::RpcDesc>] Return the given RPC descriptor given the method on the service being called
143
+ #
144
+ def rpc_desc(request_method)
145
+ service_klass.rpc_descs[request_method]
146
+ end
147
+
148
+ ##
149
+ # Get the appropriate protobuf request message for the given request method on the service being called
150
+ #
151
+ # @param [Symbol] request_method The method name being called on the remote service
152
+ # @param [Hash] params (Optional) A hash of parameters that will populate the request object
153
+ # @return [Class] The request object that corresponds to the method being called
154
+ #
155
+ def request_object(request_method, params = {})
156
+ desc = rpc_desc(request_method)
157
+ desc&.input ? desc.input.new(params) : nil
158
+ end
159
+
160
+ ##
161
+ # Properly find the appropriate call signature for the GRPC::GenericService given the request method name
162
+ #
163
+ # @return [Symbol]
164
+ #
165
+ def call_signature(request_method)
166
+ desc = rpc_desc(request_method)
167
+ desc&.name ? desc.name.to_s.underscore.to_sym : nil
168
+ end
169
+
170
+ ##
171
+ # Build a sanitized, authenticated metadata hash for the given request
172
+ #
173
+ # @param [Hash] metadata A base metadata hash to build from
174
+ # @return [Hash] The compiled metadata hash that is ready to be transported over the wire
175
+ #
176
+ def build_metadata(metadata = {})
177
+ unless opts[:password].empty?
178
+ username = opts.fetch(:username, 'grpc').to_s
179
+ username = username.empty? ? '' : "#{username}:"
180
+ auth_string = Base64.encode64("#{username}#{opts[:password]}")
181
+ metadata[:authorization] = "Basic #{auth_string}".tr("\n", '')
182
+ end
183
+ metadata
184
+ end
185
+
186
+ ##
187
+ # Build the SSL/TLS credentials for the outbound gRPC request
188
+ #
189
+ # @return [Symbol|GRPC::Core::ChannelCredentials] The generated SSL credentials for the outbound gRPC request
190
+ #
191
+ # :nocov:
192
+ def build_ssl_credentials
193
+ cert = nil
194
+ if opts[:ssl_certificate_file]
195
+ cert = File.read(opts[:ssl_certificate_file]).to_s.strip
196
+ elsif opts[:ssl_certificate]
197
+ cert = opts[:ssl_certificate].to_s.strip
198
+ end
199
+
200
+ cert ? GRPC::Core::ChannelCredentials.new(cert) : :this_channel_is_insecure
201
+ end
202
+ # :nocov:
203
+
204
+ ##
205
+ # Return the specified error deserializer class by the configuration
206
+ #
207
+ # @return [Class] The proper error deserializer class. Defaults to JSON.
208
+ #
209
+ def error_deserializer_class
210
+ if Gruf.error_serializer
211
+ Gruf.error_serializer.is_a?(Class) ? Gruf.error_serializer : Gruf.error_serializer.to_s.constantize
212
+ else
213
+ Gruf::Serializers::Errors::Json
214
+ end
215
+ end
216
+ end
217
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (c) 2017-present, BigCommerce Pty. Ltd. All rights reserved
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
6
+ # documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
7
+ # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
8
+ # persons to whom the Software is furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
11
+ # Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
14
+ # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
15
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
16
+ # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
17
+ #
18
+ module Gruf
19
+ class Client < SimpleDelegator
20
+ ##
21
+ # Represents an error that was returned from the server's trailing metadata. Used as a custom exception object
22
+ # that is instead raised in the case of the service returning serialized error data, as opposed to the normal
23
+ # GRPC::BadStatus error
24
+ #
25
+ class Error < StandardError
26
+ # @return [Object] error The deserialized error
27
+ attr_reader :error
28
+
29
+ ##
30
+ # Initialize the client error
31
+ #
32
+ # @param [Object] error The deserialized error
33
+ #
34
+ def initialize(error)
35
+ @error = error
36
+ end
37
+ end
38
+
39
+ ##
40
+ # See https://github.com/grpc/grpc-go/blob/master/codes/codes.go for a detailed summary of each error type
41
+ #
42
+ module Errors
43
+ class Base < Gruf::Client::Error; end
44
+ class Error < Base; end
45
+ class Validation < Base; end
46
+
47
+ class Ok < Base; end
48
+
49
+ class InvalidArgument < Validation; end
50
+ class NotFound < Validation; end
51
+ class AlreadyExists < Validation; end
52
+ class OutOfRange < Validation; end
53
+
54
+ class Cancelled < Error; end
55
+ class DataLoss < Error; end
56
+ class DeadlineExceeded < Error; end
57
+ class FailedPrecondition < Error; end
58
+ class Internal < Error; end
59
+ class PermissionDenied < Error; end
60
+ class Unauthenticated < Error; end
61
+ class Unavailable < Error; end
62
+ class Unimplemented < Error; end
63
+ class Unknown < Error; end
64
+ end
65
+ end
66
+ end