knife-essentials 0.8.3 → 0.8.4
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/lib/chef/knife/diff_essentials.rb +2 -2
- data/lib/chef/knife/download_essentials.rb +5 -1
- data/lib/chef/knife/list_essentials.rb +2 -1
- data/lib/chef/knife/upload_essentials.rb +5 -1
- data/lib/chef_fs/command_line.rb +94 -63
- data/lib/chef_fs/file_system.rb +113 -93
- data/lib/chef_fs/file_system/base_fs_object.rb +91 -37
- data/lib/chef_fs/file_system/chef_repository_file_system_cookbooks_dir.rb +14 -1
- data/lib/chef_fs/file_system/chef_server_root_dir.rb +2 -1
- data/lib/chef_fs/file_system/cookbook_file.rb +7 -1
- data/lib/chef_fs/file_system/cookbooks_dir.rb +13 -6
- data/lib/chef_fs/file_system/environments_dir.rb +59 -0
- data/lib/chef_fs/file_system/multiplexed_dir.rb +1 -1
- data/lib/chef_fs/file_system/nodes_dir.rb +1 -0
- data/lib/chef_fs/file_system/operation_not_allowed_error.rb +29 -0
- data/lib/chef_fs/file_system/operation_skipped_error.rb +29 -0
- data/lib/chef_fs/knife.rb +29 -21
- data/lib/chef_fs/version.rb +1 -1
- data/spec/chef_fs/diff_spec.rb +30 -30
- data/spec/chef_fs/file_system/cookbooks_dir_spec.rb +5 -1
- data/spec/integration/chef_repo_path_spec.rb +705 -0
- data/spec/integration/chef_repository_file_system_spec.rb +82 -713
- data/spec/integration/chefignore_spec.rb +258 -0
- data/spec/integration/diff_spec.rb +151 -0
- data/spec/integration/download_spec.rb +403 -0
- data/spec/integration/list_spec.rb +21 -21
- data/spec/integration/upload_spec.rb +407 -0
- data/spec/support/integration_helper.rb +9 -4
- data/spec/support/knife_support.rb +14 -2
- metadata +12 -3
@@ -0,0 +1,258 @@
|
|
1
|
+
require 'support/integration_helper'
|
2
|
+
require 'chef/knife/list_essentials'
|
3
|
+
require 'chef/knife/show_essentials'
|
4
|
+
|
5
|
+
describe 'chefignore tests' do
|
6
|
+
extend IntegrationSupport
|
7
|
+
include KnifeSupport
|
8
|
+
|
9
|
+
when_the_repository "has lots of stuff in it" do
|
10
|
+
file 'roles/x.json', {}
|
11
|
+
file 'environments/x.json', {}
|
12
|
+
file 'data_bags/bag1/x.json', {}
|
13
|
+
file 'cookbooks/cookbook1/x.json', {}
|
14
|
+
|
15
|
+
context "and has a chefignore everywhere except cookbooks" do
|
16
|
+
chefignore = "x.json\nroles/x.json\nenvironments/x.json\ndata_bags/bag1/x.json\nbag1/x.json\ncookbooks/cookbook1/x.json\ncookbook1/x.json\n"
|
17
|
+
file 'chefignore', chefignore
|
18
|
+
file 'roles/chefignore', chefignore
|
19
|
+
file 'environments/chefignore', chefignore
|
20
|
+
file 'data_bags/chefignore', chefignore
|
21
|
+
file 'data_bags/bag1/chefignore', chefignore
|
22
|
+
file 'cookbooks/cookbook1/chefignore', chefignore
|
23
|
+
|
24
|
+
it 'nothing is ignored' do
|
25
|
+
# NOTE: many of the "chefignore" files should probably not show up
|
26
|
+
# themselves, but we have other tests that talk about that
|
27
|
+
knife('list --local -Rfp /').should_succeed <<EOM
|
28
|
+
/cookbooks/
|
29
|
+
/cookbooks/cookbook1/
|
30
|
+
/cookbooks/cookbook1/chefignore
|
31
|
+
/cookbooks/cookbook1/x.json
|
32
|
+
/data_bags/
|
33
|
+
/data_bags/bag1/
|
34
|
+
/data_bags/bag1/chefignore
|
35
|
+
/data_bags/bag1/x.json
|
36
|
+
/data_bags/chefignore
|
37
|
+
/environments/
|
38
|
+
/environments/chefignore
|
39
|
+
/environments/x.json
|
40
|
+
/roles/
|
41
|
+
/roles/chefignore
|
42
|
+
/roles/x.json
|
43
|
+
EOM
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
when_the_repository 'has a cookbook with only chefignored files' do
|
49
|
+
file 'cookbooks/cookbook1/templates/default/x.rb', ''
|
50
|
+
file 'cookbooks/cookbook1/libraries/x.rb', ''
|
51
|
+
file 'cookbooks/chefignore', "libraries/x.rb\ntemplates/default/x.rb\n"
|
52
|
+
|
53
|
+
it 'the cookbook is not listed' do
|
54
|
+
knife('list --local -Rfp /').should_succeed(<<EOM, :stderr => "WARN: Cookbook 'cookbook1' is empty or entirely chefignored at #{Chef::Config.chef_repo_path}/cookbooks/cookbook1\n")
|
55
|
+
/cookbooks/
|
56
|
+
EOM
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
when_the_repository "has multiple cookbooks" do
|
61
|
+
file 'cookbooks/cookbook1/x.json', {}
|
62
|
+
file 'cookbooks/cookbook1/y.json', {}
|
63
|
+
file 'cookbooks/cookbook2/x.json', {}
|
64
|
+
file 'cookbooks/cookbook2/y.json', {}
|
65
|
+
|
66
|
+
context 'and has a chefignore with filenames' do
|
67
|
+
file 'cookbooks/chefignore', "x.json\n"
|
68
|
+
|
69
|
+
it 'matching files and directories get ignored in all cookbooks' do
|
70
|
+
knife('list --local -Rfp /').should_succeed <<EOM
|
71
|
+
/cookbooks/
|
72
|
+
/cookbooks/cookbook1/
|
73
|
+
/cookbooks/cookbook1/y.json
|
74
|
+
/cookbooks/cookbook2/
|
75
|
+
/cookbooks/cookbook2/y.json
|
76
|
+
EOM
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
context "and has a chefignore with wildcards" do
|
81
|
+
file 'cookbooks/chefignore', "x.*\n"
|
82
|
+
file 'cookbooks/cookbook1/x.rb', ''
|
83
|
+
|
84
|
+
it 'matching files and directories get ignored in all cookbooks' do
|
85
|
+
knife('list --local -Rfp /').should_succeed <<EOM
|
86
|
+
/cookbooks/
|
87
|
+
/cookbooks/cookbook1/
|
88
|
+
/cookbooks/cookbook1/y.json
|
89
|
+
/cookbooks/cookbook2/
|
90
|
+
/cookbooks/cookbook2/y.json
|
91
|
+
EOM
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
context "and has a chefignore with relative paths" do
|
96
|
+
file 'cookbooks/cookbook1/recipes/x.rb', ''
|
97
|
+
file 'cookbooks/cookbook2/recipes/y.rb', ''
|
98
|
+
file 'cookbooks/chefignore', "recipes/x.rb\n"
|
99
|
+
|
100
|
+
it 'matching directories get ignored' do
|
101
|
+
knife('list --local -Rfp /').should_succeed <<EOM
|
102
|
+
/cookbooks/
|
103
|
+
/cookbooks/cookbook1/
|
104
|
+
/cookbooks/cookbook1/x.json
|
105
|
+
/cookbooks/cookbook1/y.json
|
106
|
+
/cookbooks/cookbook2/
|
107
|
+
/cookbooks/cookbook2/recipes/
|
108
|
+
/cookbooks/cookbook2/recipes/y.rb
|
109
|
+
/cookbooks/cookbook2/x.json
|
110
|
+
/cookbooks/cookbook2/y.json
|
111
|
+
EOM
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
context "and has a chefignore with subdirectories" do
|
116
|
+
file 'cookbooks/cookbook1/recipes/y.rb', ''
|
117
|
+
file 'cookbooks/chefignore', "recipes\nrecipes/\n"
|
118
|
+
|
119
|
+
it 'matching directories do NOT get ignored' do
|
120
|
+
knife('list --local -Rfp /').should_succeed <<EOM
|
121
|
+
/cookbooks/
|
122
|
+
/cookbooks/cookbook1/
|
123
|
+
/cookbooks/cookbook1/recipes/
|
124
|
+
/cookbooks/cookbook1/recipes/y.rb
|
125
|
+
/cookbooks/cookbook1/x.json
|
126
|
+
/cookbooks/cookbook1/y.json
|
127
|
+
/cookbooks/cookbook2/
|
128
|
+
/cookbooks/cookbook2/x.json
|
129
|
+
/cookbooks/cookbook2/y.json
|
130
|
+
EOM
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
context "and has a chefignore that ignores all files in a subdirectory" do
|
135
|
+
file 'cookbooks/cookbook1/templates/default/x.rb', ''
|
136
|
+
file 'cookbooks/cookbook1/libraries/x.rb', ''
|
137
|
+
file 'cookbooks/chefignore', "libraries/x.rb\ntemplates/default/x.rb\n"
|
138
|
+
|
139
|
+
it 'ignores the subdirectory entirely' do
|
140
|
+
knife('list --local -Rfp /').should_succeed <<EOM
|
141
|
+
/cookbooks/
|
142
|
+
/cookbooks/cookbook1/
|
143
|
+
/cookbooks/cookbook1/x.json
|
144
|
+
/cookbooks/cookbook1/y.json
|
145
|
+
/cookbooks/cookbook2/
|
146
|
+
/cookbooks/cookbook2/x.json
|
147
|
+
/cookbooks/cookbook2/y.json
|
148
|
+
EOM
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
context "and has an empty chefignore" do
|
153
|
+
file 'cookbooks/chefignore', "\n"
|
154
|
+
|
155
|
+
it 'nothing is ignored' do
|
156
|
+
knife('list --local -Rfp /').should_succeed <<EOM
|
157
|
+
/cookbooks/
|
158
|
+
/cookbooks/cookbook1/
|
159
|
+
/cookbooks/cookbook1/x.json
|
160
|
+
/cookbooks/cookbook1/y.json
|
161
|
+
/cookbooks/cookbook2/
|
162
|
+
/cookbooks/cookbook2/x.json
|
163
|
+
/cookbooks/cookbook2/y.json
|
164
|
+
EOM
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
context "and has a chefignore with comments and empty lines" do
|
169
|
+
file 'cookbooks/chefignore', "\n\n # blah\n#\nx.json\n\n"
|
170
|
+
|
171
|
+
it 'matching files and directories get ignored in all cookbooks' do
|
172
|
+
knife('list --local -Rfp /').should_succeed <<EOM
|
173
|
+
/cookbooks/
|
174
|
+
/cookbooks/cookbook1/
|
175
|
+
/cookbooks/cookbook1/y.json
|
176
|
+
/cookbooks/cookbook2/
|
177
|
+
/cookbooks/cookbook2/y.json
|
178
|
+
EOM
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
when_the_repository "has multiple cookbook paths" do
|
184
|
+
before :each do
|
185
|
+
Chef::Config.cookbook_path = [
|
186
|
+
File.join(Chef::Config.chef_repo_path, 'cookbooks1'),
|
187
|
+
File.join(Chef::Config.chef_repo_path, 'cookbooks2')
|
188
|
+
]
|
189
|
+
end
|
190
|
+
|
191
|
+
file 'cookbooks1/mycookbook/metadata.rb', ''
|
192
|
+
file 'cookbooks1/mycookbook/x.json', {}
|
193
|
+
file 'cookbooks2/yourcookbook/metadata.rb', ''
|
194
|
+
file 'cookbooks2/yourcookbook/x.json', ''
|
195
|
+
|
196
|
+
context "and multiple chefignores" do
|
197
|
+
file 'cookbooks1/chefignore', "metadata.rb\n"
|
198
|
+
file 'cookbooks2/chefignore', "x.json\n"
|
199
|
+
it "chefignores apply only to the directories they are in" do
|
200
|
+
knife('list --local -Rfp /').should_succeed <<EOM
|
201
|
+
/cookbooks/
|
202
|
+
/cookbooks/mycookbook/
|
203
|
+
/cookbooks/mycookbook/x.json
|
204
|
+
/cookbooks/yourcookbook/
|
205
|
+
/cookbooks/yourcookbook/metadata.rb
|
206
|
+
EOM
|
207
|
+
end
|
208
|
+
|
209
|
+
context "and conflicting cookbooks" do
|
210
|
+
file 'cookbooks1/yourcookbook/metadata.rb', ''
|
211
|
+
file 'cookbooks1/yourcookbook/x.json', ''
|
212
|
+
file 'cookbooks1/yourcookbook/onlyincookbooks1.rb', ''
|
213
|
+
file 'cookbooks2/yourcookbook/onlyincookbooks2.rb', ''
|
214
|
+
|
215
|
+
it "chefignores apply only to the winning cookbook" do
|
216
|
+
knife('list --local -Rfp /').should_succeed(<<EOM, :stderr => "WARN: Child with name 'yourcookbook' found in multiple directories: #{Chef::Config.chef_repo_path}/cookbooks1/yourcookbook and #{Chef::Config.chef_repo_path}/cookbooks2/yourcookbook\n")
|
217
|
+
/cookbooks/
|
218
|
+
/cookbooks/mycookbook/
|
219
|
+
/cookbooks/mycookbook/x.json
|
220
|
+
/cookbooks/yourcookbook/
|
221
|
+
/cookbooks/yourcookbook/onlyincookbooks1.rb
|
222
|
+
/cookbooks/yourcookbook/x.json
|
223
|
+
EOM
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
when_the_repository 'has a cookbook named chefignore' do
|
230
|
+
file 'cookbooks/chefignore/metadata.rb', {}
|
231
|
+
it 'knife list -Rfp /cookbooks shows it' do
|
232
|
+
knife('list --local -Rfp /cookbooks').should_succeed <<EOM
|
233
|
+
/cookbooks/chefignore/
|
234
|
+
/cookbooks/chefignore/metadata.rb
|
235
|
+
EOM
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
when_the_repository 'has multiple cookbook paths, one with a chefignore file and the other with a cookbook named chefignore' do
|
240
|
+
file 'cookbooks1/chefignore', ''
|
241
|
+
file 'cookbooks1/blah/metadata.rb', ''
|
242
|
+
file 'cookbooks2/chefignore/metadata.rb', ''
|
243
|
+
before :each do
|
244
|
+
Chef::Config.cookbook_path = [
|
245
|
+
File.join(Chef::Config.chef_repo_path, 'cookbooks1'),
|
246
|
+
File.join(Chef::Config.chef_repo_path, 'cookbooks2')
|
247
|
+
]
|
248
|
+
end
|
249
|
+
it 'knife list -Rfp /cookbooks shows the chefignore cookbook' do
|
250
|
+
knife('list --local -Rfp /cookbooks').should_succeed <<EOM
|
251
|
+
/cookbooks/blah/
|
252
|
+
/cookbooks/blah/metadata.rb
|
253
|
+
/cookbooks/chefignore/
|
254
|
+
/cookbooks/chefignore/metadata.rb
|
255
|
+
EOM
|
256
|
+
end
|
257
|
+
end
|
258
|
+
end
|
@@ -0,0 +1,151 @@
|
|
1
|
+
require 'support/integration_helper'
|
2
|
+
require 'chef/knife/diff_essentials'
|
3
|
+
|
4
|
+
describe 'knife diff' do
|
5
|
+
extend IntegrationSupport
|
6
|
+
include KnifeSupport
|
7
|
+
|
8
|
+
when_the_chef_server "has one of each thing" do
|
9
|
+
client 'x', '{}'
|
10
|
+
cookbook 'x', '1.0.0', { 'metadata.rb' => 'version "1.0.0"' }
|
11
|
+
data_bag 'x', { 'y' => '{}' }
|
12
|
+
environment 'x', '{}'
|
13
|
+
node 'x', '{}'
|
14
|
+
role 'x', '{}'
|
15
|
+
user 'x', '{}'
|
16
|
+
|
17
|
+
when_the_repository 'has only top-level directories' do
|
18
|
+
directory 'clients'
|
19
|
+
directory 'cookbooks'
|
20
|
+
directory 'data_bags'
|
21
|
+
directory 'environments'
|
22
|
+
directory 'nodes'
|
23
|
+
directory 'roles'
|
24
|
+
directory 'users'
|
25
|
+
|
26
|
+
it 'knife diff reports everything as deleted' do
|
27
|
+
knife('diff --name-status /').should_succeed <<EOM
|
28
|
+
D\t/cookbooks/x
|
29
|
+
D\t/data_bags/x
|
30
|
+
D\t/environments/_default.json
|
31
|
+
D\t/environments/x.json
|
32
|
+
D\t/roles/x.json
|
33
|
+
EOM
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
when_the_repository 'has an identical copy of each thing' do
|
38
|
+
file 'clients/x.json', <<EOM
|
39
|
+
{}
|
40
|
+
EOM
|
41
|
+
file 'cookbooks/x/metadata.rb', 'version "1.0.0"'
|
42
|
+
file 'data_bags/x/y.json', <<EOM
|
43
|
+
{
|
44
|
+
"id": "y"
|
45
|
+
}
|
46
|
+
EOM
|
47
|
+
file 'environments/_default.json', <<EOM
|
48
|
+
{
|
49
|
+
"name": "_default",
|
50
|
+
"description": "The default Chef environment",
|
51
|
+
"cookbook_versions": {
|
52
|
+
},
|
53
|
+
"json_class": "Chef::Environment",
|
54
|
+
"chef_type": "environment",
|
55
|
+
"default_attributes": {
|
56
|
+
},
|
57
|
+
"override_attributes": {
|
58
|
+
}
|
59
|
+
}
|
60
|
+
EOM
|
61
|
+
file 'environments/x.json', <<EOM
|
62
|
+
{
|
63
|
+
"chef_type": "environment",
|
64
|
+
"cookbook_versions": {
|
65
|
+
},
|
66
|
+
"default_attributes": {
|
67
|
+
},
|
68
|
+
"description": "",
|
69
|
+
"json_class": "Chef::Environment",
|
70
|
+
"name": "x",
|
71
|
+
"override_attributes": {
|
72
|
+
}
|
73
|
+
}
|
74
|
+
EOM
|
75
|
+
file 'nodes/x.json', <<EOM
|
76
|
+
{}
|
77
|
+
EOM
|
78
|
+
file 'roles/x.json', <<EOM
|
79
|
+
{
|
80
|
+
"chef_type": "role",
|
81
|
+
"default_attributes": {
|
82
|
+
},
|
83
|
+
"description": "",
|
84
|
+
"env_run_lists": {
|
85
|
+
},
|
86
|
+
"json_class": "Chef::Role",
|
87
|
+
"name": "x",
|
88
|
+
"override_attributes": {
|
89
|
+
},
|
90
|
+
"run_list": [
|
91
|
+
|
92
|
+
]
|
93
|
+
}
|
94
|
+
EOM
|
95
|
+
file 'users/x.json', <<EOM
|
96
|
+
{}
|
97
|
+
EOM
|
98
|
+
|
99
|
+
it 'knife diff reports no differences' do
|
100
|
+
knife('diff /').should_succeed :stdout => ''
|
101
|
+
end
|
102
|
+
|
103
|
+
context 'except the role file' do
|
104
|
+
file 'roles/x.json', <<EOM
|
105
|
+
{
|
106
|
+
"foo": "bar"
|
107
|
+
}
|
108
|
+
EOM
|
109
|
+
it 'knife diff reports the role as different' do
|
110
|
+
knife('diff --name-status /').should_succeed <<EOM
|
111
|
+
M\t/roles/x.json
|
112
|
+
EOM
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
context 'as well as one extra copy of each thing' do
|
117
|
+
file 'clients/y.json', {}
|
118
|
+
file 'cookbooks/x/blah.rb', ''
|
119
|
+
file 'cookbooks/y/metadata.rb', 'version "1.0.0"'
|
120
|
+
file 'data_bags/x/z.json', {}
|
121
|
+
file 'data_bags/y/zz.json', {}
|
122
|
+
file 'environments/y.json', {}
|
123
|
+
file 'nodes/y.json', {}
|
124
|
+
file 'roles/y.json', {}
|
125
|
+
file 'users/y.json', {}
|
126
|
+
|
127
|
+
it 'knife diff reports the new files as added' do
|
128
|
+
knife('diff --name-status /').should_succeed <<EOM
|
129
|
+
A\t/cookbooks/x/blah.rb
|
130
|
+
A\t/cookbooks/y
|
131
|
+
A\t/data_bags/x/z.json
|
132
|
+
A\t/data_bags/y
|
133
|
+
A\t/environments/y.json
|
134
|
+
A\t/roles/y.json
|
135
|
+
EOM
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
when_the_repository 'is empty' do
|
141
|
+
it 'knife diff reports everything as deleted' do
|
142
|
+
knife('diff --name-status /').should_succeed <<EOM
|
143
|
+
D\t/cookbooks
|
144
|
+
D\t/data_bags
|
145
|
+
D\t/environments
|
146
|
+
D\t/roles
|
147
|
+
EOM
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
@@ -0,0 +1,403 @@
|
|
1
|
+
require 'support/integration_helper'
|
2
|
+
require 'chef/knife/download_essentials'
|
3
|
+
require 'chef/knife/diff_essentials'
|
4
|
+
|
5
|
+
describe 'knife download' do
|
6
|
+
extend IntegrationSupport
|
7
|
+
include KnifeSupport
|
8
|
+
|
9
|
+
when_the_chef_server "has one of each thing" do
|
10
|
+
client 'x', '{}'
|
11
|
+
cookbook 'x', '1.0.0', { 'metadata.rb' => 'version "1.0.0"' }
|
12
|
+
data_bag 'x', { 'y' => '{}' }
|
13
|
+
environment 'x', '{}'
|
14
|
+
node 'x', '{}'
|
15
|
+
role 'x', '{}'
|
16
|
+
user 'x', '{}'
|
17
|
+
|
18
|
+
when_the_repository 'has only top-level directories' do
|
19
|
+
directory 'clients'
|
20
|
+
directory 'cookbooks'
|
21
|
+
directory 'data_bags'
|
22
|
+
directory 'environments'
|
23
|
+
directory 'nodes'
|
24
|
+
directory 'roles'
|
25
|
+
directory 'users'
|
26
|
+
|
27
|
+
it 'knife download downloads everything' do
|
28
|
+
knife('download /').should_succeed <<EOM
|
29
|
+
Created /cookbooks/x
|
30
|
+
Created /cookbooks/x/metadata.rb
|
31
|
+
Created /data_bags/x
|
32
|
+
Created /data_bags/x/y.json
|
33
|
+
Created /environments/_default.json
|
34
|
+
Created /environments/x.json
|
35
|
+
Created /roles/x.json
|
36
|
+
EOM
|
37
|
+
knife('diff --name-status /').should_succeed ''
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
when_the_repository 'has an identical copy of each thing' do
|
42
|
+
file 'clients/x.json', <<EOM
|
43
|
+
{}
|
44
|
+
EOM
|
45
|
+
file 'cookbooks/x/metadata.rb', 'version "1.0.0"'
|
46
|
+
file 'data_bags/x/y.json', <<EOM
|
47
|
+
{
|
48
|
+
"id": "y"
|
49
|
+
}
|
50
|
+
EOM
|
51
|
+
file 'environments/_default.json', <<EOM
|
52
|
+
{
|
53
|
+
"name": "_default",
|
54
|
+
"description": "The default Chef environment",
|
55
|
+
"cookbook_versions": {
|
56
|
+
},
|
57
|
+
"json_class": "Chef::Environment",
|
58
|
+
"chef_type": "environment",
|
59
|
+
"default_attributes": {
|
60
|
+
},
|
61
|
+
"override_attributes": {
|
62
|
+
}
|
63
|
+
}
|
64
|
+
EOM
|
65
|
+
file 'environments/x.json', <<EOM
|
66
|
+
{
|
67
|
+
"chef_type": "environment",
|
68
|
+
"cookbook_versions": {
|
69
|
+
},
|
70
|
+
"default_attributes": {
|
71
|
+
},
|
72
|
+
"description": "",
|
73
|
+
"json_class": "Chef::Environment",
|
74
|
+
"name": "x",
|
75
|
+
"override_attributes": {
|
76
|
+
}
|
77
|
+
}
|
78
|
+
EOM
|
79
|
+
file 'nodes/x.json', <<EOM
|
80
|
+
{}
|
81
|
+
EOM
|
82
|
+
file 'roles/x.json', <<EOM
|
83
|
+
{
|
84
|
+
"chef_type": "role",
|
85
|
+
"default_attributes": {
|
86
|
+
},
|
87
|
+
"description": "",
|
88
|
+
"env_run_lists": {
|
89
|
+
},
|
90
|
+
"json_class": "Chef::Role",
|
91
|
+
"name": "x",
|
92
|
+
"override_attributes": {
|
93
|
+
},
|
94
|
+
"run_list": [
|
95
|
+
|
96
|
+
]
|
97
|
+
}
|
98
|
+
EOM
|
99
|
+
file 'users/x.json', <<EOM
|
100
|
+
{}
|
101
|
+
EOM
|
102
|
+
|
103
|
+
it 'knife download makes no changes' do
|
104
|
+
knife('download /').should_succeed ''
|
105
|
+
knife('diff --name-status /').should_succeed ''
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'knife download --purge makes no changes' do
|
109
|
+
knife('download --purge /').should_succeed ''
|
110
|
+
knife('diff --name-status /').should_succeed ''
|
111
|
+
end
|
112
|
+
|
113
|
+
context 'except the role file' do
|
114
|
+
file 'roles/x.json', <<EOM
|
115
|
+
{
|
116
|
+
"chef_type": "role",
|
117
|
+
"default_attributes": {
|
118
|
+
},
|
119
|
+
"description": "blarghle",
|
120
|
+
"env_run_lists": {
|
121
|
+
},
|
122
|
+
"json_class": "Chef::Role",
|
123
|
+
"name": "x",
|
124
|
+
"override_attributes": {
|
125
|
+
},
|
126
|
+
"run_list": [
|
127
|
+
|
128
|
+
]
|
129
|
+
}
|
130
|
+
EOM
|
131
|
+
it 'knife download changes the role' do
|
132
|
+
knife('download /').should_succeed "Updated /roles/x.json\n"
|
133
|
+
knife('diff --name-status /').should_succeed ''
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
context 'as well as one extra copy of each thing' do
|
138
|
+
file 'clients/y.json', { 'name' => 'y' }
|
139
|
+
file 'cookbooks/x/blah.rb', ''
|
140
|
+
file 'cookbooks/y/metadata.rb', 'version "1.0.0"'
|
141
|
+
file 'data_bags/x/z.json', <<EOM
|
142
|
+
{
|
143
|
+
"id": "z"
|
144
|
+
}
|
145
|
+
EOM
|
146
|
+
file 'data_bags/y/zz.json', <<EOM
|
147
|
+
{
|
148
|
+
"id": "zz"
|
149
|
+
}
|
150
|
+
EOM
|
151
|
+
file 'environments/y.json', <<EOM
|
152
|
+
{
|
153
|
+
"chef_type": "environment",
|
154
|
+
"cookbook_versions": {
|
155
|
+
},
|
156
|
+
"default_attributes": {
|
157
|
+
},
|
158
|
+
"description": "",
|
159
|
+
"json_class": "Chef::Environment",
|
160
|
+
"name": "y",
|
161
|
+
"override_attributes": {
|
162
|
+
}
|
163
|
+
}
|
164
|
+
EOM
|
165
|
+
file 'nodes/y.json', { 'name' => 'y' }
|
166
|
+
file 'roles/y.json', <<EOM
|
167
|
+
{
|
168
|
+
"chef_type": "role",
|
169
|
+
"default_attributes": {
|
170
|
+
},
|
171
|
+
"description": "",
|
172
|
+
"env_run_lists": {
|
173
|
+
},
|
174
|
+
"json_class": "Chef::Role",
|
175
|
+
"name": "y",
|
176
|
+
"override_attributes": {
|
177
|
+
},
|
178
|
+
"run_list": [
|
179
|
+
|
180
|
+
]
|
181
|
+
}
|
182
|
+
EOM
|
183
|
+
file 'users/y.json', { 'name' => 'y' }
|
184
|
+
|
185
|
+
it 'knife download does nothing' do
|
186
|
+
knife('download /').should_succeed ''
|
187
|
+
knife('diff --name-status /').should_succeed <<EOM
|
188
|
+
A\t/cookbooks/x/blah.rb
|
189
|
+
A\t/cookbooks/y
|
190
|
+
A\t/data_bags/x/z.json
|
191
|
+
A\t/data_bags/y
|
192
|
+
A\t/environments/y.json
|
193
|
+
A\t/roles/y.json
|
194
|
+
EOM
|
195
|
+
end
|
196
|
+
|
197
|
+
it 'knife download --purge deletes the extra files' do
|
198
|
+
knife('download --purge /').should_succeed <<EOM
|
199
|
+
Deleted extra entry /cookbooks/x/blah.rb (purge is on)
|
200
|
+
Deleted extra entry /cookbooks/y (purge is on)
|
201
|
+
Deleted extra entry /data_bags/x/z.json (purge is on)
|
202
|
+
Deleted extra entry /data_bags/y (purge is on)
|
203
|
+
Deleted extra entry /environments/y.json (purge is on)
|
204
|
+
Deleted extra entry /roles/y.json (purge is on)
|
205
|
+
EOM
|
206
|
+
knife('diff --name-status /').should_succeed ''
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
when_the_repository 'is empty' do
|
212
|
+
it 'knife download creates the extra files' do
|
213
|
+
knife('download /').should_succeed <<EOM
|
214
|
+
Created /cookbooks
|
215
|
+
Created /cookbooks/x
|
216
|
+
Created /cookbooks/x/metadata.rb
|
217
|
+
Created /data_bags
|
218
|
+
Created /data_bags/x
|
219
|
+
Created /data_bags/x/y.json
|
220
|
+
Created /environments
|
221
|
+
Created /environments/_default.json
|
222
|
+
Created /environments/x.json
|
223
|
+
Created /roles
|
224
|
+
Created /roles/x.json
|
225
|
+
EOM
|
226
|
+
knife('diff --name-status /').should_succeed ''
|
227
|
+
end
|
228
|
+
|
229
|
+
context 'when current directory is top level' do
|
230
|
+
cwd '.'
|
231
|
+
it 'knife download with no parameters reports an error' do
|
232
|
+
knife('download').should_fail "FATAL: Must specify at least one argument. If you want to download everything in this directory, type \"knife download .\"\n", :stdout => /USAGE/
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
# Test download of an item when the other end doesn't even have the container
|
239
|
+
when_the_repository 'is empty' do
|
240
|
+
when_the_chef_server 'has two data bag items' do
|
241
|
+
data_bag 'x', { 'y' => {}, 'z' => {} }
|
242
|
+
|
243
|
+
it 'knife download of one data bag item itself succeeds' do
|
244
|
+
knife('download /data_bags/x/y.json').should_succeed <<EOM
|
245
|
+
Created /data_bags
|
246
|
+
Created /data_bags/x
|
247
|
+
Created /data_bags/x/y.json
|
248
|
+
EOM
|
249
|
+
knife('diff --name-status /data_bags').should_succeed <<EOM
|
250
|
+
D\t/data_bags/x/z.json
|
251
|
+
EOM
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
when_the_repository 'has three data bag items' do
|
257
|
+
file 'data_bags/x/deleted.json', <<EOM
|
258
|
+
{
|
259
|
+
"id": "deleted"
|
260
|
+
}
|
261
|
+
EOM
|
262
|
+
file 'data_bags/x/modified.json', <<EOM
|
263
|
+
{
|
264
|
+
"id": "modified"
|
265
|
+
}
|
266
|
+
EOM
|
267
|
+
file 'data_bags/x/unmodified.json', <<EOM
|
268
|
+
{
|
269
|
+
"id": "unmodified"
|
270
|
+
}
|
271
|
+
EOM
|
272
|
+
|
273
|
+
when_the_chef_server 'has a modified, unmodified, added and deleted data bag item' do
|
274
|
+
data_bag 'x', {
|
275
|
+
'added' => {},
|
276
|
+
'modified' => { 'foo' => 'bar' },
|
277
|
+
'unmodified' => {}
|
278
|
+
}
|
279
|
+
|
280
|
+
it 'knife download of the modified file succeeds' do
|
281
|
+
knife('download /data_bags/x/modified.json').should_succeed <<EOM
|
282
|
+
Updated /data_bags/x/modified.json
|
283
|
+
EOM
|
284
|
+
knife('diff --name-status /data_bags').should_succeed <<EOM
|
285
|
+
D\t/data_bags/x/added.json
|
286
|
+
A\t/data_bags/x/deleted.json
|
287
|
+
EOM
|
288
|
+
end
|
289
|
+
it 'knife download of the unmodified file does nothing' do
|
290
|
+
knife('download /data_bags/x/unmodified.json').should_succeed ''
|
291
|
+
knife('diff --name-status /data_bags').should_succeed <<EOM
|
292
|
+
D\t/data_bags/x/added.json
|
293
|
+
M\t/data_bags/x/modified.json
|
294
|
+
A\t/data_bags/x/deleted.json
|
295
|
+
EOM
|
296
|
+
end
|
297
|
+
it 'knife download of the added file succeeds' do
|
298
|
+
knife('download /data_bags/x/added.json').should_succeed <<EOM
|
299
|
+
Created /data_bags/x/added.json
|
300
|
+
EOM
|
301
|
+
knife('diff --name-status /data_bags').should_succeed <<EOM
|
302
|
+
M\t/data_bags/x/modified.json
|
303
|
+
A\t/data_bags/x/deleted.json
|
304
|
+
EOM
|
305
|
+
end
|
306
|
+
it 'knife download of the deleted file does nothing' do
|
307
|
+
knife('download /data_bags/x/deleted.json').should_succeed ''
|
308
|
+
knife('diff --name-status /data_bags').should_succeed <<EOM
|
309
|
+
D\t/data_bags/x/added.json
|
310
|
+
M\t/data_bags/x/modified.json
|
311
|
+
A\t/data_bags/x/deleted.json
|
312
|
+
EOM
|
313
|
+
end
|
314
|
+
it 'knife download --purge of the deleted file deletes it' do
|
315
|
+
knife('download --purge /data_bags/x/deleted.json').should_succeed <<EOM
|
316
|
+
Deleted extra entry /data_bags/x/deleted.json (purge is on)
|
317
|
+
EOM
|
318
|
+
knife('diff --name-status /data_bags').should_succeed <<EOM
|
319
|
+
D\t/data_bags/x/added.json
|
320
|
+
M\t/data_bags/x/modified.json
|
321
|
+
EOM
|
322
|
+
end
|
323
|
+
it 'knife download of the entire data bag downloads everything' do
|
324
|
+
knife('download /data_bags/x').should_succeed <<EOM
|
325
|
+
Created /data_bags/x/added.json
|
326
|
+
Updated /data_bags/x/modified.json
|
327
|
+
EOM
|
328
|
+
knife('diff --name-status /data_bags').should_succeed <<EOM
|
329
|
+
A\t/data_bags/x/deleted.json
|
330
|
+
EOM
|
331
|
+
end
|
332
|
+
it 'knife download --purge of the entire data bag downloads everything' do
|
333
|
+
knife('download --purge /data_bags/x').should_succeed <<EOM
|
334
|
+
Created /data_bags/x/added.json
|
335
|
+
Updated /data_bags/x/modified.json
|
336
|
+
Deleted extra entry /data_bags/x/deleted.json (purge is on)
|
337
|
+
EOM
|
338
|
+
knife('diff --name-status /data_bags').should_succeed ''
|
339
|
+
end
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
when_the_repository 'has a cookbook' do
|
344
|
+
file 'cookbooks/x/metadata.rb', 'version "1.0.0"'
|
345
|
+
file 'cookbooks/x/z.rb', ''
|
346
|
+
|
347
|
+
when_the_chef_server 'has a modified, added and deleted file for the cookbook' do
|
348
|
+
cookbook 'x', '1.0.0', { 'metadata.rb' => 'version "1.0.0"', 'y.rb' => 'hi' }
|
349
|
+
|
350
|
+
it 'knife download of a modified file succeeds' do
|
351
|
+
knife('download /cookbooks/x/metadata.rb').should_succeed "Updated /cookbooks/x/metadata.rb\n"
|
352
|
+
knife('diff --name-status /cookbooks').should_succeed <<EOM
|
353
|
+
D\t/cookbooks/x/y.rb
|
354
|
+
A\t/cookbooks/x/z.rb
|
355
|
+
EOM
|
356
|
+
end
|
357
|
+
it 'knife download of a deleted file does nothing' do
|
358
|
+
knife('download /cookbooks/x/z.rb').should_succeed ''
|
359
|
+
knife('diff --name-status /cookbooks').should_succeed <<EOM
|
360
|
+
M\t/cookbooks/x/metadata.rb
|
361
|
+
D\t/cookbooks/x/y.rb
|
362
|
+
A\t/cookbooks/x/z.rb
|
363
|
+
EOM
|
364
|
+
end
|
365
|
+
it 'knife download --purge of a deleted file succeeds' do
|
366
|
+
knife('download --purge /cookbooks/x/z.rb').should_succeed "Deleted extra entry /cookbooks/x/z.rb (purge is on)\n"
|
367
|
+
knife('diff --name-status /cookbooks').should_succeed <<EOM
|
368
|
+
M\t/cookbooks/x/metadata.rb
|
369
|
+
D\t/cookbooks/x/y.rb
|
370
|
+
EOM
|
371
|
+
end
|
372
|
+
it 'knife download of an added file succeeds' do
|
373
|
+
knife('download /cookbooks/x/y.rb').should_succeed "Created /cookbooks/x/y.rb\n"
|
374
|
+
knife('diff --name-status /cookbooks').should_succeed <<EOM
|
375
|
+
M\t/cookbooks/x/metadata.rb
|
376
|
+
A\t/cookbooks/x/z.rb
|
377
|
+
EOM
|
378
|
+
end
|
379
|
+
it 'knife download of the cookbook itself succeeds' do
|
380
|
+
knife('download /cookbooks/x').should_succeed <<EOM
|
381
|
+
Updated /cookbooks/x/metadata.rb
|
382
|
+
Created /cookbooks/x/y.rb
|
383
|
+
EOM
|
384
|
+
knife('diff --name-status /cookbooks').should_succeed <<EOM
|
385
|
+
A\t/cookbooks/x/z.rb
|
386
|
+
EOM
|
387
|
+
end
|
388
|
+
it 'knife download --purge of the cookbook itself succeeds' do
|
389
|
+
knife('download --purge /cookbooks/x').should_succeed <<EOM
|
390
|
+
Updated /cookbooks/x/metadata.rb
|
391
|
+
Created /cookbooks/x/y.rb
|
392
|
+
Deleted extra entry /cookbooks/x/z.rb (purge is on)
|
393
|
+
EOM
|
394
|
+
knife('diff --name-status /cookbooks').should_succeed ''
|
395
|
+
end
|
396
|
+
end
|
397
|
+
end
|
398
|
+
|
399
|
+
# download from a cwd
|
400
|
+
# download with *'s
|
401
|
+
# download with JSON that isn't *really* modified
|
402
|
+
# Multiple cookbook versions!!!
|
403
|
+
end
|