knife-tar 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,276 @@
1
+
2
+ require 'open-uri'
3
+ require 'chef/mixin/command'
4
+ require 'tmp_directory'
5
+
6
+ #A class for handling a tar file that contains chef components.
7
+
8
+ class Chef
9
+ class TarFile
10
+
11
+ #The named conventions for chef components
12
+ COOKBOOKS_PATH = "cookbooks"
13
+ ROLES_PATH = "roles"
14
+ ENVIRONMENTS_PATH = "environments"
15
+ DATA_BAGS_PATH = "data_bags"
16
+ API_CLIENTS_PATH = "api_clients"
17
+ WEB_USERS_PATH = "web_users"
18
+ NODES_PATH = "nodes"
19
+
20
+ #A list of valid chef file extensions
21
+ CHEF_FILE_EXTENSIONS = [".js", ".json", ".rb"]
22
+
23
+ def initialize tarPath, create=false
24
+
25
+ if tarPath==nil
26
+ raise ArgumentError, "A tar file path must be given"
27
+ end
28
+
29
+ @create_tar = create
30
+
31
+ unless create
32
+ @temp_directory = TmpDirectory.new.path
33
+
34
+ #Assume for now that the components live directly inside the tar file
35
+ @tar_contents_path = @temp_directory
36
+
37
+ localTarFile = File.join(@temp_directory, 'cookbooks.tgz')
38
+
39
+ #Move/Download tar file to tmp directory
40
+ File.open(localTarFile, 'wb') do |f|
41
+ open(tarPath) do |r|
42
+ f.write(r.read)
43
+ end
44
+ end
45
+
46
+ #Untar file
47
+ Chef::Mixin::Command.run_command(:command => "tar zxfC #{localTarFile} #{@temp_directory}")
48
+
49
+ #Verify tar file structure and update tar_contents_path if necessary
50
+
51
+ dirList = get_directories_names @tar_contents_path
52
+
53
+ if !is_tar_valid? dirList
54
+ #The tar does not contain any immediate chef component directories, check to see if there is a top-level project folder
55
+ #that contains any chef component directories
56
+
57
+ if dirList.size!=1 or !is_tar_valid? get_directories_names(File.join(@tar_contents_path, dirList.first))
58
+ raise InvalidStructureError, "The tar file has an invalid structure"
59
+ end
60
+
61
+ #The tar file is valid but contains a top-level project folder so update the @tar_contents_path
62
+ @tar_contents_path = File.join(@tar_contents_path, dirList.first)
63
+ end
64
+
65
+ #Remove tar file
66
+ FileUtils.rm_f localTarFile
67
+
68
+ else
69
+
70
+ # Verify that the tarPath doesn't already exist
71
+ if File.exists? tarPath
72
+ raise ArgumentError, "We cannot create a tar file at path : #{tarPath} because it already exists"
73
+ end
74
+
75
+ @temp_directory = TmpDirectory.new("chef-server").path
76
+
77
+ #We will create the tar file such that their is no single root directory inside the tar file
78
+ @tar_contents_path = @temp_directory
79
+
80
+ FileUtils.mkdir_p @temp_directory
81
+
82
+ @create_tar_path = File.absolute_path tarPath
83
+
84
+ # We are setting up a directory to become a Chef TarFile so create the resource directories
85
+ FileUtils.mkdir_p File.join @tar_contents_path, COOKBOOKS_PATH
86
+ FileUtils.mkdir_p File.join @tar_contents_path, ROLES_PATH
87
+ FileUtils.mkdir_p File.join @tar_contents_path, ENVIRONMENTS_PATH
88
+ FileUtils.mkdir_p File.join @tar_contents_path, DATA_BAGS_PATH
89
+ FileUtils.mkdir_p File.join @tar_contents_path, API_CLIENTS_PATH
90
+ FileUtils.mkdir_p File.join @tar_contents_path, WEB_USERS_PATH
91
+ FileUtils.mkdir_p File.join @tar_contents_path, NODES_PATH
92
+
93
+ end
94
+
95
+ end
96
+
97
+ #Returns the absolute path to the cookbooks directory
98
+ def cookbooks_path
99
+ verify_path COOKBOOKS_PATH
100
+ File.join @tar_contents_path, COOKBOOKS_PATH
101
+ end
102
+
103
+ #Returns list of absolute paths of the cookbooks
104
+ def cookbooks
105
+ get_directories_absolute_paths cookbooks_path
106
+ end
107
+
108
+ #Returns the absolute path to the roles directory
109
+ def roles_path
110
+ verify_path ROLES_PATH
111
+ File.join @tar_contents_path, ROLES_PATH
112
+ end
113
+
114
+ #Returns a list of absolute paths to the roles json files
115
+ def roles
116
+ get_chef_files_absolute_paths roles_path
117
+ end
118
+
119
+ #Returns the absolute path to the environments directory
120
+ def environments_path
121
+ verify_path ENVIRONMENTS_PATH
122
+ File.join @tar_contents_path, ENVIRONMENTS_PATH
123
+ end
124
+
125
+ #Returns a list of absolute paths to the environemnts json files
126
+ def environments
127
+ get_chef_files_absolute_paths environments_path
128
+ end
129
+
130
+ #Returns the absolute path to the data_bags directory
131
+ def data_bags_path
132
+ verify_path DATA_BAGS_PATH
133
+ File.join @tar_contents_path, DATA_BAGS_PATH
134
+ end
135
+
136
+ #Returns a list of absolute paths to the data_bags json files
137
+ def data_bags
138
+
139
+ #Data bags follow a different structure then the other components, their structure is
140
+ #|- data_bags
141
+ #\ \- data_bag_1
142
+ #| | |- values_1.json
143
+ #| ...
144
+
145
+ dir_list = get_directories_absolute_paths(data_bags_path)
146
+
147
+ data_bags_absolute_paths = Array.new
148
+
149
+ dir_list.each do |dir_path|
150
+ data_bags_absolute_paths = data_bags_absolute_paths | get_chef_files_absolute_paths(dir_path)
151
+ end
152
+
153
+ data_bags_absolute_paths
154
+ end
155
+
156
+ #Returns the absolute path to the api_clients directory
157
+ def api_clients_path
158
+ verify_path API_CLIENTS_PATH
159
+ File.join @tar_contents_path, API_CLIENTS_PATH
160
+ end
161
+
162
+ #Returns a list of absolute paths to the api_clients json files
163
+ def api_clients
164
+ get_chef_files_absolute_paths api_clients_path
165
+ end
166
+
167
+ #Returns the absolute path of the nodes directory
168
+ def nodes_path
169
+ verify_path NODES_PATH
170
+ File.join @tar_contents_path, NODES_PATH
171
+ end
172
+
173
+ #Returns a list of absolute paths to the nodes json files
174
+ def nodes
175
+ get_chef_files_absolute_paths nodes_path
176
+ end
177
+
178
+ #Returns the absolute path of the web_users directory
179
+ def web_users_path
180
+ verify_path WEB_USERS_PATH
181
+ File.join @tar_contents_path, WEB_USERS_PATH
182
+ end
183
+
184
+ #Returns a list of absolute paths to the web_users json files
185
+ def web_users
186
+ get_chef_files_absolute_paths web_users_path
187
+ end
188
+
189
+ def save
190
+ if @create_tar
191
+
192
+ #Tar up the directory from the parent directory of the tar's contents (this will really be /tmp)
193
+ Chef::Mixin::Command.run_command(:cwd => File.expand_path("..",@tar_contents_path), :command => "tar zfc #{@create_tar_path} #{File.basename @tar_contents_path}")
194
+
195
+ @create_tar = false
196
+ else
197
+ raise StandardError, "The tar file is not in the correct state to be saved"
198
+ end
199
+ end
200
+
201
+ private
202
+
203
+ #Returns true if the list of directories contains at least one chef component
204
+ def is_tar_valid? dir_list
205
+
206
+ #Remove unnessary directories
207
+ dir_list.delete(".")
208
+ dir_list.delete("..")
209
+
210
+ dir_list.each do |dir|
211
+ [API_CLIENTS_PATH, COOKBOOKS_PATH, DATA_BAGS_PATH, ENVIRONMENTS_PATH, NODES_PATH, ROLES_PATH, WEB_USERS_PATH].each do |component|
212
+ if dir == component
213
+ return true
214
+ end
215
+ end
216
+ end
217
+ return false
218
+ end
219
+
220
+ #Throws an exception if the given component does not exist within the tar's contents
221
+ def verify_path component
222
+ if !File.exists? File.join @tar_contents_path, component
223
+ raise MissingChefComponentError, "The '#{component}' directory does not exist within the tar file"
224
+ end
225
+ end
226
+
227
+ #Returns a list of the base file names for all the directories at the given path
228
+ def get_directories_names path
229
+ get_directories_absolute_paths(path).map {|dir| File.basename(dir) }
230
+ end
231
+
232
+ #Returns a list of the absolute paths of all the directories at the given path
233
+ def get_directories_absolute_paths path
234
+ dir_list = Dir["#{path}/*/"]
235
+
236
+ #Remove unnecessary directories
237
+ dir_list.delete(File.join(path, "."))
238
+ dir_list.delete(File.join(path, ".."))
239
+
240
+ dir_list
241
+ end
242
+
243
+ #Returns a list of the base file names for all files at the given path
244
+ def get_file_names path
245
+ Dir.entries(path).select { |file| !File.directory? File.join(path, file) }
246
+ end
247
+
248
+ #Returns a list of the absolute paths of all the files at the given path
249
+ def get_file_absolute_paths path
250
+ get_file_names(path).map { |file| File.join(path, file) }
251
+ end
252
+
253
+ #Returns a list of the absolute paths of all the valid chef component files at the given path
254
+ def get_chef_files_absolute_paths path
255
+ get_file_absolute_paths(path).select { |file| is_valid_chef_component_file?(file) }
256
+ end
257
+
258
+ #Returns true if the filename is a valid chef component file
259
+ def is_valid_chef_component_file? filename
260
+ extension = File.extname(filename)
261
+ CHEF_FILE_EXTENSIONS.each do |validExtension|
262
+ if extension.casecmp(validExtension) == 0
263
+ return true
264
+ end
265
+ end
266
+ return false
267
+ end
268
+
269
+ #Error when a Chef::TarFile does not have the correct structure
270
+ class InvalidStructureError < StandardError; end
271
+
272
+ #Error thrown when a chef component that is accessed cannot be found
273
+ class MissingChefComponentError < StandardError; end
274
+
275
+ end
276
+ end
@@ -0,0 +1,25 @@
1
+ require 'tmpdir'
2
+
3
+ class TmpDirectory
4
+
5
+ attr_reader :path
6
+
7
+ def initialize name="tmp"
8
+ @path = ::File.join(Dir.tmpdir, "#{name}-#{Time.now.strftime("%Y%m%d%H%M%S")}-#{Random.rand}")
9
+
10
+ FileUtils.mkdir_p @path
11
+
12
+ #Add shutdown hook to remove tar tmp directory
13
+ Kernel.at_exit do
14
+ cleanup
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ #Remove the created temp directory
21
+ def cleanup
22
+ FileUtils.rm_rf @path
23
+ end
24
+
25
+ end
metadata ADDED
@@ -0,0 +1,95 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: knife-tar
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.3.0
5
+ platform: ruby
6
+ authors:
7
+ - Bryan Baugher
8
+ - Aaron Blythe
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-01-11 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: chef
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - '>='
19
+ - !ruby/object:Gem::Version
20
+ version: 0.10.0
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - '>='
26
+ - !ruby/object:Gem::Version
27
+ version: 0.10.0
28
+ - !ruby/object:Gem::Dependency
29
+ name: rake
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ~>
33
+ - !ruby/object:Gem::Version
34
+ version: 0.9.2.2
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ~>
40
+ - !ruby/object:Gem::Version
41
+ version: 0.9.2.2
42
+ description: This is a knife plugin for Chef which can install and upload chef components
43
+ from a tar file or url
44
+ email: Bryan.Baugher@Cerner.com
45
+ executables: []
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - lib/chef/knife/client_tar_download.rb
50
+ - lib/chef/knife/client_tar_upload.rb
51
+ - lib/chef/knife/cookbook_tar_download.rb
52
+ - lib/chef/knife/cookbook_tar_upload.rb
53
+ - lib/chef/knife/data_bag_tar_download.rb
54
+ - lib/chef/knife/data_bag_tar_upload.rb
55
+ - lib/chef/knife/environment_tar_download.rb
56
+ - lib/chef/knife/environment_tar_upload.rb
57
+ - lib/chef/knife/node_tar_download.rb
58
+ - lib/chef/knife/node_tar_upload.rb
59
+ - lib/chef/knife/role_tar_download.rb
60
+ - lib/chef/knife/role_tar_upload.rb
61
+ - lib/chef/knife/tar_download_all.rb
62
+ - lib/chef/knife/tar_upload_all.rb
63
+ - lib/chef/knife/user_tar_download.rb
64
+ - lib/chef/knife/user_tar_upload.rb
65
+ - lib/chef/tar_file.rb
66
+ - lib/tmp_directory.rb
67
+ - Gemfile
68
+ - Rakefile
69
+ - README.md
70
+ homepage: http://github.com/Cerner/knife-tar
71
+ licenses:
72
+ - Apache License, Version 2.0
73
+ metadata: {}
74
+ post_install_message:
75
+ rdoc_options: []
76
+ require_paths:
77
+ - lib
78
+ required_ruby_version: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ required_rubygems_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ requirements: []
89
+ rubyforge_project:
90
+ rubygems_version: 2.0.3
91
+ signing_key:
92
+ specification_version: 4
93
+ summary: A Chef knife plugin to install/upload chef components from a tar file or
94
+ url
95
+ test_files: []