nerve_pharmeasy 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +22 -0
  3. data/.mailmap +2 -0
  4. data/.nerve.rc +2 -0
  5. data/.travis.yml +8 -0
  6. data/CONTRIBUTING.md +28 -0
  7. data/Gemfile +2 -0
  8. data/Gemfile.lock +75 -0
  9. data/LICENSE.txt +22 -0
  10. data/README.md +116 -0
  11. data/Rakefile +7 -0
  12. data/Vagrantfile +121 -0
  13. data/bin/nerve +16 -0
  14. data/example/nerve.conf.json +54 -0
  15. data/example/nerve_services/etcd_service1.json +19 -0
  16. data/example/nerve_services/zookeeper_service1.json +18 -0
  17. data/lib/nerve/configuration_manager.rb +106 -0
  18. data/lib/nerve/log.rb +24 -0
  19. data/lib/nerve/reporter/base.rb +61 -0
  20. data/lib/nerve/reporter/etcd.rb +73 -0
  21. data/lib/nerve/reporter/zookeeper.rb +101 -0
  22. data/lib/nerve/reporter.rb +18 -0
  23. data/lib/nerve/ring_buffer.rb +30 -0
  24. data/lib/nerve/service_watcher/base.rb +65 -0
  25. data/lib/nerve/service_watcher/http.rb +70 -0
  26. data/lib/nerve/service_watcher/rabbitmq.rb +68 -0
  27. data/lib/nerve/service_watcher/tcp.rb +56 -0
  28. data/lib/nerve/service_watcher.rb +152 -0
  29. data/lib/nerve/utils.rb +17 -0
  30. data/lib/nerve/version.rb +3 -0
  31. data/lib/nerve.rb +249 -0
  32. data/nerve.conf.json +23 -0
  33. data/nerve.gemspec +33 -0
  34. data/spec/.gitkeep +0 -0
  35. data/spec/configuration_manager_spec.rb +31 -0
  36. data/spec/example_services_spec.rb +42 -0
  37. data/spec/factories/check.rb +16 -0
  38. data/spec/factories/service.rb +26 -0
  39. data/spec/lib/nerve/reporter_etcd_spec.rb +18 -0
  40. data/spec/lib/nerve/reporter_spec.rb +86 -0
  41. data/spec/lib/nerve/reporter_zookeeper_spec.rb +32 -0
  42. data/spec/lib/nerve/service_watcher_spec.rb +89 -0
  43. data/spec/lib/nerve_spec.rb +186 -0
  44. data/spec/spec_helper.rb +33 -0
  45. metadata +216 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7fa208f63d742675316279d2dada16d3675a2cb8
