kitchen-scribe 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +3 -2
- data/lib/chef/knife/scribe_adjust.rb +33 -10
- data/lib/chef/knife/scribe_copy.rb +1 -1
- data/lib/kitchen-scribe/version.rb +1 -1
- data/spec/chef/knife/scribe_adjust_spec.rb +73 -26
- data/spec/chef/knife/scribe_copy_spec.rb +2 -2
- metadata +2 -2
data/README.md
CHANGED
@@ -10,9 +10,10 @@ It performs two main functions.
|
|
10
10
|
|
11
11
|
1. _Documenting changes_. It pulls the configuration of all your environements, roles, and nodes then saves them into json files in the place of your choosing and commits the changes to a local git repository. It can also pull/push them to a remote repostory for safekeeping.
|
12
12
|
|
13
|
-
2. _Making precise changes_. It can perform precise updates on your environments, roles and nodes by using json data structure describing the change.
|
13
|
+
2. _Making precise changes_. It can perform precise updates on your environments, roles and nodes by using json data structure describing the change.
|
14
14
|
|
15
|
-
|
15
|
+
|
16
|
+
The philosophy behind using scribe to update your environments, roles an nodes is that you may want to prepare some changes in advance, be able to test them and then have them applied to the final setup. Also it might be important to isolate those changes in a clear way so people who are not familiar with chef don't have to edit a huge json object to get them in. Lastly, you can now automate applying your changes as well, and automation is what Chef is all about in the end:).
|
16
17
|
|
17
18
|
The plugin is still in the beta stage, I've tested it manualy to some extent, but I'm sure there are things I missed. Please submit any bugs you find through the github issue system and I promiss to take care of them as soon as possible.
|
18
19
|
|
@@ -38,6 +38,9 @@ class Chef
|
|
38
38
|
}
|
39
39
|
|
40
40
|
ENVIRONMENT_ADJUSTMENT_TEMPLATE = {
|
41
|
+
"action" => "merge",
|
42
|
+
"type" => "environment",
|
43
|
+
"search" => "name:my_environment_name",
|
41
44
|
"adjustment" => { "default_attributes" => { },
|
42
45
|
"override_attributes" => { },
|
43
46
|
"cookbook_versions" => { }
|
@@ -45,6 +48,9 @@ class Chef
|
|
45
48
|
}
|
46
49
|
|
47
50
|
ROLE_ADJUSTMENT_TEMPLATE = {
|
51
|
+
"action" => "merge",
|
52
|
+
"type" => "role",
|
53
|
+
"search" => "name:my_role_name",
|
48
54
|
"adjustment" => { "default_attributes" => { },
|
49
55
|
"override_attributes" => { },
|
50
56
|
"run_list" => [ ]
|
@@ -52,8 +58,11 @@ class Chef
|
|
52
58
|
}
|
53
59
|
|
54
60
|
NODE_ADJUSTMENT_TEMPLATE = {
|
55
|
-
"
|
56
|
-
|
61
|
+
"action" => "merge",
|
62
|
+
"type" => "node",
|
63
|
+
"search" => "name:my_node_name",
|
64
|
+
"adjustment" => { "normal" => { },
|
65
|
+
"run_list" => [ ],
|
57
66
|
}
|
58
67
|
}
|
59
68
|
|
@@ -192,15 +201,29 @@ class Chef
|
|
192
201
|
def apply_adjustment(adjustment)
|
193
202
|
query = adjustment["search"].include?(":") ? adjustment["search"] : "name:" + adjustment["search"]
|
194
203
|
Chef::Search::Query.new.search(adjustment["type"], query ) do |result|
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
204
|
+
key = result.class.name.downcase + ":" + result.name
|
205
|
+
prepared_hash = prepare_adjustment_subject(key, result)
|
206
|
+
changes[key].store("adjusted", send(("action_" + adjustment["action"]).to_sym, prepared_hash, adjustment["adjustment"]))
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
def prepare_adjustment_subject(key, chef_object)
|
211
|
+
prepared_hash = prepare_object_hash(chef_object)
|
212
|
+
if changes.has_key? key
|
213
|
+
prepared_hash = changes[key]["adjusted"]
|
214
|
+
else
|
215
|
+
changes.store(key, { "original" => prepared_hash })
|
216
|
+
end
|
217
|
+
prepared_hash
|
218
|
+
end
|
219
|
+
|
220
|
+
def prepare_object_hash(chef_object)
|
221
|
+
prepared_hash = chef_object.to_hash
|
222
|
+
if prepared_hash["chef_type"] == "node"
|
223
|
+
prepared_hash.keep_if { |key, value| ["name","chef_type","chef_environment","run_list"].include? key }
|
224
|
+
prepared_hash.merge!({ "normal" => chef_object.normal_attrs })
|
203
225
|
end
|
226
|
+
prepared_hash
|
204
227
|
end
|
205
228
|
|
206
229
|
def write_adjustments
|
@@ -132,7 +132,7 @@ class Chef
|
|
132
132
|
|
133
133
|
def fetch_nodes
|
134
134
|
Chef::Node.list(true).each do |name, n|
|
135
|
-
node_hash = {"name" => name, "env" => n.chef_environment, "
|
135
|
+
node_hash = {"name" => name, "env" => n.chef_environment, "normal" => n.normal_attrs, "run_list" => n.run_list}
|
136
136
|
save_to_file("nodes",name, node_hash)
|
137
137
|
end
|
138
138
|
end
|
@@ -28,10 +28,6 @@ describe Chef::Knife::ScribeAdjust do
|
|
28
28
|
@scribe.should respond_to(:action_merge)
|
29
29
|
end
|
30
30
|
|
31
|
-
it "responds to #action_hash_only_merge" do
|
32
|
-
@scribe.should respond_to(:action_hash_only_merge)
|
33
|
-
end
|
34
|
-
|
35
31
|
it "responds to #action_overwrite" do
|
36
32
|
@scribe.should respond_to(:action_overwrite)
|
37
33
|
end
|
@@ -614,11 +610,7 @@ describe Chef::Knife::ScribeAdjust do
|
|
614
610
|
Chef::Search::Query.stub(:new).and_return(@query)
|
615
611
|
@chef_obj = double("chef_object")
|
616
612
|
@chef_obj.stub(:to_hash).and_return( { "name" => "test_name", "chef_type" => "test_type", "a" => 3, "c" => 3 } )
|
617
|
-
|
618
|
-
json_create_return_obj = double("final_chef_object")
|
619
|
-
json_create_return_obj.stub(:save)
|
620
|
-
chef_obj_class.stub(:json_create).and_return(json_create_return_obj)
|
621
|
-
@chef_obj.stub(:class).and_return(chef_obj_class)
|
613
|
+
@chef_obj.stub(:name).and_return("test_name")
|
622
614
|
@query.stub(:search).and_yield(@chef_obj)
|
623
615
|
end
|
624
616
|
|
@@ -644,35 +636,90 @@ describe Chef::Knife::ScribeAdjust do
|
|
644
636
|
end
|
645
637
|
end
|
646
638
|
|
647
|
-
it "
|
648
|
-
@
|
639
|
+
it "saves the changed version in the changes hash" do
|
640
|
+
adjusted_hash = @chef_obj.to_hash.dup.merge({ "a" => "b" })
|
641
|
+
changes_hash = { "original" => @chef_obj.to_hash, "adjusted" => adjusted_hash }
|
642
|
+
@scribe.changes[@chef_obj.class.name.downcase + ":" + @chef_obj.name] = changes_hash
|
643
|
+
adjusted_hash = @scribe.send(("action_" + @adjustment["action"]).to_sym, adjusted_hash, @adjustment["adjustment"])
|
644
|
+
changes_hash.should_receive(:store).with("adjusted", adjusted_hash).and_call_original
|
649
645
|
@scribe.apply_adjustment(@adjustment)
|
650
646
|
end
|
647
|
+
end
|
648
|
+
|
649
|
+
describe "#prepare_adjustment_subject" do
|
650
|
+
before(:each) do
|
651
|
+
@chef_obj = double("chef_object")
|
652
|
+
@chef_obj.stub(:to_hash).and_return( { "name" => "test_name", "chef_type" => "test_type", "a" => 3, "c" => 3 } )
|
653
|
+
@key = "test_type:test_name"
|
654
|
+
end
|
655
|
+
|
656
|
+
it "checks if the a change to a given object is already pending" do
|
657
|
+
@scribe.changes.should_receive(:has_key?).with(@key)
|
658
|
+
@scribe.prepare_adjustment_subject(@key, @chef_obj)
|
659
|
+
end
|
651
660
|
|
652
661
|
describe "if the key doesn't exist" do
|
653
662
|
it "saves the original in the changes hash" do
|
654
|
-
@scribe.changes.should_receive(:store).with(@
|
663
|
+
@scribe.changes.should_receive(:store).with(@key,
|
655
664
|
{ "original" => @chef_obj.to_hash }
|
656
665
|
).and_call_original
|
657
|
-
@scribe.
|
666
|
+
@scribe.prepare_adjustment_subject(@key, @chef_obj)
|
667
|
+
end
|
668
|
+
|
669
|
+
it "prepares the object hash" do
|
670
|
+
@scribe.should_receive(:prepare_object_hash).with(@chef_obj)
|
671
|
+
@scribe.prepare_adjustment_subject(@key, @chef_obj)
|
672
|
+
end
|
673
|
+
|
674
|
+
it "returns the prepared object hash" do
|
675
|
+
@scribe.prepare_adjustment_subject(@key, @chef_obj).should == @chef_obj.to_hash
|
658
676
|
end
|
659
677
|
end
|
660
678
|
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
679
|
+
describe "if the key already exists" do
|
680
|
+
before(:each) do
|
681
|
+
@adjusted_hash = @chef_obj.to_hash.dup.merge({"a" => "b"})
|
682
|
+
changes_hash = { "original" => @chef_obj.to_hash, "adjusted" => @adjusted_hash }
|
683
|
+
@scribe.changes[@key] = changes_hash
|
684
|
+
end
|
685
|
+
|
686
|
+
it "it returns the previously adjusted version" do
|
687
|
+
@scribe.prepare_adjustment_subject(@key, @chef_obj).should == @adjusted_hash
|
688
|
+
end
|
667
689
|
end
|
690
|
+
end
|
668
691
|
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
692
|
+
describe "#prepare_object_hash" do
|
693
|
+
describe "if object isn't a node" do
|
694
|
+
before(:each) do
|
695
|
+
@chef_obj = double("chef_object")
|
696
|
+
@chef_obj.stub(:to_hash).and_return( { "name" => "test_name", "chef_type" => "test_type", "a" => 3, "c" => 3 } )
|
697
|
+
end
|
698
|
+
|
699
|
+
it "returns the object converted to hash" do
|
700
|
+
@scribe.prepare_object_hash(@chef_obj).should == @chef_obj.to_hash
|
701
|
+
end
|
702
|
+
end
|
703
|
+
|
704
|
+
describe "if object is a node" do
|
705
|
+
before(:each) do
|
706
|
+
@chef_obj = double("chef_object")
|
707
|
+
@node_data = { "name" => "test_name",
|
708
|
+
"chef_type" => "node",
|
709
|
+
"a" => 3,
|
710
|
+
"c" => 3,
|
711
|
+
"chef_environment" => "test_env",
|
712
|
+
"run_list" => "blah"
|
713
|
+
}
|
714
|
+
@chef_obj.stub(:to_hash).and_return( @node_data)
|
715
|
+
@chef_obj.stub(:normal_attrs).and_return({"nx" => "ny"})
|
716
|
+
@prepared_data = @node_data.select { |key, value| ["name","chef_type","chef_environment","run_list"].include? key }
|
717
|
+
@prepared_data.merge!({"normal" => {"nx" => "ny"}})
|
718
|
+
end
|
719
|
+
|
720
|
+
it "keeps only the relevant information" do
|
721
|
+
@scribe.prepare_object_hash(@chef_obj).should == @prepared_data
|
722
|
+
end
|
676
723
|
end
|
677
724
|
end
|
678
725
|
|
@@ -398,13 +398,13 @@ describe Chef::Knife::ScribeCopy do
|
|
398
398
|
@node1.stub(:chef_environment) { "chef_environment1" }
|
399
399
|
@node1.stub(:normal_attrs) { { :attr1 => "val1" } }
|
400
400
|
@node1.stub(:run_list) { ["cookbook1", "cookbook2"] }
|
401
|
-
@serialized_node1 = {"name" => @node1.name, "env" => @node1.chef_environment, "
|
401
|
+
@serialized_node1 = {"name" => @node1.name, "env" => @node1.chef_environment, "normal" => @node1.normal_attrs, "run_list" => @node1.run_list}
|
402
402
|
@node2 = { :test2 => :value2 }
|
403
403
|
@node2.stub(:name) { "node_name2" }
|
404
404
|
@node2.stub(:chef_environment) { "chef_environment2" }
|
405
405
|
@node2.stub(:normal_attrs) { { :attrA => "valA" } }
|
406
406
|
@node2.stub(:run_list) { ["cookbookA", "cookbookB"] }
|
407
|
-
@serialized_node2 = {"name" => @node2.name, "env" => @node2.chef_environment, "
|
407
|
+
@serialized_node2 = {"name" => @node2.name, "env" => @node2.chef_environment, "normal" => @node2.normal_attrs, "run_list" => @node2.run_list}
|
408
408
|
Chef::Node.stub(:list) { { @node1.name => @node1, @node2.name => @node2 } }
|
409
409
|
end
|
410
410
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kitchen-scribe
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-07-25 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: chef
|