Skip to content
This repository has been archived by the owner on Jan 25, 2022. It is now read-only.

Commit

Permalink
Use session generated by DEA as sticky session
Browse files Browse the repository at this point in the history
Instead of routers encrypt/decrypt the sticky session.

Change-Id: I8ef4891e336003aadca2cb84ee9390feb8239113
  • Loading branch information
Anfernee Gui committed Oct 31, 2012
1 parent 346867c commit f1a5d3f
Show file tree
Hide file tree
Showing 5 changed files with 12 additions and 64 deletions.
34 changes: 5 additions & 29 deletions lib/router/router.rb
Expand Up @@ -4,7 +4,7 @@ class Router
VERSION = 0.98

class << self
attr_reader :log, :notfound_redirect, :session_key
attr_reader :log, :notfound_redirect
attr_accessor :server, :local_server, :timestamp, :pid_file
attr_accessor :inet, :port

Expand Down Expand Up @@ -32,7 +32,6 @@ def config(config)
log.info "Registered 404 redirect at #{config['404_redirect']}"
end

@session_key = config['session_key'] || '14fbc303b76bacd1e0a3ab641c11d11400341c5d'
@expose_all_apps = config['status']['expose_all_apps'] if config['status']

@enable_nonprod_apps = config['enable_nonprod_apps'] || false
Expand All @@ -49,7 +48,7 @@ def setup_listeners
msg_hash = Yajl::Parser.parse(msg, :symbolize_keys => true)
return unless uris = msg_hash[:uris]
uris.each { |uri| register_droplet(uri, msg_hash[:host], msg_hash[:port],
msg_hash[:tags], msg_hash[:app]) }
msg_hash[:tags], msg_hash[:app], msg_hash[:private_instance_id]) }
}
NATS.subscribe('router.unregister') { |msg|
msg_hash = Yajl::Parser.parse(msg, :symbolize_keys => true)
Expand Down Expand Up @@ -136,39 +135,15 @@ def check_registered_urls
to_drop.each { |droplet| unregister_droplet(droplet[:url], droplet[:host], droplet[:port]) }
end

def generate_session_cookie(droplet)
token = [ droplet[:url], droplet[:host], droplet[:port] ]
c = OpenSSL::Cipher::Cipher.new('blowfish')
c.encrypt
c.key = @session_key
e = c.update(Marshal.dump(token))
e << c.final
session = [e].pack('m0').gsub("\n",'')
droplet[:session] = session
session
end

def decrypt_session_cookie(key)
e = key.unpack('m*')[0]
d = OpenSSL::Cipher::Cipher.new('blowfish')
d.decrypt
d.key = @session_key
p = d.update(e)
p << d.final
Marshal.load(p)
rescue
nil
end

def get_session_cookie(droplet)
droplet[:session] || generate_session_cookie(droplet)
droplet[:session] || ""
end

def lookup_droplet(url)
@droplets[url.downcase]
end

def register_droplet(url, host, port, tags, app_id)
def register_droplet(url, host, port, tags, app_id, session=nil)
return unless host && port
url.downcase!
tags ||= {}
Expand All @@ -185,6 +160,7 @@ def register_droplet(url, host, port, tags, app_id)
tags.delete_if { |key, value| key.nil? || value.nil? }
droplet = {
:app => app_id,
:session => session,
:host => host,
:port => port,
:clients => Hash.new(0),
Expand Down
19 changes: 2 additions & 17 deletions lib/router/router_uls_server.rb
Expand Up @@ -35,8 +35,8 @@ class ParserError < StandardError; end

# Pick a droplet based on original backend addr or pick a droplet randomly
if sticky
_, host, port = Router.decrypt_session_cookie(sticky)
droplet = check_original_droplet(droplets, host, port)
droplet = droplets.find { |d| d[:session] == sticky }
Router.log.debug "request's __VCAP_ID__ is stale" unless droplet
end
droplet ||= droplets[rand*droplets.size]
Router.log.debug "Routing #{droplet[:url]} to #{droplet[:host]}:#{droplet[:port]}"
Expand Down Expand Up @@ -86,21 +86,6 @@ class ParserError < StandardError; end

protected

def check_original_droplet(droplets, host, port)
droplet = nil
if host and port
Router.log.debug "request has __VCAP_ID__ cookie for #{host}:#{port}"
# Check host?
droplets.each do |d|
if(d[:host] == host && d[:port] == port.to_i)
droplet = d; break
end
end
Router.log.debug "request's __VCAP_ID__ is stale" unless droplet
end
droplet
end

def update_uls_stats(stats)
stats.each do |stat|
if stat[ULS_REQUEST_TAGS].length > 0
Expand Down
14 changes: 0 additions & 14 deletions spec/functional/router_spec.rb
Expand Up @@ -103,20 +103,6 @@
original_apps_set.should == received_apps_set
end

it 'should generate the same token as router v1 did' do
Router.config({})
token = Router.generate_session_cookie(ROUTER_V1_DROPLET)
token.should == ROUTER_V1_SESSION
end

it 'should decrypt router v1 session' do
Router.config({})
url, host, port = Router.decrypt_session_cookie(ROUTER_V1_SESSION)
url.should == ROUTER_V1_DROPLET[:url]
host.should == ROUTER_V1_DROPLET[:host]
port.should == ROUTER_V1_DROPLET[:port]
end

it 'should properly exit when NATS fails to reconnect' do
@nats_server.stop
@nats_server.ready?.should be_false
Expand Down
2 changes: 0 additions & 2 deletions spec/integration/router_spec.rb
Expand Up @@ -213,8 +213,6 @@

# Verify cookie to backend that never exists
Router.config({})
droplet = { :url => 'sticky.vcap.me', :host => '10.10.10.10', :port => 10 }
down_dea_cookie = "__VCAP_ID__=#{Router.generate_session_cookie(droplet)}"
sticky_request = simple_sticky_request('sticky.vcap.me', '/sticky', bad_cookie)

results = send_requests_to_apps(RouterServer.host, RouterServer.port,
Expand Down
7 changes: 5 additions & 2 deletions spec/integration/spec_helper.rb
Expand Up @@ -314,16 +314,19 @@ def initialize(nats_uri, dea_id, host='127.0.0.1')
@host = host
end

def reg_hash_for_app(app, tags = {})
def reg_hash_for_app(app, tags={})
session = VCAP.secure_uuid + VCAP.secure_uuid

{ :dea => @dea_id,
:session => session,
:host => @host,
:port => app.port,
:uris => app.uris,
:tags => tags
}
end

def register_app(app, tags = {})
def register_app(app, tags={})
NATS.start(:uri => @nats_uri) do
NATS.publish('router.register', reg_hash_for_app(app, tags).to_json) { NATS.stop }
end
Expand Down

0 comments on commit f1a5d3f

Please sign in to comment.