safety_razor 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.cane +0 -0
- data/.gitignore +19 -0
- data/.tailor +4 -0
- data/.travis.yml +11 -0
- data/Berksfile +3 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +9 -0
- data/Guardfile +10 -0
- data/LICENSE.txt +22 -0
- data/README.md +328 -0
- data/Rakefile +39 -0
- data/Vagrantfile +27 -0
- data/lib/safety_razor.rb +7 -0
- data/lib/safety_razor/client.rb +58 -0
- data/lib/safety_razor/slice/active_model.rb +30 -0
- data/lib/safety_razor/slice/base.rb +89 -0
- data/lib/safety_razor/slice/broker.rb +27 -0
- data/lib/safety_razor/slice/model.rb +27 -0
- data/lib/safety_razor/slice/node.rb +58 -0
- data/lib/safety_razor/slice/policy.rb +27 -0
- data/lib/safety_razor/slice/tag.rb +22 -0
- data/lib/safety_razor/slice/tag_matcher.rb +65 -0
- data/lib/safety_razor/version.rb +6 -0
- data/safety_razor.gemspec +36 -0
- data/script/bootstrap +33 -0
- data/spec/acceptance/active_model_spec.rb +115 -0
- data/spec/acceptance/broker_spec.rb +52 -0
- data/spec/acceptance/model_spec.rb +69 -0
- data/spec/acceptance/node_spec.rb +59 -0
- data/spec/acceptance/policy_spec.rb +82 -0
- data/spec/acceptance/tag_matcher_spec.rb +38 -0
- data/spec/acceptance/tag_spec.rb +43 -0
- data/spec/spec_helper.rb +16 -0
- data/spec/unit/safety_razor/client_spec.rb +84 -0
- metadata +281 -0
data/Vagrantfile
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- mode: ruby -*-
|
2
|
+
# vi: set ft=ruby :
|
3
|
+
|
4
|
+
Vagrant.configure("2") do |config|
|
5
|
+
config.vm.box = "opscode-ubuntu-12.04"
|
6
|
+
config.vm.box_url = "https://opscode-vm.s3.amazonaws.com/vagrant/opscode_ubuntu-12.04_provisionerless.box"
|
7
|
+
|
8
|
+
config.vm.network :forwarded_port, guest: 8026, host: 8026
|
9
|
+
|
10
|
+
config.omnibus.chef_version = :latest
|
11
|
+
config.berkshelf.enabled = true
|
12
|
+
|
13
|
+
config.vm.provision :chef_solo do |chef|
|
14
|
+
chef.run_list = ["recipe[razor]"]
|
15
|
+
chef.json = {
|
16
|
+
:razor => {
|
17
|
+
:images => {
|
18
|
+
'ubuntu-minimal-10.04' => {
|
19
|
+
'url' => 'http://archive.ubuntu.com/ubuntu/dists/lucid/main/installer-amd64/current/images/netboot/mini.iso',
|
20
|
+
'checksum' => '72602f91a85a856248e519c6446d303fa8990b4328899385990a95177681dc58',
|
21
|
+
'version' => '10.04'
|
22
|
+
}
|
23
|
+
}
|
24
|
+
}
|
25
|
+
}
|
26
|
+
end
|
27
|
+
end
|
data/lib/safety_razor.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'faraday'
|
4
|
+
|
5
|
+
require 'safety_razor/slice/active_model'
|
6
|
+
require 'safety_razor/slice/broker'
|
7
|
+
require 'safety_razor/slice/model'
|
8
|
+
require 'safety_razor/slice/node'
|
9
|
+
require 'safety_razor/slice/policy'
|
10
|
+
require 'safety_razor/slice/tag'
|
11
|
+
require 'safety_razor/slice/tag_matcher'
|
12
|
+
|
13
|
+
module SafetyRazor
|
14
|
+
|
15
|
+
# Client object which manages the connection to the Razor API endpoint.
|
16
|
+
#
|
17
|
+
# @author Fletcher Nichol <fnichol@nichol.ca>
|
18
|
+
#
|
19
|
+
class Client
|
20
|
+
|
21
|
+
attr_reader :connection
|
22
|
+
|
23
|
+
def initialize(options = {})
|
24
|
+
@connection = Faraday.new(:url => options[:uri]) do |faraday|
|
25
|
+
faraday.request :url_encoded
|
26
|
+
faraday.adapter Faraday.default_adapter
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def active_model
|
31
|
+
@active_model ||= Slice::ActiveModel.new(self)
|
32
|
+
end
|
33
|
+
|
34
|
+
def broker
|
35
|
+
@broker ||= Slice::Broker.new(self)
|
36
|
+
end
|
37
|
+
|
38
|
+
def model
|
39
|
+
@model ||= Slice::Model.new(self)
|
40
|
+
end
|
41
|
+
|
42
|
+
def node
|
43
|
+
@node ||= Slice::Node.new(self)
|
44
|
+
end
|
45
|
+
|
46
|
+
def policy
|
47
|
+
@policy ||= Slice::Policy.new(self)
|
48
|
+
end
|
49
|
+
|
50
|
+
def tag
|
51
|
+
@tag ||= Slice::Tag.new(self)
|
52
|
+
end
|
53
|
+
|
54
|
+
def tag_matcher
|
55
|
+
@tag_matcher ||= Slice::TagMatcher.new(self)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'safety_razor/slice/base'
|
4
|
+
|
5
|
+
module SafetyRazor
|
6
|
+
|
7
|
+
module Slice
|
8
|
+
|
9
|
+
# Client API for Razor's active model slice.
|
10
|
+
#
|
11
|
+
# @author Fletcher Nichol <fnichol@nichol.ca>
|
12
|
+
#
|
13
|
+
class ActiveModel < Base
|
14
|
+
|
15
|
+
def create(params)
|
16
|
+
raise NoMethodError, "Node#create is not defined"
|
17
|
+
end
|
18
|
+
|
19
|
+
def update(params)
|
20
|
+
raise NoMethodError, "Node#update is not defined"
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def slice_name
|
26
|
+
"active_model"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'hashie'
|
5
|
+
|
6
|
+
module SafetyRazor
|
7
|
+
|
8
|
+
module Slice
|
9
|
+
|
10
|
+
# Common behavior for Razor's model slices.
|
11
|
+
#
|
12
|
+
# @author Fletcher Nichol <fnichol@nichol.ca>
|
13
|
+
#
|
14
|
+
class Base
|
15
|
+
|
16
|
+
def initialize(client)
|
17
|
+
@client = client
|
18
|
+
end
|
19
|
+
|
20
|
+
def create(params)
|
21
|
+
payload = JSON.generate(params)
|
22
|
+
response = connection.post(slice_path, 'json_hash' => payload)
|
23
|
+
parse(response).first
|
24
|
+
end
|
25
|
+
|
26
|
+
def get(uuid)
|
27
|
+
response = connection.get(slice_path(uuid))
|
28
|
+
parse(response).first
|
29
|
+
end
|
30
|
+
|
31
|
+
def all
|
32
|
+
response = connection.get(slice_path)
|
33
|
+
parse(response)
|
34
|
+
end
|
35
|
+
|
36
|
+
def update(params)
|
37
|
+
payload = JSON.generate(params)
|
38
|
+
uuid = params[:uuid]
|
39
|
+
response = connection.put(slice_path(uuid), 'json_hash' => payload)
|
40
|
+
parse(response).first
|
41
|
+
end
|
42
|
+
|
43
|
+
def destroy(uuid)
|
44
|
+
connection.delete(slice_path(uuid))
|
45
|
+
end
|
46
|
+
|
47
|
+
protected
|
48
|
+
|
49
|
+
attr_reader :client
|
50
|
+
|
51
|
+
def connection
|
52
|
+
client.connection
|
53
|
+
end
|
54
|
+
|
55
|
+
def slice_path(uuid = nil)
|
56
|
+
path = "/razor/api/#{slice_name}"
|
57
|
+
path += "/#{uuid}" if uuid
|
58
|
+
path
|
59
|
+
end
|
60
|
+
|
61
|
+
def parse(response)
|
62
|
+
collection = JSON.parse(response.body)["response"]
|
63
|
+
collection = [collection] if collection.is_a?(Hash)
|
64
|
+
|
65
|
+
Array(collection).map { |obj| new_mash(strip_ivars(obj)) }
|
66
|
+
end
|
67
|
+
|
68
|
+
def new_mash(obj)
|
69
|
+
Hashie::Mash.new(obj)
|
70
|
+
end
|
71
|
+
|
72
|
+
def strip_ivars(obj)
|
73
|
+
case obj
|
74
|
+
when Hash
|
75
|
+
stripped = Hash.new
|
76
|
+
obj.each_pair do |key, value|
|
77
|
+
new_key = key.is_a?(String) ? key.sub(/^@/, '') : key
|
78
|
+
stripped[new_key] = strip_ivars(value)
|
79
|
+
end
|
80
|
+
stripped
|
81
|
+
when Array
|
82
|
+
obj.map { |value| strip_ivars(value) }
|
83
|
+
else
|
84
|
+
obj
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'safety_razor/slice/base'
|
4
|
+
|
5
|
+
module SafetyRazor
|
6
|
+
|
7
|
+
module Slice
|
8
|
+
|
9
|
+
# Client API for Razor's broker slice.
|
10
|
+
#
|
11
|
+
# @author Fletcher Nichol <fnichol@nichol.ca>
|
12
|
+
#
|
13
|
+
class Broker < Base
|
14
|
+
|
15
|
+
def plugins
|
16
|
+
response = connection.get(slice_path("plugins"))
|
17
|
+
parse(response)
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def slice_name
|
23
|
+
"broker"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'safety_razor/slice/base'
|
4
|
+
|
5
|
+
module SafetyRazor
|
6
|
+
|
7
|
+
module Slice
|
8
|
+
|
9
|
+
# Client API for Razor's model slice.
|
10
|
+
#
|
11
|
+
# @author Fletcher Nichol <fnichol@nichol.ca>
|
12
|
+
#
|
13
|
+
class Model < Base
|
14
|
+
|
15
|
+
def templates
|
16
|
+
response = connection.get(slice_path("templates"))
|
17
|
+
parse(response)
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def slice_name
|
23
|
+
"model"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'safety_razor/slice/base'
|
4
|
+
|
5
|
+
module SafetyRazor
|
6
|
+
|
7
|
+
module Slice
|
8
|
+
|
9
|
+
# Client API for Razor's node slice.
|
10
|
+
#
|
11
|
+
# @author Fletcher Nichol <fnichol@nichol.ca>
|
12
|
+
#
|
13
|
+
class Node < Base
|
14
|
+
|
15
|
+
def register(params)
|
16
|
+
payload = JSON.generate(params)
|
17
|
+
response = connection.post(slice_path("register"),
|
18
|
+
'json_hash' => payload)
|
19
|
+
parse(response).first
|
20
|
+
end
|
21
|
+
|
22
|
+
def checkin(params)
|
23
|
+
payload = JSON.generate(params)
|
24
|
+
response = connection.post(slice_path("checkin"),
|
25
|
+
'json_hash' => payload)
|
26
|
+
parse(response).first
|
27
|
+
end
|
28
|
+
|
29
|
+
def get_attributes(uuid)
|
30
|
+
response = connection.get(slice_path(uuid), "field" => "attributes")
|
31
|
+
parse(response).first
|
32
|
+
end
|
33
|
+
|
34
|
+
def get_hardware_ids(uuid)
|
35
|
+
response = connection.get(slice_path(uuid), "field" => "hardware_ids")
|
36
|
+
parse(response).first["hw_id"]
|
37
|
+
end
|
38
|
+
|
39
|
+
def create(params)
|
40
|
+
raise NoMethodError, "Node#create is not defined"
|
41
|
+
end
|
42
|
+
|
43
|
+
def update(params)
|
44
|
+
raise NoMethodError, "Node#update is not defined"
|
45
|
+
end
|
46
|
+
|
47
|
+
def destroy(uuid)
|
48
|
+
raise NoMethodError, "Node#destroy is not defined"
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def slice_name
|
54
|
+
"node"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'safety_razor/slice/base'
|
4
|
+
|
5
|
+
module SafetyRazor
|
6
|
+
|
7
|
+
module Slice
|
8
|
+
|
9
|
+
# Client API for Razor's policy slice.
|
10
|
+
#
|
11
|
+
# @author Fletcher Nichol <fnichol@nichol.ca>
|
12
|
+
#
|
13
|
+
class Policy < Base
|
14
|
+
|
15
|
+
def templates
|
16
|
+
response = connection.get(slice_path("templates"))
|
17
|
+
parse(response)
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def slice_name
|
23
|
+
"policy"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'safety_razor/slice/base'
|
4
|
+
|
5
|
+
module SafetyRazor
|
6
|
+
|
7
|
+
module Slice
|
8
|
+
|
9
|
+
# Client API for Razor's tag slice.
|
10
|
+
#
|
11
|
+
# @author Fletcher Nichol <fnichol@nichol.ca>
|
12
|
+
#
|
13
|
+
class Tag < Base
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def slice_name
|
18
|
+
"tag"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'safety_razor/slice/base'
|
4
|
+
|
5
|
+
module SafetyRazor
|
6
|
+
|
7
|
+
module Slice
|
8
|
+
|
9
|
+
# Client API for Razor's tag matcher slice.
|
10
|
+
#
|
11
|
+
# @author Fletcher Nichol <fnichol@nichol.ca>
|
12
|
+
#
|
13
|
+
class TagMatcher < Base
|
14
|
+
|
15
|
+
def create(tag_uuid, params)
|
16
|
+
payload = JSON.generate(params)
|
17
|
+
response = connection.post(slice_path(tag_uuid), 'json_hash' => payload)
|
18
|
+
parse(response).first
|
19
|
+
end
|
20
|
+
|
21
|
+
def get(tag_uuid, uuid)
|
22
|
+
response = connection.get(slice_path(tag_uuid, uuid))
|
23
|
+
parse(response).first
|
24
|
+
end
|
25
|
+
|
26
|
+
def all
|
27
|
+
raise NoMethodError, "TagMatcher#all is not defined"
|
28
|
+
end
|
29
|
+
|
30
|
+
def update(tag_uuid, params)
|
31
|
+
payload = JSON.generate(params)
|
32
|
+
uuid = params[:uuid]
|
33
|
+
response = connection.put(slice_path(tag_uuid, uuid),
|
34
|
+
'json_hash' => payload)
|
35
|
+
parse(response).first
|
36
|
+
end
|
37
|
+
|
38
|
+
def destroy(tag_uuid, uuid)
|
39
|
+
connection.delete(slice_path(tag_uuid, uuid))
|
40
|
+
end
|
41
|
+
|
42
|
+
protected
|
43
|
+
|
44
|
+
def slice_path(tag_uuid, uuid = nil)
|
45
|
+
path = "/razor/api/tag/#{tag_uuid}/matcher"
|
46
|
+
path += "/#{uuid}" if uuid
|
47
|
+
path
|
48
|
+
end
|
49
|
+
|
50
|
+
def new_mash(obj)
|
51
|
+
Hashie::Mash.new(obj).extend(KeyReaderMethod)
|
52
|
+
end
|
53
|
+
|
54
|
+
# Overrides a Hash method collision with the tag matcher attribute of
|
55
|
+
# `key'.
|
56
|
+
#
|
57
|
+
module KeyReaderMethod
|
58
|
+
|
59
|
+
def key
|
60
|
+
self["key"]
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|