safety_razor 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|