Class: Toxiproxy

Inherits:
Object
  • Object
show all
Extended by:
SingleForwardable
Defined in:
lib/toxiproxy.rb,
lib/toxiproxy/toxic.rb,
lib/toxiproxy/version.rb,
lib/toxiproxy/proxy_collection.rb,
lib/toxiproxy/toxic_collection.rb

Defined Under Namespace

Classes: InvalidToxic, NotFound, ProxyCollection, ProxyExists, Toxic, ToxicCollection

Constant Summary collapse

DEFAULT_URI =
'http://127.0.0.1:8474'
VALID_DIRECTIONS =
[:upstream, :downstream]
VERSION =
"2.0.2"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options) ⇒ Toxiproxy

Returns a new instance of Toxiproxy.



22
23
24
25
26
27
# File 'lib/toxiproxy.rb', line 22

def initialize(options)
  @upstream = options[:upstream]
  @listen   = options[:listen] || "localhost:0"
  @name     = options[:name]
  @enabled  = options[:enabled]
end

Instance Attribute Details

#enabledObject (readonly)

Returns the value of attribute enabled.



20
21
22
# File 'lib/toxiproxy.rb', line 20

def enabled
  @enabled
end

#listenObject (readonly)

Returns the value of attribute listen.



20
21
22
# File 'lib/toxiproxy.rb', line 20

def listen
  @listen
end

#nameObject (readonly)

Returns the value of attribute name.



20
21
22
# File 'lib/toxiproxy.rb', line 20

def name
  @name
end

Class Method Details

.[](query) ⇒ Object

If given a regex, it’ll use ‘grep` to return a Toxiproxy::Collection. Otherwise, it’ll convert the passed object to a string and find the proxy by name.



95
96
97
98
# File 'lib/toxiproxy.rb', line 95

def self.[](query)
  return grep(query) if query.is_a?(Regexp)
  find_by_name!(query)
end

.allObject

Returns a collection of all currently active Toxiproxies.



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/toxiproxy.rb', line 51

def self.all
  request = Net::HTTP::Get.new("/proxies")
  response = http_request(request)
  assert_response(response)

  proxies = JSON.parse(response.body).map { |name, attrs|
    self.new({
      upstream: attrs["upstream"],
      listen: attrs["listen"],
      name: attrs["name"],
      enabled: attrs["enabled"]
    })
  }

  ProxyCollection.new(proxies)
end

.create(options) ⇒ Object

Convenience method to create a proxy.



76
77
78
# File 'lib/toxiproxy.rb', line 76

def self.create(options)
  self.new(options).create
end

.find_by_name(name = nil, &block) ⇒ Object

Find a single proxy by name.



81
82
83
# File 'lib/toxiproxy.rb', line 81

def self.find_by_name(name = nil, &block)
  self.all.find { |p| p.name == name.to_s }
end

.find_by_name!(*args) ⇒ Object

Calls find_by_name and raises NotFound if not found

Raises:



86
87
88
89
90
# File 'lib/toxiproxy.rb', line 86

def self.find_by_name!(*args)
  proxy = find_by_name(*args)
  raise NotFound, "#{name} not found in #{self.all.map(&:name).join(', ')}" unless proxy
  proxy
end

.host=(host) ⇒ Object

Sets the toxiproxy host to use.



69
70
71
72
73
# File 'lib/toxiproxy.rb', line 69

def self.host=(host)
  @uri = host.is_a?(::URI) ? host : ::URI.parse(host)
  reset_http_client!
  @uri
end

.populate(*proxies) ⇒ Object



100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/toxiproxy.rb', line 100

def self.populate(*proxies)
  proxies = proxies.first if proxies.first.is_a?(Array)

  request = Net::HTTP::Post.new("/populate")
  request.body = proxies.to_json
  request["Content-Type"] = "application/json"

  response = http_request(request)
  assert_response(response)

  proxies = JSON.parse(response.body).fetch('proxies', []).map do |attrs|
    self.new({
      upstream: attrs["upstream"],
      listen: attrs["listen"],
      name: attrs["name"],
      enabled: attrs["enabled"]
    })
  end

  ProxyCollection.new(proxies)
end

.resetObject

Re-enables all proxies and disables all toxics.



32
33
34
35
36
37
38
39
# File 'lib/toxiproxy.rb', line 32

def self.reset
  request = Net::HTTP::Post.new("/reset")
  request["Content-Type"] = "application/json"

  response = http_request(request)
  assert_response(response)
  self
end

.reset_http_client!Object



229
230
231
232
# File 'lib/toxiproxy.rb', line 229

def self.reset_http_client!
  @http.finish if @http&.started?
  @http = nil
end

.running?Boolean

Returns:

  • (Boolean)


122
123
124
125
126
127
# File 'lib/toxiproxy.rb', line 122

def self.running?
  TCPSocket.new(uri.host, uri.port).close
  true
rescue Errno::ECONNREFUSED, Errno::ECONNRESET
  false
end

.versionObject



41
42
43
44
45
46
47
48
# File 'lib/toxiproxy.rb', line 41

def self.version
  return false unless running?

  request = Net::HTTP::Get.new("/version")
  response = http_request(request)
  assert_response(response)
  response.body
end

Instance Method Details

#createObject

Create a Toxiproxy, proxying traffic from ‘@listen` (optional argument to the constructor) to `@upstream`. `#down` `#upstream` or `#downstream` can at any time alter the health of this connection.



