hibachi 0.0.1.pre
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/.rspec +1 -0
- data/.travis.yml +11 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +18 -0
- data/README.md +197 -0
- data/Rakefile +10 -0
- data/hibachi.gemspec +31 -0
- data/lib/generators/hibachi/install_generator.rb +14 -0
- data/lib/generators/hibachi/model_generator.rb +41 -0
- data/lib/generators/templates/hibachi.rb +11 -0
- data/lib/generators/templates/model.rb.erb +4 -0
- data/lib/hibachi/chef_runner.rb +54 -0
- data/lib/hibachi/configuration.rb +18 -0
- data/lib/hibachi/install_active_job_error.rb +13 -0
- data/lib/hibachi/job.rb +7 -0
- data/lib/hibachi/model.rb +42 -0
- data/lib/hibachi/node.rb +112 -0
- data/lib/hibachi/persistence.rb +76 -0
- data/lib/hibachi/provisioning.rb +28 -0
- data/lib/hibachi/querying.rb +48 -0
- data/lib/hibachi/railtie.rb +24 -0
- data/lib/hibachi/recipe.rb +48 -0
- data/lib/hibachi/version.rb +3 -0
- data/lib/hibachi.rb +9 -0
- data/spec/dummy/README.rdoc +28 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/images/.keep +0 -0
- data/spec/dummy/app/assets/javascripts/application.js +13 -0
- data/spec/dummy/app/assets/stylesheets/application.css +15 -0
- data/spec/dummy/app/controllers/application_controller.rb +5 -0
- data/spec/dummy/app/controllers/concerns/.keep +0 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/mailers/.keep +0 -0
- data/spec/dummy/app/models/.keep +0 -0
- data/spec/dummy/app/models/concerns/.keep +0 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/config/application.rb +24 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/database.yml +13 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +37 -0
- data/spec/dummy/config/environments/production.rb +83 -0
- data/spec/dummy/config/environments/test.rb +39 -0
- data/spec/dummy/config/hibachi.rb +6 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +4 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/routes.rb +56 -0
- data/spec/dummy/config/secrets.yml +22 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/lib/assets/.keep +0 -0
- data/spec/dummy/log/.keep +0 -0
- data/spec/dummy/public/404.html +67 -0
- data/spec/dummy/public/422.html +67 -0
- data/spec/dummy/public/500.html +66 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/fixtures/chef.json +7 -0
- data/spec/hibachi/chef_runner_spec.rb +25 -0
- data/spec/hibachi/configuration_spec.rb +29 -0
- data/spec/hibachi/model_spec.rb +24 -0
- data/spec/hibachi/node_spec.rb +52 -0
- data/spec/hibachi/recipe_spec.rb +32 -0
- data/spec/hibachi/store_spec.rb +37 -0
- data/spec/hibachi_spec.rb +13 -0
- data/spec/spec_helper.rb +19 -0
- data/spec/support/mock_setting.rb +18 -0
- data/spec/support/mock_singleton.rb +5 -0
- metadata +299 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 93d51833915516bde538031d378a015bcac41b0d
|
4
|
+
data.tar.gz: ca5f2c393ab648c57a620a2f74b2f30fbecb64d7
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6cfc2e1dec973836c824094c604d5c338274eb9883f59ef5fb2e2feedc67056b7e743e0a24770f2f11ccd8629d9b7c9ac5fc66966a8d81e677f6d718d8095d1b
|
7
|
+
data.tar.gz: 19c4b64c853cbe399769e6a8759e7c8c4aca6263da7d53258918711cee39784e4c7c1d274d33f86c015926ee077795c65ac9cb866138631cab298015f84bdd08
|
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color --format=documentation
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
Copyright (c) 2014 Tom Scott
|
2
|
+
All rights reserved.
|
3
|
+
|
4
|
+
Developed by:
|
5
|
+
|
6
|
+
Tom Scott
|
7
|
+
TelVue Corporation
|
8
|
+
|
9
|
+
http://www.telvue.com/
|
10
|
+
|
11
|
+
|
12
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal with the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
13
|
+
|
14
|
+
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimers.
|
15
|
+
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimers in the documentation and/or other materials provided with the distribution.
|
16
|
+
Neither the names of Tom Scott, TelVue Corporation, nor the names of its contributors may be used to endorse or promote products derived from this Software without specific prior written permission.
|
17
|
+
|
18
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,197 @@
|
|
1
|
+
# Hibachi
|
2
|
+
|
3
|
+
Hibachi is a bridge between your Rails application and your Chef
|
4
|
+
configuration. It provides a framework for building Rails models
|
5
|
+
that persist to a central JSON file rather than a database, as well as
|
6
|
+
automatically running Chef in an `ActiveJob` in the background.
|
7
|
+
|
8
|
+
## Installation
|
9
|
+
|
10
|
+
Add the gem to your Gemfile:
|
11
|
+
|
12
|
+
```ruby
|
13
|
+
gem 'hibachi'
|
14
|
+
```
|
15
|
+
|
16
|
+
Run the following command to install:
|
17
|
+
|
18
|
+
```bash
|
19
|
+
$ bundle
|
20
|
+
```
|
21
|
+
|
22
|
+
Now, you can run the generator to set up Hibachi's configuration
|
23
|
+
(optional):
|
24
|
+
|
25
|
+
```bash
|
26
|
+
$ rails generate hibachi:install
|
27
|
+
```
|
28
|
+
|
29
|
+
This will generate the following Rails initializer:
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
require 'hibachi'
|
33
|
+
|
34
|
+
Hibachi.configure do |config|
|
35
|
+
config.chef_json_path = "#{Rails.root}/config/chef.json"
|
36
|
+
config.chef_dir = "#{Rails.root}/config/chef"
|
37
|
+
config.run_in_background = false # NOTE: will be `true` by default when ActiveJob hits 1.0
|
38
|
+
end
|
39
|
+
```
|
40
|
+
|
41
|
+
## Configuration
|
42
|
+
|
43
|
+
Configuration is stored in the `Rails.application.config.hibachi`
|
44
|
+
object, which is set up by our Railtie and required upon requiring the
|
45
|
+
gem. The default settings are specified above, but you can override them
|
46
|
+
either in the generated initializer or in the Rails environment config,
|
47
|
+
just use the `config.hibachi` namespace.
|
48
|
+
|
49
|
+
- **chef_json_path** defines an absolute path to the JSON file that
|
50
|
+
dictates user-specified configuration.
|
51
|
+
- **chef_dir** defines an absolute path to the Chef repo that has been
|
52
|
+
installed on this machine.
|
53
|
+
- **run_in_background** is a flag that dictates whether to queue Chef
|
54
|
+
runs in a background job or run them directly. The default is false,
|
55
|
+
but *will* be true whenever ActiveJob is merged in, as this method has
|
56
|
+
the best performance.
|
57
|
+
|
58
|
+
## Usage
|
59
|
+
|
60
|
+
When you want to manipulate settings, generate a new Hibachi model:
|
61
|
+
|
62
|
+
```bash
|
63
|
+
$ rails generate hibachi:model NetworkInterface name dhcp address netmask gateway
|
64
|
+
```
|
65
|
+
|
66
|
+
You'll get a file that looks like this:
|
67
|
+
|
68
|
+
```ruby
|
69
|
+
class NetworkInterface < Hibachi::Model
|
70
|
+
recipe :network_interfaces
|
71
|
+
|
72
|
+
attr_accessor :name, :dhcp, :address, :netmask, :gateway
|
73
|
+
|
74
|
+
end
|
75
|
+
```
|
76
|
+
|
77
|
+
`Hibachi::Model` is really just an `ActiveModel::Model` with some added
|
78
|
+
sugar. So you can use all the validation and callbacks you'd expect from
|
79
|
+
an ActiveModel:
|
80
|
+
|
81
|
+
```ruby
|
82
|
+
class NetworkInterface < Hibachi::Model
|
83
|
+
recipe :network_interfaces
|
84
|
+
|
85
|
+
attr_accessor :name, :dhcp, :address, :netmask, :gateway
|
86
|
+
|
87
|
+
validates :name, presence: true
|
88
|
+
validates :dhcp, presence: true
|
89
|
+
|
90
|
+
validates :address, presence: true, :if => :dhcp?
|
91
|
+
validates :netmask, presence: true, :if => :dhcp?
|
92
|
+
validates :gateway, presence: true, :if => :dhcp?
|
93
|
+
|
94
|
+
def dhcp?
|
95
|
+
!!dhcp
|
96
|
+
end
|
97
|
+
end
|
98
|
+
```
|
99
|
+
|
100
|
+
When you want to add a new interface, you can do it as if it were a
|
101
|
+
regular ActiveRecord model:
|
102
|
+
|
103
|
+
```ruby
|
104
|
+
NetworkInterface.create name: 'eth2', dhcp: true
|
105
|
+
```
|
106
|
+
|
107
|
+
Running `create()` will not only persist this new setting to the JSON,
|
108
|
+
but will also run Chef on the box for the recipe provided in the class
|
109
|
+
definition.
|
110
|
+
|
111
|
+
Other AR-like methods such as `update()` and `destroy()` are also
|
112
|
+
available. They pretty much take the same parameters.
|
113
|
+
|
114
|
+
### Singletons
|
115
|
+
|
116
|
+
Another concept in configuration is the idea of a "singleton", that is,
|
117
|
+
a model that exists without the need for enumeration. For example, say
|
118
|
+
you have a recipe that configures Nginx like so:
|
119
|
+
|
120
|
+
```ruby
|
121
|
+
template "install site configuration" do
|
122
|
+
source "site.conf.erb"
|
123
|
+
action :create
|
124
|
+
end
|
125
|
+
|
126
|
+
nginx_site node[:app_cookbook][:nginx_site][:server_name] do
|
127
|
+
action :enable
|
128
|
+
end
|
129
|
+
```
|
130
|
+
|
131
|
+
You can configure that attribute with your front-end app by generating a
|
132
|
+
`Hibachi::Model` like this:
|
133
|
+
|
134
|
+
```ruby
|
135
|
+
class NginxSite < Hibachi::Model
|
136
|
+
recipe :nginx_site, :type => :singleton
|
137
|
+
attr_accessor :server_name
|
138
|
+
end
|
139
|
+
```
|
140
|
+
|
141
|
+
This affects the way attributes are both looked up and persisted by
|
142
|
+
Hibachi. Instead of treating the attribute as if it was an Array of
|
143
|
+
Hashes, Hibachi will write to the attribute directly as a Hash. So when
|
144
|
+
doing this:
|
145
|
+
|
146
|
+
```ruby
|
147
|
+
site = NginxSite.fetch
|
148
|
+
site.update :server_name => 'www.example.org'
|
149
|
+
```
|
150
|
+
|
151
|
+
You'll get **chef.json** that looks like this (using the `:app_cookbook`
|
152
|
+
namespace from before):
|
153
|
+
|
154
|
+
```json
|
155
|
+
{
|
156
|
+
"app_cookbook": {
|
157
|
+
"nginx_site": {
|
158
|
+
"server_name": "www.example.org"
|
159
|
+
}
|
160
|
+
}
|
161
|
+
}
|
162
|
+
```
|
163
|
+
|
164
|
+
|
165
|
+
## Contributing
|
166
|
+
|
167
|
+
1. Fork it ( http://github.com/tubbo/hibachi/fork )
|
168
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
169
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
170
|
+
4. Commit your tests (`git commit -am 'Tests for my feature'`)
|
171
|
+
5. Push to the branch (`git push origin my-new-feature`)
|
172
|
+
6. Create new Pull Request
|
173
|
+
7. ![ship it](https://assets-cdn.github.com/images/icons/emoji/shipit.png)
|
174
|
+
|
175
|
+
## License
|
176
|
+
|
177
|
+
This software is licensed under [The University of Illinois/NCSA Open
|
178
|
+
Source License](http://opensource.org/licenses/NCSA)...
|
179
|
+
|
180
|
+
Copyright (c) 2014 Tom Scott
|
181
|
+
All rights reserved.
|
182
|
+
|
183
|
+
Developed by:
|
184
|
+
|
185
|
+
Tom Scott
|
186
|
+
TelVue Corporation
|
187
|
+
|
188
|
+
http://www.telvue.com/
|
189
|
+
|
190
|
+
|
191
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal with the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
192
|
+
|
193
|
+
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimers.
|
194
|
+
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimers in the documentation and/or other materials provided with the distribution.
|
195
|
+
Neither the names of Tom Scott, TelVue Corporation, nor the names of its contributors may be used to endorse or promote products derived from this Software without specific prior written permission.
|
196
|
+
|
197
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE.
|
data/Rakefile
ADDED
data/hibachi.gemspec
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'hibachi/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "hibachi"
|
8
|
+
spec.version = Hibachi::VERSION
|
9
|
+
spec.authors = ["Tom Scott"]
|
10
|
+
spec.email = ["tscott@telvue.com"]
|
11
|
+
spec.summary = %q{A Rails model layer for your Chef configuration.}
|
12
|
+
spec.description = "#{spec.summary} Control your Chef configs with Rails."
|
13
|
+
spec.homepage = "http://github.com/tubbo/hibachi"
|
14
|
+
spec.license = "NCSA"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(spec)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency 'rails'
|
22
|
+
|
23
|
+
spec.add_development_dependency 'bundler', '~> 1.5'
|
24
|
+
spec.add_development_dependency 'rake'
|
25
|
+
spec.add_development_dependency 'rspec-rails'
|
26
|
+
spec.add_development_dependency 'yard'
|
27
|
+
spec.add_development_dependency 'redcarpet' # for docs in markdown
|
28
|
+
spec.add_development_dependency 'sqlite3' # for the dummy app
|
29
|
+
spec.add_development_dependency 'pry'
|
30
|
+
spec.add_development_dependency 'pry-byebug'
|
31
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'rails/generators/base'
|
2
|
+
|
3
|
+
module Hibachi
|
4
|
+
module Generators
|
5
|
+
class InstallGenerator < Rails::Generators::Base
|
6
|
+
desc "Installs Hibachi to this Rails app"
|
7
|
+
source_root File.expand_path("../../templates", __FILE__)
|
8
|
+
|
9
|
+
def copy_initializer
|
10
|
+
template 'hibachi.rb', 'config/initializers/hibachi.rb'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'rails/generators/named_base'
|
2
|
+
|
3
|
+
module Hibachi
|
4
|
+
module Generators
|
5
|
+
class ModelGenerator < Rails::Generators::NamedBase
|
6
|
+
include Rails::Generators::ResourceHelpers
|
7
|
+
|
8
|
+
desc "Generates a model for interacting with the Chef config"
|
9
|
+
source_root File.expand_path("../../templates", __FILE__)
|
10
|
+
|
11
|
+
argument :model_attributes, :type => :array
|
12
|
+
class_option :recipe, :type => :string, :description => "Specify recipe"
|
13
|
+
|
14
|
+
def copy_model_definition
|
15
|
+
template 'model.rb.erb', "app/models/#{file_path}.rb"
|
16
|
+
end
|
17
|
+
|
18
|
+
protected
|
19
|
+
def model_class
|
20
|
+
file_path.classify
|
21
|
+
end
|
22
|
+
|
23
|
+
def symbolized_model_attributes
|
24
|
+
ARGV[1..-1].reject { |arg|
|
25
|
+
arg =~ /\A--/
|
26
|
+
}.map { |arg|
|
27
|
+
":#{arg}"
|
28
|
+
}.join ', '
|
29
|
+
end
|
30
|
+
|
31
|
+
def recipe_name
|
32
|
+
return "'#{derived_recipe_name}'" if derived_recipe_name =~ /\:/
|
33
|
+
":#{derived_recipe_name}" # prefer symbols
|
34
|
+
end
|
35
|
+
|
36
|
+
def derived_recipe_name
|
37
|
+
options[:recipe] || file_path.tableize
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'hibachi'
|
2
|
+
|
3
|
+
# Configure global Hibachi settings here, such as the location of the log file
|
4
|
+
# and Chef JSON file. You my also use the Rails config to manipulate
|
5
|
+
# these settings, as all configuration data is stored in the
|
6
|
+
# `Rails.application.config.hibachi` namespace.
|
7
|
+
|
8
|
+
Hibachi.configure do |config|
|
9
|
+
#config.chef_json_path = "#{Rails.root}/config/chef.json"
|
10
|
+
#config.log_path = "#{Rails.root}/log/hibachi.log"
|
11
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'hibachi/install_active_job_error'
|
2
|
+
|
3
|
+
module Hibachi
|
4
|
+
module ChefRunner
|
5
|
+
# Runs the local Chef::Solo client for the given recipe. Loads the
|
6
|
+
# configuration specified at `Hibachi.config.chef_json_path` as
|
7
|
+
# Chef JSON, running only the given recipe name as specified in the
|
8
|
+
# method call. Used by the model backend to run Chef when they are
|
9
|
+
# updated, so configuration stays up to date with the JSON
|
10
|
+
# configuration.
|
11
|
+
def run_chef recipe, options={}
|
12
|
+
return true unless config.run_chef
|
13
|
+
|
14
|
+
if options[:background]
|
15
|
+
run_chef_in_bg(recipe) and return true
|
16
|
+
else
|
17
|
+
run "touch #{config.log_path}" and
|
18
|
+
log "Running Chef for '#{recipe}' at '#{Time.now}'..." and
|
19
|
+
chef "-r '#{recipe_name(recipe)}' -J #{config.chef_json_path}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
def run_chef_in_bg recipe
|
25
|
+
raise InstallActiveJobError unless using_active_job?
|
26
|
+
require 'hibachi/job' # we must require it here "conditionally"
|
27
|
+
Hibachi::Job.enqueue self
|
28
|
+
end
|
29
|
+
|
30
|
+
def using_active_job?
|
31
|
+
defined? ActiveJob::Base
|
32
|
+
end
|
33
|
+
|
34
|
+
def chef options
|
35
|
+
run %(cd #{config.chef_dir} && chef-solo -l debug #{options})
|
36
|
+
end
|
37
|
+
|
38
|
+
def log message
|
39
|
+
run %(echo "#{message}" >> #{config.chef_json_path})
|
40
|
+
end
|
41
|
+
|
42
|
+
def run command
|
43
|
+
`#{command}` and $?.success?
|
44
|
+
end
|
45
|
+
|
46
|
+
def recipe_name name
|
47
|
+
if name =~ /\:\:/
|
48
|
+
"recipe[#{cookbook}::#{name}]"
|
49
|
+
else
|
50
|
+
"recipe[#{cookbook}::#{name}::default]"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'hibachi/railtie'
|
2
|
+
|
3
|
+
module Hibachi
|
4
|
+
# Methods for manipulating Hibachi's configuration settings, which are
|
5
|
+
# actually stored in the Rails config. This module is meant to be
|
6
|
+
# extend'ed onto the Hibachi main module.
|
7
|
+
module Configuration
|
8
|
+
# Manipulate the Hibachi configuration.
|
9
|
+
def configure
|
10
|
+
yield config
|
11
|
+
end
|
12
|
+
|
13
|
+
# Shorthand access to the entire Hibachi configuration.
|
14
|
+
def config
|
15
|
+
Rails.application.config.hibachi
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Hibachi
|
2
|
+
# Thrown when `Hibachi::Job` is called, but `ActiveJob::Base` was not
|
3
|
+
# defined. Prevents a possibly harder-to-diagnose error.
|
4
|
+
class InstallActiveJobError < StandardError
|
5
|
+
def initialize
|
6
|
+
@message = %{
|
7
|
+
You must install ActiveJob to run Hibachi in the background..
|
8
|
+
|
9
|
+
<https://github.com/rails/activejob>
|
10
|
+
}
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/lib/hibachi/job.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'active_model'
|
2
|
+
|
3
|
+
require 'hibachi/recipe'
|
4
|
+
require 'hibachi/persistence'
|
5
|
+
require 'hibachi/provisioning'
|
6
|
+
require 'hibachi/querying'
|
7
|
+
|
8
|
+
module Hibachi
|
9
|
+
# A Rails model backend for describing machine configuration and
|
10
|
+
# exposing such configuration to manipulation by the end user.
|
11
|
+
# Hibachi::Model is subclassed like an ActiveRecord::Base, you define
|
12
|
+
# attributes on the class that map to attributes in each model's JSON
|
13
|
+
# representation.
|
14
|
+
class Model
|
15
|
+
include ActiveModel::Model
|
16
|
+
include Recipe
|
17
|
+
include Persistence
|
18
|
+
include Provisioning
|
19
|
+
extend Querying
|
20
|
+
|
21
|
+
# Store all attributes in this Hash.
|
22
|
+
attr_reader :attributes
|
23
|
+
|
24
|
+
# Set attributes to the main collector before assigning them to
|
25
|
+
# methods.
|
26
|
+
def initialize(from_attrs={})
|
27
|
+
@attributes = from_attrs
|
28
|
+
super
|
29
|
+
end
|
30
|
+
|
31
|
+
# The JSON representation of each Model object is simply its
|
32
|
+
# attributes exposed as JSON.
|
33
|
+
def to_json(*arguments)
|
34
|
+
@json ||= attributes.to_json
|
35
|
+
end
|
36
|
+
|
37
|
+
protected
|
38
|
+
def config
|
39
|
+
Hibachi.config
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/hibachi/node.rb
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
module Hibachi
|
2
|
+
# Interaction object with the Chef JSON. This class is used to write
|
3
|
+
# to and read from the configuration on disk, which is also used by
|
4
|
+
# Chef to manage machine configuration. It's called "Node" because
|
5
|
+
# that's what Chef Server calls each of the servers it's deploying
|
6
|
+
# your code to.
|
7
|
+
#
|
8
|
+
# All operations on this class are "hard", that is, they will actually
|
9
|
+
# write data out to the config file.
|
10
|
+
class Node
|
11
|
+
include ActiveModel::Model
|
12
|
+
include Enumerable
|
13
|
+
|
14
|
+
attr_accessor :attributes, :file_path
|
15
|
+
|
16
|
+
validates :file_path, presence: true
|
17
|
+
|
18
|
+
validate :file_exists
|
19
|
+
validate :has_cookbook_attributes
|
20
|
+
|
21
|
+
# Derive config from file at given path.
|
22
|
+
def self.find at_path=""
|
23
|
+
node = new file_path: at_path
|
24
|
+
node.valid?
|
25
|
+
node
|
26
|
+
end
|
27
|
+
|
28
|
+
# Test if the specified file we're supposed to manipulate does in
|
29
|
+
# fact exist.
|
30
|
+
def exists?
|
31
|
+
@exists ||= File.exists? file_path
|
32
|
+
end
|
33
|
+
alias present? exists?
|
34
|
+
|
35
|
+
# Iterate through all attributes.
|
36
|
+
def each
|
37
|
+
attributes.each { |attr| yield attr }
|
38
|
+
end
|
39
|
+
|
40
|
+
delegate :empty?, :to => :attributes
|
41
|
+
delegate :any?, :to => :attributes
|
42
|
+
|
43
|
+
# Find the attribute at a given key.
|
44
|
+
def [] key
|
45
|
+
attributes[key]
|
46
|
+
end
|
47
|
+
|
48
|
+
# Set the attribute at a given key.
|
49
|
+
def []= key, value
|
50
|
+
merge! key => value
|
51
|
+
end
|
52
|
+
|
53
|
+
# Merge incoming Hash with the Chef JSON.
|
54
|
+
def merge! with_new_attributes={}
|
55
|
+
attributes.merge! with_new_attributes
|
56
|
+
update!
|
57
|
+
end
|
58
|
+
|
59
|
+
# Delete an attribute from the Hash and write JSON.
|
60
|
+
def delete id
|
61
|
+
attributes.delete id
|
62
|
+
update!
|
63
|
+
end
|
64
|
+
|
65
|
+
# Delete all attributes from this recipe.
|
66
|
+
def delete!
|
67
|
+
@attributes = {}
|
68
|
+
update!
|
69
|
+
end
|
70
|
+
|
71
|
+
# Attributes as initially populated by the parsed JSON file. Scoped
|
72
|
+
# by the global cookbook.
|
73
|
+
def attributes
|
74
|
+
@attributes ||= parsed_json_attributes[Hibachi.config.cookbook] || {}
|
75
|
+
end
|
76
|
+
|
77
|
+
delegate :any?, :to => :attributes
|
78
|
+
delegate :empty?, :to => :attributes
|
79
|
+
|
80
|
+
protected
|
81
|
+
# All attributes as parsed from the Chef JSON.
|
82
|
+
def parsed_json_attributes
|
83
|
+
JSON.parse(chef_json).with_indifferent_access
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
def chef_json
|
88
|
+
@raw_json ||= File.read file_path
|
89
|
+
end
|
90
|
+
|
91
|
+
def update!
|
92
|
+
File.write file_path, pretty_formatted_json
|
93
|
+
true
|
94
|
+
rescue StandardError => exception
|
95
|
+
logger.error exception.message
|
96
|
+
exception.backtrace.each { |line| logger.error line }
|
97
|
+
false
|
98
|
+
end
|
99
|
+
|
100
|
+
def pretty_formatted_json
|
101
|
+
JSON.pretty_generate Hibachi.config.cookbook => attributes
|
102
|
+
end
|
103
|
+
|
104
|
+
def file_exists
|
105
|
+
errors.add :file, "'#{file_path}' does not exist" unless exists?
|
106
|
+
end
|
107
|
+
|
108
|
+
def has_cookbook_attributes
|
109
|
+
errors.add :cookbook, "could not be parsed from JSON" unless any?
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|