nerve_pharmeasy 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +22 -0
- data/.mailmap +2 -0
- data/.nerve.rc +2 -0
- data/.travis.yml +8 -0
- data/CONTRIBUTING.md +28 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +75 -0
- data/LICENSE.txt +22 -0
- data/README.md +116 -0
- data/Rakefile +7 -0
- data/Vagrantfile +121 -0
- data/bin/nerve +16 -0
- data/example/nerve.conf.json +54 -0
- data/example/nerve_services/etcd_service1.json +19 -0
- data/example/nerve_services/zookeeper_service1.json +18 -0
- data/lib/nerve/configuration_manager.rb +106 -0
- data/lib/nerve/log.rb +24 -0
- data/lib/nerve/reporter/base.rb +61 -0
- data/lib/nerve/reporter/etcd.rb +73 -0
- data/lib/nerve/reporter/zookeeper.rb +101 -0
- data/lib/nerve/reporter.rb +18 -0
- data/lib/nerve/ring_buffer.rb +30 -0
- data/lib/nerve/service_watcher/base.rb +65 -0
- data/lib/nerve/service_watcher/http.rb +70 -0
- data/lib/nerve/service_watcher/rabbitmq.rb +68 -0
- data/lib/nerve/service_watcher/tcp.rb +56 -0
- data/lib/nerve/service_watcher.rb +152 -0
- data/lib/nerve/utils.rb +17 -0
- data/lib/nerve/version.rb +3 -0
- data/lib/nerve.rb +249 -0
- data/nerve.conf.json +23 -0
- data/nerve.gemspec +33 -0
- data/spec/.gitkeep +0 -0
- data/spec/configuration_manager_spec.rb +31 -0
- data/spec/example_services_spec.rb +42 -0
- data/spec/factories/check.rb +16 -0
- data/spec/factories/service.rb +26 -0
- data/spec/lib/nerve/reporter_etcd_spec.rb +18 -0
- data/spec/lib/nerve/reporter_spec.rb +86 -0
- data/spec/lib/nerve/reporter_zookeeper_spec.rb +32 -0
- data/spec/lib/nerve/service_watcher_spec.rb +89 -0
- data/spec/lib/nerve_spec.rb +186 -0
- data/spec/spec_helper.rb +33 -0
- 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
data/.nerve.rc
ADDED
data/.travis.yml
ADDED
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
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
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
|