cf-registrar 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,34 @@
1
+ # Cf::Registrar
2
+
3
+ [![Build Status](https://travis-ci.org/cloudfoundry/cf-registrar.png?branch=master)](https://travis-ci.org/cloudfoundry/cf-registrar)
4
+
5
+ [![Code Climate](https://codeclimate.com/repos/52e301fd6956803ff1003c85/badges/c66e290472608e6af5f9/gpa.png)](https://codeclimate.com/repos/52e301fd6956803ff1003c85/feed)
6
+
7
+ Helper to register with common components like Varz and CF Router
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ gem 'cf-registrar', git: 'https://github.com/cloudfoundry/cf-registrar'
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install cf-registrar
22
+
23
+ ## Usage
24
+
25
+ # Modes can be --register-with-router and --register-varz-credentials
26
+ $ cf-registrar --<mode1> --<mode2> ...
27
+
28
+ ## Contributing
29
+
30
+ 1. Fork it ( http://github.com/cloudfoundry/cf-registrar/fork )
31
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
32
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
33
+ 4. Push to the branch (`git push origin my-new-feature`)
34
+ 5. Create new Pull Request
@@ -0,0 +1,9 @@
1
+ require 'bundler/gem_tasks'
2
+
3
+ require 'rspec/core/rake_task'
4
+
5
+ task default: :spec
6
+
7
+ RSpec::Core::RakeTask.new do |t|
8
+ t.rspec_opts = ['--format', 'documentation', '--colour']
9
+ end
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env ruby
2
+ require "rubygems"
3
+ require "yaml"
4
+
5
+ $:.unshift(File.expand_path("../../lib", __FILE__))
6
+
7
+ require "cf/registrar"
8
+ require "steno"
9
+ require "securerandom"
10
+
11
+ if ARGV.empty?
12
+ puts "Usage: cf-registrar --<mode1> --<mode2> ...\n\nModes can be --register-with-router and --register-varz-credentials"
13
+ exit
14
+ end
15
+
16
+ config_file = ENV["CONFIG_FILE"] || File.expand_path("../config/registrar.example.yml", File.dirname(__FILE__))
17
+ config = YAML.load_file(config_file)
18
+
19
+ Steno.init(Steno::Config.from_hash(config["logging"]))
20
+ logger = Steno.logger("cf-registrar")
21
+
22
+ unless config["varz"]["file"].nil?
23
+ varz_config = YAML.load_file(config["varz"]["file"])
24
+ unless varz_config.nil?
25
+ logger.info "Reading varz config from #{config["varz"]["file"]}"
26
+ config["varz"] = varz_config["varz"]
27
+ end
28
+ end
29
+
30
+ logger.debug("Config #{config.inspect}")
31
+
32
+ EM.run do
33
+ cf_registrar = Cf::Registrar.new({
34
+ :message_bus_servers => config["message_bus_servers"],
35
+ :host => config["host"],
36
+ :port => config["port"],
37
+ :uri => config["uri"],
38
+ :tags => config["tags"],
39
+ :index => config["index"],
40
+ :varz => config["varz"],
41
+ :private_instance_id => SecureRandom.uuid
42
+ })
43
+ if ARGV.include?("--register-with-router") || ARGV.include?("--register_with_router")
44
+ cf_registrar.register_with_router
45
+ end
46
+
47
+ if ARGV.include?("--register-varz-credentials") || ARGV.include?("--register_varz_credentials")
48
+ cf_registrar.register_varz_credentials
49
+ end
50
+
51
+ %w[TERM INT QUIT].each do |signal|
52
+ trap signal do
53
+ logger.info("Shutting down")
54
+ if ARGV.include? "--register-with-router"
55
+ cf_registrar.shutdown { exit }
56
+ else
57
+ exit
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,27 @@
1
+ require File.join(File.dirname(__FILE__), 'lib/cf-registrar/version')
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = 'cf-registrar'
5
+ spec.version = CfRegistrar::VERSION.dup
6
+ spec.authors = ['CloudFoundry Core Team']
7
+ spec.email = ['cfpi-dev@googlegroups.com']
8
+ spec.summary = %q{Cloud Foundry registrar}
9
+ spec.description = %q{Helper for registering a component with things like Varz and the CF Router.}
10
+ spec.homepage = ''
11
+ spec.license = 'Apache'
12
+
13
+ spec.files = `git ls-files -z`.split("\x0")
14
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
15
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
16
+ spec.require_paths = ['lib']
17
+
18
+ spec.add_dependency 'eventmachine', '~> 1.0.0'
19
+ spec.add_dependency 'steno'
20
+ spec.add_dependency 'vcap-concurrency'
21
+ spec.add_dependency 'cf-message-bus', '~> 0.3.0'
22
+
23
+ spec.add_development_dependency 'bundler'
24
+ spec.add_development_dependency 'rake'
25
+ spec.add_development_dependency 'rspec'
26
+ spec.add_development_dependency 'rspec-its'
27
+ end
@@ -0,0 +1,18 @@
1
+ ---
2
+ logging:
3
+ level: all
4
+ message_bus_servers:
5
+ - nats://localhost:4222
6
+ uri: test.vcap.me
7
+ # Alternatively, multiple urls are support like so
8
+ # uri:
9
+ # - test.vcap.me
10
+ # - abc.vcap.me
11
+ host: localhost
12
+ port: 80
13
+ varz:
14
+ type: new_component
15
+ username: varz
16
+ password: varzclientpassword
17
+ # Absolute path to file containing the varz credentials
18
+ # file: /tmp/uaa.yml
@@ -0,0 +1 @@
1
+ require "cf/registrar"
@@ -0,0 +1,3 @@
1
+ module CfRegistrar
2
+ VERSION = "1.0.3".freeze
3
+ end
@@ -0,0 +1,142 @@
1
+ require "eventmachine"
2
+ require "steno"
3
+ require "securerandom"
4
+ require "cf_message_bus/message_bus"
5
+
6
+ module Cf
7
+ class Registrar
8
+ DISCOVER_TOPIC = "vcap.component.discover"
9
+ ANNOUNCE_TOPIC = "vcap.component.announce"
10
+ ROUTER_START_TOPIC = "router.start"
11
+ ROUTER_GREET_TOPIC = "router.greet"
12
+ ROUTER_REGISTER_TOPIC = "router.register"
13
+ ROUTER_UNREGISTER_TOPIC = "router.unregister"
14
+
15
+ attr_reader :logger, :message_bus_servers, :type, :host, :port,
16
+ :username, :password, :uri, :tags, :uuid, :index, :private_instance_id
17
+
18
+ def initialize(config)
19
+ @logger = Steno.logger("cf.registrar")
20
+
21
+ config = symbolize_keys(config)
22
+
23
+ @message_bus_servers = config[:message_bus_servers]
24
+ @host = config[:host]
25
+ @port = config[:port]
26
+ @uri = config[:uri]
27
+ @tags = config[:tags]
28
+ @index = config[:index] || 0
29
+ @private_instance_id = config[:private_instance_id]
30
+
31
+ if config[:varz]
32
+ @type = config[:varz][:type]
33
+ @username = config[:varz][:username]
34
+ @password = config[:varz][:password]
35
+ @uuid = config[:varz][:uuid] || SecureRandom.uuid
36
+ end
37
+ end
38
+
39
+ def register_varz_credentials
40
+ discover_msg = {
41
+ :type => type,
42
+ :host => "#{host}:#{port}",
43
+ :index => index,
44
+ :uuid => "#{index}-#{uuid}",
45
+ :credentials => [username, password]
46
+ }
47
+
48
+ if username.nil? || password.nil?
49
+ logger.error("Could not register nil varz credentials")
50
+ else
51
+ logger.info("Connected to NATS - varz registration")
52
+
53
+ message_bus.subscribe(DISCOVER_TOPIC) do |_, reply|
54
+ logger.debug("Received #{DISCOVER_TOPIC} publishing #{reply.inspect} #{discover_msg.inspect}")
55
+ message_bus.publish(reply, discover_msg)
56
+ end
57
+
58
+ logger.info("Announcing start up #{ANNOUNCE_TOPIC}")
59
+ message_bus.publish(ANNOUNCE_TOPIC, discover_msg)
60
+ end
61
+ end
62
+
63
+ def register_with_router
64
+ logger.info("Connected to NATS - router registration")
65
+
66
+ @router_start_sid = message_bus.subscribe(ROUTER_START_TOPIC) do |message|
67
+ handle_router_greeting(message)
68
+ end
69
+
70
+ message_bus.request(ROUTER_GREET_TOPIC) do |message|
71
+ handle_router_greeting(message)
72
+ end
73
+
74
+ send_registration_message
75
+ end
76
+
77
+ def shutdown(&block)
78
+ EM.cancel_timer(@registration_timer) if @registration_timer
79
+ unsubscribe_from_router_start
80
+ send_unregistration_message(&block)
81
+ end
82
+
83
+ private
84
+
85
+ def handle_router_greeting(message)
86
+ send_registration_message
87
+
88
+ if (interval = message["minimumRegisterIntervalInSeconds"])
89
+ setup_interval(interval)
90
+ end
91
+ end
92
+
93
+ def message_bus
94
+ @message_bus ||= CfMessageBus::MessageBus.new(
95
+ servers: message_bus_servers,
96
+ logger: logger)
97
+ end
98
+
99
+ def send_registration_message
100
+ logger.debug("Sending registration: #{registry_message}")
101
+ message_bus.publish(ROUTER_REGISTER_TOPIC, registry_message)
102
+ end
103
+
104
+ def send_unregistration_message(&block)
105
+ logger.info("Sending unregistration: #{registry_message}")
106
+ message_bus.publish(ROUTER_UNREGISTER_TOPIC, registry_message, &block)
107
+ end
108
+
109
+ def unsubscribe_from_router_start
110
+ logger.debug('Unsubscribing from router.start')
111
+ message_bus.unsubscribe(@router_start_sid)
112
+ end
113
+
114
+ def registry_message
115
+ {
116
+ :host => host,
117
+ :port => port,
118
+ :uris => Array(uri),
119
+ :tags => tags,
120
+ :index => index,
121
+ :private_instance_id => private_instance_id
122
+ }
123
+ end
124
+
125
+ def setup_interval(interval)
126
+ EM.cancel_timer(@registration_timer) if @registration_timer
127
+
128
+ @registration_timer = EM.add_periodic_timer(interval) do
129
+ send_registration_message
130
+ end
131
+ end
132
+
133
+ def symbolize_keys(hash)
134
+ return hash unless hash.is_a? Hash
135
+ Hash[
136
+ hash.each_pair.map do |k, v|
137
+ [k.to_sym, symbolize_keys(v)]
138
+ end
139
+ ]
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,182 @@
1
+ require "spec_helper"
2
+ require 'rspec/its'
3
+ require "cf/registrar"
4
+ require "cf_message_bus/mock_message_bus"
5
+
6
+ module Cf
7
+ describe Registrar do
8
+ let(:message_bus) { CfMessageBus::MockMessageBus.new }
9
+ let(:bus_uri) { "a message bus uri" }
10
+ let(:logger) { double(:logger, info: nil, error: nil, debug: nil) }
11
+ let(:config) do
12
+ { message_bus_servers: [bus_uri],
13
+ host: "registrar.host",
14
+ port: 98765,
15
+ uri: "fancyuri",
16
+ tags: "taggy goodness",
17
+ private_instance_id: "monkey-id",
18
+ index: "indextastic",
19
+ varz: {}
20
+ }
21
+ end
22
+
23
+ let(:registry_message) do
24
+ {
25
+ host: config[:host],
26
+ port: config[:port],
27
+ uris: Array(config[:uri]),
28
+ tags: config[:tags],
29
+ index: "indextastic",
30
+ private_instance_id: "monkey-id"
31
+ }
32
+ end
33
+
34
+ before do
35
+ EM.stub(:cancel_timer)
36
+ CfMessageBus::MessageBus.stub(:new) { message_bus }
37
+ end
38
+
39
+ subject { described_class.new(config) }
40
+
41
+ describe ".new" do
42
+ let(:config) { { message_bus_servers: ["m"], host: "h", port: "p", uri: "u", tags: "t", index: 1, private_instance_id: "monkey" } }
43
+
44
+ its(:logger) { should be_a Steno::Logger }
45
+ its(:message_bus_servers) { should eq(["m"]) }
46
+ its(:host) { should eq "h" }
47
+ its(:port) { should eq "p" }
48
+ its(:uri) { should eq "u" }
49
+ its(:tags) { should eq "t" }
50
+ its(:index) { should eq 1 }
51
+ its(:private_instance_id) { should eq "monkey" }
52
+
53
+ context "when the index is not provided" do
54
+ let(:config) { { message_bus_servers: ["m"], host: "h", port: "p", uri: "u", tags: "t" } }
55
+
56
+ its(:index) { should eq 0 }
57
+ end
58
+
59
+ context "when no varz has been provided" do
60
+ let(:config) { {} }
61
+
62
+ its(:username) { should be_nil }
63
+ its(:password) { should be_nil }
64
+ its(:type) { should be_nil }
65
+ its(:uuid) { should be_nil }
66
+ end
67
+
68
+ context "when there is a varz provided" do
69
+ let(:config) { { varz: { username: "user", password: "pass", type: "foo", uuid: "123" } } }
70
+
71
+ its(:username) { should eq "user" }
72
+ its(:password) { should eq "pass" }
73
+ its(:type) { should eq "foo" }
74
+ its(:uuid) { should eq "123" }
75
+
76
+ context "and a uuid is not provided" do
77
+ let(:config) { { varz: { username: "user", password: "pass", type: "foo" } } }
78
+
79
+ its(:uuid) { should_not be_nil }
80
+ end
81
+ end
82
+
83
+ context "when there are values with String keys" do
84
+ let(:config) { { "host" => "h", :varz => { "username" => "user" } } }
85
+
86
+ its(:host) { should eq "h" }
87
+ its(:username) { should eq "user" }
88
+ end
89
+ end
90
+
91
+ describe "#register_with_router" do
92
+ it "creates the message bus correctly with logger" do
93
+ CfMessageBus::MessageBus.should_receive(:new).with(servers: [bus_uri], logger: subject.logger)
94
+ subject.register_with_router
95
+ end
96
+
97
+ it "registers routes immediately" do
98
+ subject.register_with_router
99
+ expect(message_bus).to have_published_with_message("router.register", registry_message)
100
+ end
101
+
102
+ it "registers upon a router.start message" do
103
+ EM.should_receive(:add_periodic_timer).with(33)
104
+
105
+ subject.register_with_router
106
+
107
+ message_bus.clear_published_messages
108
+
109
+ message_bus.publish("router.start", minimumRegisterIntervalInSeconds: 33)
110
+
111
+ expect(message_bus).to have_published_with_message("router.register", registry_message)
112
+ end
113
+
114
+ it "greets the router" do
115
+ EM.should_receive(:add_periodic_timer).with(33)
116
+
117
+ subject.register_with_router
118
+
119
+ message_bus.clear_published_messages
120
+
121
+ message_bus.respond_to_request("router.greet", minimumRegisterIntervalInSeconds: 33)
122
+ end
123
+
124
+ it "periodically registers with the router" do
125
+ EM.should_receive(:add_periodic_timer).with(33).and_return(:periodic_timer)
126
+ subject.register_with_router
127
+ message_bus.publish("router.start", minimumRegisterIntervalInSeconds: 33)
128
+ end
129
+
130
+ it "clears an existing timer when registering a new one" do
131
+ subject.register_with_router
132
+
133
+ EM.should_receive(:add_periodic_timer).with(33).and_return(:periodic_timer)
134
+ message_bus.publish("router.start", minimumRegisterIntervalInSeconds: 33)
135
+
136
+ EM.should_receive(:cancel_timer).with(:periodic_timer)
137
+ EM.should_receive(:add_periodic_timer).with(24)
138
+ message_bus.publish("router.start", minimumRegisterIntervalInSeconds: 24)
139
+ end
140
+
141
+ context "when there is no timer interval returned" do
142
+ it "does not set up a timer" do
143
+ subject.register_with_router
144
+
145
+ EM.should_not_receive(:add_periodic_timer)
146
+ message_bus.publish("router.start", {})
147
+ end
148
+ end
149
+ end
150
+
151
+ describe "#shutdown" do
152
+ before do
153
+ subject.register_with_router
154
+ EM.should_receive(:add_periodic_timer).with(33).and_return(:periodic_timer)
155
+ message_bus.publish("router.start", minimumRegisterIntervalInSeconds: 33)
156
+ end
157
+
158
+ it "publishes router.unregister" do
159
+ subject.shutdown
160
+ expect(message_bus).to have_published_with_message("router.unregister", registry_message)
161
+ end
162
+
163
+ it "stops sending registration messages" do
164
+ EM.should_receive(:cancel_timer).with(:periodic_timer)
165
+ subject.shutdown
166
+ end
167
+
168
+ it 'unsubscribes from the router start topic' do
169
+ subject.shutdown
170
+
171
+ message_bus.clear_published_messages
172
+ message_bus.publish('router.start', minimumRegisterIntervalInSeconds: 33)
173
+
174
+ expect(message_bus.has_published?('router.register')).to be_falsey
175
+ end
176
+
177
+ it "calls the given block after sending" do
178
+ expect { |b| subject.shutdown(&b) }.to yield_control
179
+ end
180
+ end
181
+ end
182
+ end