186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
# File 'lib/toxiproxy.rb', line 186

def create
  request = Net::HTTP::Post.new("/proxies")
  request["Content-Type"] = "application/json"

  hash = {upstream: upstream, name: name, listen: listen, enabled: enabled}
  request.body = hash.to_json

  response = http_request(request)
  assert_response(response)

  new = JSON.parse(response.body)
  @listen = new["listen"]

  self
end

#destroyObject

Destroys a Toxiproxy.



203
204
205
206
207
208
# File 'lib/toxiproxy.rb', line 203

def destroy
  request = Net::HTTP::Delete.new("/proxies/#{name}")
  response = http_request(request)
  assert_response(response)
  self
end

#disableObject

Disables a Toxiproxy. This will drop all active connections and stop the proxy from listening.



158
159
160
161
162
163
164
165
166
167
168
# File 'lib/toxiproxy.rb', line 158

def disable
  request = Net::HTTP::Post.new("/proxies/#{name}")
  request["Content-Type"] = "application/json"

  hash = {enabled: false}
  request.body = hash.to_json

  response = http_request(request)
  assert_response(response)
  self
end

#down(&block) ⇒ Object

Simulates the endpoint is down, by closing the connection and no longer accepting connections. This is useful to simulate critical system failure, such as a data store becoming completely unavailable.



150
151
152
153
154
155
# File 'lib/toxiproxy.rb', line 150

def down(&block)
  disable
  yield
ensure
  enable
end

#downstream(type, attrs = {}) ⇒ Object Also known as: toxic, toxicate

Set a downstream toxic.



139
140
141
142
143
# File 'lib/toxiproxy.rb', line 139

def downstream(type, attrs = {})
  collection = ToxicCollection.new([self])
  collection.downstream(type, attrs)
  collection
end

#enableObject

Enables a Toxiproxy. This will cause the proxy to start listening again.



171
172
173
174
175
176
177
178
179
180
181
# File 'lib/toxiproxy.rb', line 171

def enable
  request = Net::HTTP::Post.new("/proxies/#{name}")
  request["Content-Type"] = "application/json"

  hash = {enabled: true}
  request.body = hash.to_json

  response = http_request(request)
  assert_response(response)
  self
end

#toxicsObject

Returns an array of the current toxics for a direction.



211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
# File 'lib/toxiproxy.rb', line 211

def toxics
  request = Net::HTTP::Get.new("/proxies/#{name}/toxics")
  response = http_request(request)
  assert_response(response)

  JSON.parse(response.body).map { |attrs|
    Toxic.new(
      type: attrs['type'],
      name: attrs['name'],
      proxy: self,
      stream: attrs['stream'],
      toxicity: attrs['toxicity'],
      attributes: attrs['attributes'],
    )
  }
end

#upstream(type = nil, attrs = {}) ⇒ Object

Set an upstream toxic.



130
131
132
133
134
135
136
# File 'lib/toxiproxy.rb', line 130

def upstream(type = nil, attrs = {})
  return @upstream unless type # also alias for the upstream endpoint

  collection = ToxicCollection.new([self])
  collection.upstream(type, attrs)
  collection
end