4
+ data.tar.gz: d858a5049890b8f90a0e3113f4d2add354777f39
5
+ SHA512:
6
+ metadata.gz: 968b7d526d0db51e38b14f379d3c376a3597c2484f39f3320d872fa9314150709372ecd88c28f8b81ab187a060742f13a383d13e1619588e2b015df0f9e75379
7
+ data.tar.gz: f008dee705d0cff7412e36236c8a3549c98fd6d5e9d6e49b06aea5e8a82d2938577483c217fad62d9d5ea413b0f09662a096d85209b134ae42581ac1fe038f58
data/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ InstalledFiles
7
+ _yardoc
8
+ coverage
9
+ doc/
10
+ lib/bundler/man
11
+ pkg
12
+ rdoc
13
+ spec/reports
14
+ test/tmp
15
+ test/version_tmp
16
+ tmp
17
+ *.sw?
18
+ \#*\#
19
+ .\#*
20
+ vendor
21
+ .vagrant
22
+ .ruby-version
data/.mailmap ADDED
@@ -0,0 +1,2 @@
1
+ <igor.serebryany@airbedandbreakfast.com> <igor47@moomers.org>
2
+ <martin.rhoads@airbnb.com> <ermal14@gmail.com>
data/.nerve.rc ADDED
@@ -0,0 +1,2 @@
1
+ export DATA_BAG_DIR=/Users/martin/Dropbox/airbnb/src/chef/data_bags
2
+ export COOKBOOK_DIR=/Users/martin/Dropbox/airbnb/src/chef/cookbooks
data/.travis.yml ADDED
@@ -0,0 +1,8 @@
1
+ language: ruby
2
+ cache: bundler
3
+ sudo: false
4
+ rvm:
5
+ - 1.9.3
6
+ - 2.0.0
7
+ - 2.1.6
8
+ - 2.2.2
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,28 @@
1
+ # Contributing Guidelines #
2
+
3
+ Thanks for contributing to SmartStack!
4
+
5
+ If you are opening a new PR, please ask for a merge into the `master` branch.
6
+
7
+ ## Writing Reporters ##
8
+ Nerve supports *pluggable* reporters, which means that you can easily add
9
+ a reporter by making your own gem that contains your reporter available for
10
+ require at ``nerve/reporter/#{name.downcase}``. If you do this please do
11
+ submit a PR with a link to your gem/repo and we can reference it from the
12
+ README.
13
+
14
+ In general it is preferred to keep reporters that require specific dependencies
15
+ out of nerve because that way you can select the version of dependencies that
16
+ you need (for example if you have a particular version of the docker api or
17
+ etcd). That being said, if your reporter has no external dependencies
18
+ (e.g. files) or is extremely common (e.g. zookeeper, etcd), we may choose to
19
+ support it in the repo itself.
20
+
21
+ ## Writing Checks ##
22
+
23
+ We welcome additional service checks into the core of nerve.
24
+ However, your checks must follow a few guidelines or they will not be accepted:
25
+
26
+ * be sure to respect timeouts; checks that do not time-out will not be accepted
27
+ * do NOT shell out; this becomes very expensive when done frequently
28
+ * use well-tested, stable, core libraries whenever possible
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,75 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ nerve (0.7.0)
5
+ bunny (= 1.1.0)
6
+ etcd (~> 0.2.3)
7
+ json
8
+ zk (~> 1.9.2)
9
+
10
+ GEM
11
+ remote: https://rubygems.org/
12
+ specs:
13
+ activesupport (4.2.0)
14
+ i18n (~> 0.7)
15
+ json (~> 1.7, >= 1.7.7)
16
+ minitest (~> 5.1)
17
+ thread_safe (~> 0.3, >= 0.3.4)
18
+ tzinfo (~> 1.1)
19
+ amq-protocol (1.9.2)
20
+ bunny (1.1.0)
21
+ amq-protocol (>= 1.9.2)
22
+ coderay (1.1.0)
23
+ diff-lcs (1.2.5)
24
+ etcd (0.2.4)
25
+ mixlib-log
26
+ factory_girl (4.5.0)
27
+ activesupport (>= 3.0.0)
28
+ i18n (0.7.0)
29
+ json (1.8.2)
30
+ little-plugger (1.1.3)
31
+ logging (1.8.2)
32
+ little-plugger (>= 1.1.3)
33
+ multi_json (>= 1.8.4)
34
+ method_source (0.8.2)
35
+ minitest (5.5.1)
36
+ mixlib-log (1.6.0)
37
+ multi_json (1.11.2)
38
+ pry (0.10.1)
39
+ coderay (~> 1.1.0)
40
+ method_source (~> 0.8.1)
41
+ slop (~> 3.4)
42
+ rake (10.1.1)
43
+ rspec (3.1.0)
44
+ rspec-core (~> 3.1.0)
45
+ rspec-expectations (~> 3.1.0)
46
+ rspec-mocks (~> 3.1.0)
47
+ rspec-core (3.1.7)
48
+ rspec-support (~> 3.1.0)
49
+ rspec-expectations (3.1.2)
50
+ diff-lcs (>= 1.2.0, < 2.0)
51
+ rspec-support (~> 3.1.0)
52
+ rspec-mocks (3.1.3)
53
+ rspec-support (~> 3.1.0)
54
+ rspec-support (3.1.2)
55
+ slop (3.6.0)
56
+ thread_safe (0.3.4)
57
+ tzinfo (1.2.2)
58
+ thread_safe (~> 0.1)
59
+ zk (1.9.5)
60
+ logging (~> 1.8.2)
61
+ zookeeper (~> 1.4.0)
62
+ zookeeper (1.4.10)
63
+
64
+ PLATFORMS
65
+ ruby
66
+
67
+ DEPENDENCIES
68
+ factory_girl
69
+ nerve!
70
+ pry
71
+ rake
72
+ rspec (~> 3.1.0)
73
+
74
+ BUNDLED WITH
75
+ 1.10.5
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Airbnb, Inc.
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,116 @@
1
+ [![Build Status](https://travis-ci.org/airbnb/nerve.png?branch=master)](https://travis-ci.org/airbnb/nerve)
2
+
3
+ # Nerve
4
+
5
+ Nerve is a utility for tracking the status of machines and services.
6
+ It runs locally on the boxes which make up a distributed system, and reports state information to a distributed key-value store.
7
+ At Airbnb, we use Zookeeper as our key-value store.
8
+ The combination of Nerve and [Synapse](https://github.com/airbnb/synapse) make service discovery in the cloud easy!
9
+
10
+ ## Motivation ##
11
+
12
+ We already use [Synapse](https://github.com/airbnb/synapse) to discover remote services.
13
+ However, those services needed boilerplate code to register themselves in [Zookeeper](http://zookeeper.apache.org/).
14
+ Nerve simplifies underlying services, enables code reuse, and allows us to create a more composable system.
15
+ It does so by factoring out the boilerplate into it's own application, which independenly handles monitoring and reporting.
16
+
17
+ Beyond those benefits, nerve also acts as a general watchdog on systems.
18
+ The information it reports can be used to take action from a centralized automation center: action like scaling distributed systems up or down or alerting ops or engineering about downtime.
19
+
20
+ ## Installation ##
21
+
22
+ To download and run the nerve binary, first install a version of ruby. Then,
23
+ install nerve with:
24
+
25
+ ```bash
26
+ $ mkdir -p /opt/smartstack/nerve
27
+
28
+ # If you want to install specific versions of dependencies such as an older
29
+ # version of the aws-sdk, the docker-api, etc, gem install that here *before*
30
+ # gem installing nerve. This is also where you would gem install
31
+ # custom reporters.
32
+
33
+ # If you are on Ruby 2.X use --no-document instead of --no-ri --no-rdoc
34
+ $ gem install nerve --install-dir /opt/smartstack/nerve --no-ri --no-rdoc
35
+ ```
36
+
37
+ This will download nerve and its dependencies into /opt/smartstack/nerve. You
38
+ might wish to omit the `--install-dir` flag to use your system's default gem
39
+ path, however this will require you to run `gem install nerve` with root
40
+ permissions. You can also install via bundler, but keep in mind you'll pick up
41
+ Nerve's version of library dependencies and possibly not the ones you need
42
+ for your infra/apps.
43
+
44
+ ## Configuration ##
45
+
46
+ Nerve depends on a single configuration file, in json format.
47
+ It is usually called `nerve.conf.json`.
48
+ An example config file is available in `example/nerve.conf.json`.
49
+ The config file is composed of two main sections:
50
+
51
+ * `instance_id`: the name nerve will submit when registering services; makes debugging easier
52
+ * `heartbeat_path`: a path to a file on disk to touch as nerve makes progress. This allows you to work around https://github.com/zk-ruby/zk/issues/50 by restarting a stuck nerve.
53
+ * `services`: the hash (from service name to config) of the services nerve will be monitoring
54
+ * `service_conf_dir`: path to a directory in which each json file will be interpreted as a service with the basename of the file minus the .json extension
55
+
56
+ ### Services Config ###
57
+
58
+ Each service that nerve will be monitoring is specified in the `services` hash.
59
+ The key is the name of the service, and the value is a configuration hash telling nerve how to monitor the service.
60
+ The configuration contains the following options:
61
+
62
+ * `host`: the default host on which to make service checks; you should make this your *public* ip to ensure your service is publically accessible
63
+ * `port`: the default port for service checks; nerve will report the `host`:`port` combo via your chosen reporter
64
+ * `reporter_type`: the mechanism used to report up/down information; depending on the reporter you choose, additional parameters may be required. Defaults to `zookeeper`
65
+ * `check_interval`: the frequency with which service checks will be initiated; defaults to `500ms`
66
+ * `checks`: a list of checks that nerve will perform; if all of the pass, the service will be registered; otherwise, it will be un-registered
67
+ * `weight` (optional): a positive integer weight value which can be used to affect the haproxy backend weighting in synapse.
68
+ * `haproxy_server_options` (optional): a string containing any special haproxy server options for this service instance. For example if you wanted to set a service instance as a backup.
69
+ * `labels` (optional): an object containing user-defined key-value pairs that describe this service instance. For example, you could label service instances with datacenter information.
70
+
71
+ #### Zookeeper Reporter ####
72
+
73
+ If you set your `reporter_type` to `"zookeeper"` you should also set these parameters:
74
+
75
+ * `zk_hosts`: a list of the zookeeper hosts comprising the [ensemble](https://zookeeper.apache.org/doc/r3.1.2/zookeeperAdmin.html#sc_zkMulitServerSetup) that nerve will submit registration to
76
+ * `zk_path`: the path (or [znode](https://zookeeper.apache.org/doc/r3.1.2/zookeeperProgrammers.html#sc_zkDataModel_znodes)) where the registration will be created; nerve will create the [ephemeral node](https://zookeeper.apache.org/doc/r3.1.2/zookeeperProgrammers.html#Ephemeral+Nodes) that is the registration as a child of this path
77
+
78
+ #### Etcd Reporter ####
79
+
80
+ Note: Etcd support is currently experimental!
81
+
82
+ If you set your `reporter_type` to `"etcd"` you should also set these parameters:
83
+
84
+ * `etcd_host`: etcd host that nerve will submit registration to
85
+ * `etcd_port`: port to connect to etcd.
86
+ * `etcd_path`: the path where the registration will be created; nerve will create a node with a 30s ttl that is the registration as a child of this path, and then update it every few seconds
87
+
88
+ ### Checks ###
89
+
90
+ The core of nerve is a set of service checks.
91
+ Each service can define a number of checks, and all of them must pass for the service to be registered.
92
+ Although the exact parameters passed to each check are different, all take a number of common arguments:
93
+
94
+ * `type`: (required) the kind of check; you can see available check types in the `lib/nerve/service_watcher` dir of this repo
95
+ * `name`: (optional) a descriptive, human-readable name for the check; it will be auto-generated based on the other parameters if not specified
96
+ * `host`: (optional) the host on which the check will be performed; defaults to the `host` of the service to which the check belongs
97
+ * `port`: (optional) the port on which the check will be performed; like `host`, it defaults to the `port` of the service
98
+ * `timeout`: (optional) maximum time the check can take; defaults to `100ms`
99
+ * `rise`: (optional) how many consecutive checks must pass before the check is considered passing; defaults to 1
100
+ * `fall`: (optional) how many consecutive checks must fail before the check is considered failing; defaults to 1
101
+
102
+ #### Custom External Checks ####
103
+
104
+ If you would like to run a custom check but don't feel like trying to get it merged into this project, there is a mechanism for including external checks thanks to @bakins (airbnb/nerve#36).
105
+ Build your custom check as a separate gem and make sure to `bundle install` it on your system.
106
+
107
+ Ideally, you should name your gem `"nerve-watcher-#{type}"`, as that is what nerve will `require` on boot.
108
+ However, if you have a custom name for your gem, you can specify that in the `module` argument to the check.
109
+
110
+ ## Contributing
111
+
112
+ 1. Fork it
113
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
114
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
115
+ 4. Push to the branch (`git push origin my-new-feature`)
116
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :test => :spec
7
+ task :default => :spec
data/Vagrantfile ADDED
@@ -0,0 +1,121 @@
1
+ # -*- mode: ruby -*-
2
+ # vi: set ft=ruby :
3
+
4
+ unless ENV['COOKBOOK_DIR'] and ENV['DATA_BAG_DIR']
5
+ STDERR.puts "you need to set COOKBOOK_DIR and DATA_BAG_DIR as environment variables"
6
+ Kernel.exit 1
7
+ end
8
+
9
+ this_dir = File.dirname(File.expand_path __FILE__)
10
+
11
+ STDERR.puts "mounting #{this_dir} as /root/this_dir"
12
+
13
+ Vagrant::Config.run do |config|
14
+ # All Vagrant configuration is done here. The most common configuration
15
+ # options are documented and commented below. For a complete reference,
16
+ # please see the online documentation at vagrantup.com.
17
+
18
+ # Every Vagrant virtual environment requires a box to build off of.
19
+ config.vm.box = "precise64"
20
+
21
+ # The url from where the 'config.vm.box' box will be fetched if it
22
+ # doesn't already exist on the user's system.
23
+ # config.vm.box_url = "http://domain.com/path/to/above.box"
24
+
25
+ config.vm.box_url = 'http://files.vagrantup.com/precise64.box'
26
+
27
+ # Boot with a GUI so you can see the screen. (Default is headless)
28
+ # config.vm.boot_mode = :gui
29
+
30
+ # Assign this VM to a host-only network IP, allowing you to access it
31
+ # via the IP. Host-only networks can talk to the host machine as well as
32
+ # any other machines on the same network, but cannot be accessed (through this
33
+ # network interface) by any external networks.
34
+ # config.vm.network :hostonly, "192.168.33.10"
35
+
36
+ # Assign this VM to a bridged network, allowing you to connect directly to a
37
+ # network using the host's network device. This makes the VM appear as another
38
+ # physical device on your network.
39
+ # config.vm.network :bridged
40
+
41
+ # Forward a port from the guest to the host, which allows for outside
42
+ # computers to access the VM, whereas host only networking does not.
43
+ # config.vm.forward_port 80, 8080
44
+
45
+ # Share an additional folder to the guest VM. The first argument is
46
+ # an identifier, the second is the path on the guest to mount the
47
+ # folder, and the third is the path on the host to the actual folder.
48
+ # config.vm.share_folder "v-data", "/vagrant_data", "../data"
49
+
50
+ config.vm.share_folder 'this_dir', '/this_dir', this_dir
51
+
52
+ # Enable provisioning with Puppet stand alone. Puppet manifests
53
+ # are contained in a directory path relative to this Vagrantfile.
54
+ # You will need to create the manifests directory and a manifest in
55
+ # the file base.pp in the manifests_path directory.
56
+ #
57
+ # An example Puppet manifest to provision the message of the day:
58
+ #
59
+ # # group { "puppet":
60
+ # # ensure => "present",
61
+ # # }
62
+ # #
63
+ # # File { owner => 0, group => 0, mode => 0644 }
64
+ # #
65
+ # # file { '/etc/motd':
66
+ # # content => "Welcome to your Vagrant-built virtual machine!
67
+ # # Managed by Puppet.\n"
68
+ # # }
69
+ #
70
+ # config.vm.provision :puppet do |puppet|
71
+ # puppet.manifests_path = "manifests"
72
+ # puppet.manifest_file = "base.pp"
73
+ # end
74
+
75
+ # Enable provisioning with chef solo, specifying a cookbooks path, roles
76
+ # path, and data_bags path (all relative to this Vagrantfile), and adding
77
+ # some recipes and/or roles.
78
+ #
79
+ config.vm.provision :chef_solo do |chef|
80
+ # chef.cookbooks_path = "../my-recipes/cookbooks"
81
+ # chef.roles_path = "../my-recipes/roles"
82
+ # chef.data_bags_path = '/tmp/foo'
83
+ # chef.add_recipe "mysql"
84
+ # chef.add_role "web"
85
+
86
+ # You may also specify custom JSON attributes:
87
+ # chef.json = { :mysql_password => "foo" }
88
+
89
+ chef.data_bags_path = ENV['DATA_BAG_DIR']
90
+ chef.cookbooks_path = ENV['COOKBOOK_DIR']
91
+ chef.add_recipe 'vagrant'
92
+ chef.add_recipe 'nerve'
93
+ end
94
+
95
+ # Enable provisioning with chef server, specifying the chef server URL,
96
+ # and the path to the validation key (relative to this Vagrantfile).
97
+ #
98
+ # The Opscode Platform uses HTTPS. Substitute your organization for
99
+ # ORGNAME in the URL and validation key.
100
+ #
101
+ # If you have your own Chef Server, use the appropriate URL, which may be
102
+ # HTTP instead of HTTPS depending on your configuration. Also change the
103
+ # validation key to validation.pem.
104
+ #
105
+ # config.vm.provision :chef_client do |chef|
106
+ # chef.chef_server_url = "https://api.opscode.com/organizations/ORGNAME"
107
+ # chef.validation_key_path = "ORGNAME-validator.pem"
108
+ # end
109
+ #
110
+ # If you're using the Opscode platform, your validator client is
111
+ # ORGNAME-validator, replacing ORGNAME with your organization name.
112
+ #
113
+ # IF you have your own Chef Server, the default validation client name is
114
+ # chef-validator, unless you changed the configuration.
115
+ #
116
+ # chef.validation_client_name = "ORGNAME-validator"
117
+
118
+ # Vagrant::Config.run do |config|
119
+ # config.vm.provision :shell, :path => "vagrant/init.sh"
120
+ # end
121
+ end
data/bin/nerve ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'yaml'
4
+ require 'optparse'
5
+
6
+ require 'nerve'
7
+ require 'nerve/configuration_manager'
8
+
9
+ # Parse command line options and parse configuration
10
+ config_manager = Nerve::ConfigurationManager.new()
11
+ config_manager.parse_options!
12
+
13
+ nerve_application = Nerve::Nerve.new(config_manager)
14
+ nerve_application.run
15
+
16
+ puts "exiting nerve"
@@ -0,0 +1,54 @@
1
+ {
2
+ "instance_id": "mymachine",
3
+ "service_conf_dir": "example/nerve_services",
4
+ "services": {
5
+ "your_http_service": {
6
+ "host": "1.2.3.4",
7
+ "port": 3000,
8
+ "reporter_type": "zookeeper",
9
+ "zk_hosts": ["localhost:2181"],
10
+ "zk_path": "/nerve/services/your_http_service/services",
11
+ "check_interval": 2,
12
+ "checks": [
13
+ {
14
+ "type": "http",
15
+ "uri": "/health",
16
+ "timeout": 0.2,
17
+ "rise": 3,
18
+ "fall": 2
19
+ }
20
+ ]
21
+ },
22
+ "your_tcp_service": {
23
+ "host": "1.2.3.4",
24
+ "port": 6379,
25
+ "reporter_type": "zookeeper",
26
+ "zk_hosts": ["localhost:2181"],
27
+ "zk_path": "/nerve/services/your_tcp_service/services",
28
+ "check_interval": 2,
29
+ "checks": [
30
+ {
31
+ "type": "tcp",
32
+ "timeout": 0.2,
33
+ "rise": 3,
34
+ "fall": 2
35
+ }
36
+ ]
37
+ },
38
+ "rabbitmq_service": {
39
+ "host": "1.2.3.4",
40
+ "port": 5672,
41
+ "reporter_type": "zookeeper",
42
+ "zk_hosts": ["localhost:2181"],
43
+ "zk_path": "/nerve/services/your_rabbitmq_service/services",
44
+ "check_interval": 2,
45
+ "checks": [
46
+ {
47
+ "type": "rabbitmq",
48
+ "username": "guest",
49
+ "password": "guest"
50
+ }
51
+ ]
52
+ }
53
+ }
54
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "host": "1.2.3.4",
3
+ "port": 3000,
4
+ "reporter_type": "etcd",
5
+ "etcd_host": "localhost",
6
+ "etcd_port": 4001,
7
+ "etcd_path": "/nerve/services/your_http_service/services",
8
+ "check_interval": 2,
9
+ "weight": 2,
10
+ "checks": [
11
+ {
12
+ "type": "http",
13
+ "uri": "/health",
14
+ "timeout": 0.2,
15
+ "rise": 3,
16
+ "fall": 2
17
+ }
18
+ ]
19
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "host": "1.2.3.4",
3
+ "port": 3000,
4
+ "reporter_type": "zookeeper",
5
+ "zk_hosts": ["localhost:2181"],
6
+ "zk_path": "/nerve/services/your_http_service/services",
7
+ "check_interval": 2,
8
+ "weight": 2,
9
+ "checks": [
10
+ {
11
+ "type": "http",
12
+ "uri": "/health",
13
+ "timeout": 0.2,
14
+ "rise": 3,
15
+ "fall": 2
16
+ }
17
+ ]
18
+ }
@@ -0,0 +1,106 @@
1
+ require 'yaml'
2
+ require 'optparse'
3
+ require 'nerve/log'
4
+ require 'logger'
5
+
6
+
7
+ module Nerve
8
+ class ConfigurationManager
9
+ include Logging
10
+
11
+ attr_reader :options
12
+ attr_reader :config
13
+
14
+ def parse_options_from_argv!
15
+ options = {}
16
+ # set command line options
17
+ optparse = OptionParser.new do |opts|
18
+ opts.banner =<<EOB
19
+ Welcome to nerve
20
+
21
+ Usage: nerve --config /path/to/nerve/config
22
+ EOB
23
+
24
+ options[:config] = ENV['NERVE_CONFIG']
25
+ opts.on('-c config','--config config', String, 'path to nerve config') do |key,value|
26
+ options[:config] = key
27
+ end
28
+
29
+ options[:instance_id] = ENV['NERVE_INSTANCE_ID']
30
+ opts.on('-i instance_id','--instance_id instance_id', String,
31
+ 'reported as `name` to ZK; overrides instance id from config file') do |key,value|
32
+ options[:instance_id] = key
33
+ end
34
+
35
+ options[:check_config] = ENV['NERVE_CHECK_CONFIG']
36
+ opts.on('-k', '--check-config',
37
+ 'Validate the nerve config ONLY and exit 0 if valid (non zero otherwise)') do |_|
38
+ options[:check_config] = true
39
+ end
40
+
41
+ opts.on('-h', '--help', 'Display this screen') do
42
+ puts opts
43
+ exit
44
+ end
45
+ end
46
+ optparse.parse!
47
+ options.each do|key, value|
48
+ log.info key
49
+ log.info value
50
+ end
51
+ options
52
+ end
53
+
54
+ def parse_options!
55
+ @options = parse_options_from_argv!
56
+ end
57
+
58
+ def generate_nerve_config(options)
59
+
60
+ config = parse_config_file(options[:config])
61
+ config['services'] ||= {}
62
+
63
+ if config.has_key?('service_conf_dir')
64
+ cdir = File.expand_path(config['service_conf_dir'])
65
+ if ! Dir.exists?(cdir) then
66
+ raise "service conf dir does not exist:#{cdir}"
67
+ end
68
+ cfiles = Dir.glob(File.join(cdir, '*.{yaml,json}'))
69
+ cfiles.each { |x| config['services'][File.basename(x[/(.*)\.(yaml|json)$/, 1])] = parse_config_file(x) }
70
+ end
71
+
72
+ if options[:instance_id] && !options[:instance_id].empty?
73
+ config['instance_id'] = options[:instance_id]
74
+ end
75
+
76
+ config
77
+ end
78
+
79
+ def parse_config_file(filename)
80
+ # parse nerve config file
81
+ begin
82
+ c = YAML::parse(File.read(filename))
83
+ rescue Errno::ENOENT => e
84
+ raise ArgumentError, "config file does not exist:\n#{e.inspect}"
85
+ rescue Errno::EACCES => e
86
+ raise ArgumentError, "could not open config file:\n#{e.inspect}"
87
+ rescue YAML::SyntaxError => e
88
+ raise "config file #{filename} is not proper yaml:\n#{e.inspect}"
89
+ end
90
+ return c.to_ruby
91
+ end
92
+
93
+ def reload!
94
+ raise "You must parse command line options before reloading config" if @options.nil?
95
+ @config = generate_nerve_config(@options)
96
+ end
97
+
98
+ def setConfig(configuration)
99
+ @config = configuration
100
+ @options = {}
101
+ @options[:check_config]=false
102
+ end
103
+ end
104
+ end
105
+
106
+
data/lib/nerve/log.rb ADDED
@@ -0,0 +1,24 @@
1
+ module Nerve
2
+ module Logging
3
+
4
+ def log
5
+ @logger ||= Logging.logger_for(self.class.name)
6
+ end
7
+
8
+ # Use a hash class-ivar to cache a unique Logger per class:
9
+ @loggers = {}
10
+
11
+ class << self
12
+ def logger_for(classname)
13
+ @loggers[classname] ||= configure_logger_for(classname)
14
+ end
15
+
16
+ def configure_logger_for(classname)
17
+ logger = Logger.new(STDERR)
18
+ logger.level = Logger::INFO unless ENV['DEBUG']
19
+ logger.progname = classname
20
+ return logger
21
+ end
22
+ end
23
+ end
24
+ end