knife-tar 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +5 -0
- data/README.md +281 -0
- data/Rakefile +60 -0
- data/lib/chef/knife/client_tar_download.rb +40 -0
- data/lib/chef/knife/client_tar_upload.rb +49 -0
- data/lib/chef/knife/cookbook_tar_download.rb +49 -0
- data/lib/chef/knife/cookbook_tar_upload.rb +178 -0
- data/lib/chef/knife/data_bag_tar_download.rb +44 -0
- data/lib/chef/knife/data_bag_tar_upload.rb +53 -0
- data/lib/chef/knife/environment_tar_download.rb +44 -0
- data/lib/chef/knife/environment_tar_upload.rb +36 -0
- data/lib/chef/knife/node_tar_download.rb +40 -0
- data/lib/chef/knife/node_tar_upload.rb +37 -0
- data/lib/chef/knife/role_tar_download.rb +40 -0
- data/lib/chef/knife/role_tar_upload.rb +36 -0
- data/lib/chef/knife/tar_download_all.rb +36 -0
- data/lib/chef/knife/tar_upload_all.rb +70 -0
- data/lib/chef/knife/user_tar_download.rb +40 -0
- data/lib/chef/knife/user_tar_upload.rb +49 -0
- data/lib/chef/tar_file.rb +276 -0
- data/lib/tmp_directory.rb +25 -0
- metadata +95 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 4183e7e044edb84698f6e0a61626f3300f28f213
|
4
|
+
data.tar.gz: a922309881959011c66459e8dc94d9ea05da9594
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6a93d3e779f0dbb8a75f18a359c4757c0476fd5e5c35de7f55d49476a1e5c5e6098b90f33554adfaabad933eb2be87fbe2a1fdf751e8f838defe0b8afeffeee3
|
7
|
+
data.tar.gz: 2fb7077cd62c278439a56beae3c56d96ac97991f16191b823ee5d5b2b7f86e8b25a9fed338a70c82497b57eac65ba1ea1f768acaa82141f49d2a95c077cf35f1
|
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,281 @@
|
|
1
|
+
knife-tar
|
2
|
+
=========
|
3
|
+
|
4
|
+
Description
|
5
|
+
-----------
|
6
|
+
|
7
|
+
A knife plugin facilitating uploading chef components from a tar.gz file/url to your
|
8
|
+
chef server as well as downloading components from chef-server to tar.gz format.
|
9
|
+
|
10
|
+
Why?
|
11
|
+
----
|
12
|
+
|
13
|
+
This originally started when we were looking into the best way to 'release' our
|
14
|
+
cookbooks. Numerous sources online will tell you that the suggested way to 'release'
|
15
|
+
a cookbook is to create a tag in your source control manager and upload your cookbook
|
16
|
+
from that tag. There are even chef plugins for uploading cookbooks from git as well as
|
17
|
+
other tools like [berkshelf](http://berkshelf.com/) that allow you to download cookbooks
|
18
|
+
from github. This idea didn't really mesh well with the way we would release our artifacts
|
19
|
+
which was to push everything into an artifact repository. From there we came up with the idea of
|
20
|
+
dropping all of our cookbook's files into a tar file and push that out to our
|
21
|
+
repositories.
|
22
|
+
|
23
|
+
Being beginners at chef we often ran into the issue where we wanted to upload our cookbook
|
24
|
+
to the chef-server but we forgot to include the dependencies. From that we decided our tar
|
25
|
+
file should support multiple cookbooks so we could include cookbook dependencies. At that
|
26
|
+
point others were asking about adding support for roles or environments, that is when we
|
27
|
+
realized we could support all of the chef components and modeled the format after Opscode's
|
28
|
+
[chef-repo](https://github.com/opscode/chef-repo). From there we included the download
|
29
|
+
functionality and supported multiple versions of the same cookbook.
|
30
|
+
|
31
|
+
Installation
|
32
|
+
------------
|
33
|
+
|
34
|
+
Install the chef gem prior to installing knife-tar.
|
35
|
+
|
36
|
+
gem install knife-tar
|
37
|
+
|
38
|
+
Requirements
|
39
|
+
------------
|
40
|
+
|
41
|
+
* Chef >= 0.10.10 (Does not work with Chef 11)
|
42
|
+
* `tar` is installed and on your `$PATH`
|
43
|
+
|
44
|
+
Conventions
|
45
|
+
-----------
|
46
|
+
|
47
|
+
### Tar File Structure
|
48
|
+
|
49
|
+
The knife-tar plugin focuses to allow a tar file to be used to upload a variety of chef components. Therefore
|
50
|
+
the tar file must be created in a specific way. We tried to follow the chef-repo structure seen here
|
51
|
+
(https://github.com/opscode/chef-repo).
|
52
|
+
|
53
|
+
We assume that the tar file will look like,
|
54
|
+
|
55
|
+
\[tarName\].tar.gz
|
56
|
+
|- cookbooks
|
57
|
+
| |- \[cookbookName\] | \[cookbookName\]-\[cookbookVersion\]
|
58
|
+
|- data_bags
|
59
|
+
| |- \[dataBagName\]
|
60
|
+
| | |- \[valueName\].\[json|js|rb\]
|
61
|
+
|- environments
|
62
|
+
| |- \[environmentName\].\[json|js|rb\]
|
63
|
+
|- roles
|
64
|
+
| |- \[roleName\].\[json|js|rb\]
|
65
|
+
|- web_users
|
66
|
+
| |- \[webUserName\].\[json|js|rb\]
|
67
|
+
|- api_clients
|
68
|
+
| | - \[clientName\].\[json|js|rb\]
|
69
|
+
|- nodes
|
70
|
+
| |- \[nodeName\].\[json|js|rb\]
|
71
|
+
|
72
|
+
OR
|
73
|
+
|
74
|
+
\[tarName\].tar.gz
|
75
|
+
|- \[projectName\]
|
76
|
+
| |- cookbooks
|
77
|
+
| | |- \[cookbookName\] | \[cookbookName\]-\[cookbookVersion\]
|
78
|
+
| |- data_bags
|
79
|
+
| | |- \[dataBagName\]
|
80
|
+
| | | |- \[valueName\].\[json|js|rb\]
|
81
|
+
| |- environments
|
82
|
+
| | |- \[environmentName\].\[json|js|rb\]
|
83
|
+
| |- roles
|
84
|
+
| | |- \[roleName\].\[json|js|rb\]
|
85
|
+
| |- web_users
|
86
|
+
| | |- \[webUserName\].\[json|js|rb\]
|
87
|
+
| |- api_clients
|
88
|
+
| | | - \[clientName\].\[json|js|rb\]
|
89
|
+
| |- nodes
|
90
|
+
| | |- \[nodeName\].\[json|js|rb\]
|
91
|
+
|
92
|
+
### Chef Cookbook Names
|
93
|
+
|
94
|
+
In order to support uploading multiple versions of the same cookbook the following directory names are valid for cookbooks,
|
95
|
+
|
96
|
+
* \[cookbookName\] (i.e. java)
|
97
|
+
* \[cookbookName\]-\[cookbookVersion\] (i.e. java-1.0.2)
|
98
|
+
|
99
|
+
### Chef Component File Extensions
|
100
|
+
|
101
|
+
All chef components files (i.e. all components except cookbooks) must end in the proper extension
|
102
|
+
either '.js', '.json' or '.rb' defined by Chef.
|
103
|
+
|
104
|
+
### Additional Notes
|
105
|
+
|
106
|
+
The root directory (or \[projectName\]) in the second structure can be anything except the names of the chef components
|
107
|
+
(cookbooks, data_bags, environments, roles...)
|
108
|
+
|
109
|
+
You do not have to have all of the directories in your tar file in order to use the knife-tar plugin.
|
110
|
+
You only need the directories that have the components you want to use with knife-tar. So if you only want to use
|
111
|
+
it to upload cookbooks a valid tar file could look like,
|
112
|
+
|
113
|
+
\[tarName\].tar.gz
|
114
|
+
|- cookbooks
|
115
|
+
| |- \[cookbookName\]
|
116
|
+
|
117
|
+
OR
|
118
|
+
|
119
|
+
\[tarName\].tar.gz
|
120
|
+
|- \[projectName\]
|
121
|
+
| |- cookbooks
|
122
|
+
| | |- \[cookbookName\]
|
123
|
+
|
124
|
+
Usage
|
125
|
+
-----
|
126
|
+
|
127
|
+
In all of the below instances, 'tarPath' can be either the path
|
128
|
+
to your tar file on your local filesystem or a url.
|
129
|
+
|
130
|
+
### Uploading
|
131
|
+
|
132
|
+
#### Everything
|
133
|
+
|
134
|
+
**NOTE**: If you have api clients in your tar file this command requires that you
|
135
|
+
either be running on the chef-server or have configured 'couchdb_url' in your
|
136
|
+
knife.rb to work properly.
|
137
|
+
|
138
|
+
If you want to upload all your chef resources from your tar file you can use the
|
139
|
+
following command,
|
140
|
+
|
141
|
+
Command: 'knife tar upload tarPath (options)'
|
142
|
+
|
143
|
+
#### Cookbooks
|
144
|
+
|
145
|
+
If you want to upload only your cookbooks from your tar file you can use the
|
146
|
+
following command,
|
147
|
+
|
148
|
+
Command: 'knife cookbook tar upload tarPath (options)'
|
149
|
+
|
150
|
+
#### Roles
|
151
|
+
|
152
|
+
If you want to upload only your roles from your tar file you can use the
|
153
|
+
following command,
|
154
|
+
|
155
|
+
Command: 'knife role tar upload tarPath (options)'
|
156
|
+
|
157
|
+
#### Data Bags
|
158
|
+
|
159
|
+
If you want to upload only your data bags from your tar file you can use the
|
160
|
+
following command,
|
161
|
+
|
162
|
+
Command: 'knife data bag tar upload tarPath (options)'
|
163
|
+
|
164
|
+
#### Environments
|
165
|
+
|
166
|
+
If you want to upload only your environment from your tar file you can use the
|
167
|
+
following command,
|
168
|
+
|
169
|
+
Command: 'knife environment tar upload tarPath (options)'
|
170
|
+
|
171
|
+
#### Nodes
|
172
|
+
|
173
|
+
If you want to upload only your nodes from your tar file you can use the
|
174
|
+
following command,
|
175
|
+
|
176
|
+
Command: 'knife node tar upload tarPath (options)'
|
177
|
+
|
178
|
+
#### Web UI Users
|
179
|
+
|
180
|
+
If you want to upload only your users from your tar file you can use the
|
181
|
+
following command,
|
182
|
+
|
183
|
+
Command: 'knife user tar upload tarPath (options)'
|
184
|
+
|
185
|
+
|
186
|
+
#### API Clients
|
187
|
+
|
188
|
+
**NOTE**: This command requires that you either be running on the chef-server or
|
189
|
+
have configured 'couchdb_url' in your knife.rb to work properly.
|
190
|
+
|
191
|
+
If you want to upload only your clients from your tar file you can use the
|
192
|
+
following command,
|
193
|
+
|
194
|
+
Command: 'knife client tar upload tarPath (options)'
|
195
|
+
|
196
|
+
### Downloading
|
197
|
+
|
198
|
+
#### Everything
|
199
|
+
|
200
|
+
If you want to download all of your chef resources from chef-server to a tar
|
201
|
+
file you can use the following command,
|
202
|
+
|
203
|
+
Command: 'knife tar download tarPath (options)'
|
204
|
+
|
205
|
+
#### Cookbooks
|
206
|
+
|
207
|
+
If you want to download all your cookbooks from chef-server to a tar file you
|
208
|
+
can use the following command,
|
209
|
+
|
210
|
+
Command: 'knife cookbook tar download tarPath (options)'
|
211
|
+
|
212
|
+
#### Data Bags
|
213
|
+
|
214
|
+
If you want to download all your data bags from chef-server to a tar file you
|
215
|
+
can use the following command,
|
216
|
+
|
217
|
+
Command: 'knife data bag tar download tarPath (options)'
|
218
|
+
|
219
|
+
#### Environments
|
220
|
+
|
221
|
+
If you want to download all your environments from chef-server to a tar file you
|
222
|
+
can use the following command,
|
223
|
+
|
224
|
+
Command: 'knife environment tar download tarPath (options)'
|
225
|
+
|
226
|
+
#### Nodes
|
227
|
+
|
228
|
+
If you want to download all your nodes from chef-server to a tar file you
|
229
|
+
can use the following command,
|
230
|
+
|
231
|
+
Command: 'knife node tar download tarPath (options)'
|
232
|
+
|
233
|
+
#### Roles
|
234
|
+
|
235
|
+
If you want to download all your roles from chef-server to a tar file you
|
236
|
+
can use the following command,
|
237
|
+
|
238
|
+
Command: 'knife role tar download tarPath (options)'
|
239
|
+
|
240
|
+
#### Api Clients
|
241
|
+
|
242
|
+
If you want to download all your api clients from chef-server to a tar file you
|
243
|
+
can use the following command,
|
244
|
+
|
245
|
+
Command: 'knife client tar download tarPath (options)'
|
246
|
+
|
247
|
+
#### Web UI Users
|
248
|
+
|
249
|
+
If you want to download all your web ui users from chef-server to a tar file you
|
250
|
+
can use the following command,
|
251
|
+
|
252
|
+
Command: 'knife user tar download tarPath (options)'
|
253
|
+
|
254
|
+
Author
|
255
|
+
------
|
256
|
+
|
257
|
+
Bryan Baugher
|
258
|
+
Bryan.Baugher@Cerner.com
|
259
|
+
|
260
|
+
Contributing
|
261
|
+
------------
|
262
|
+
|
263
|
+
This project is licensed under the Apache License, Version 2.0.
|
264
|
+
|
265
|
+
When contributing to the project please add your name to the CONTRIBUTORS.txt file. Adding your name to the CONTRIBUTORS.txt file
|
266
|
+
signifies agreement to all rights and reservations provided by the License.
|
267
|
+
|
268
|
+
To contribute to the project execute a pull request through github. The pull request will be reviewed by the community and merged
|
269
|
+
by the project committers. Please attempt to conform to the test, code conventions, and code formatting standards if any
|
270
|
+
are specified by the project before submitting a pull request.
|
271
|
+
|
272
|
+
LICENSE
|
273
|
+
-------
|
274
|
+
|
275
|
+
Copyright 2014 Cerner Innovation, Inc.
|
276
|
+
|
277
|
+
Licensed under the Apache License, Version 2.0 (the 'License'); you may not use this file except in compliance with the License. You may obtain a copy of the License at
|
278
|
+
|
279
|
+
[http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0) Unless required by applicable law or agreed to in writing, software distributed
|
280
|
+
under the License is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language
|
281
|
+
governing permissions and limitations under the License.
|
data/Rakefile
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
# coding: UTF-8
|
2
|
+
|
3
|
+
task :default => [:build]
|
4
|
+
|
5
|
+
task :build do
|
6
|
+
puts "Building the gem"
|
7
|
+
runCommand "gem build knife-tar.gemspec"
|
8
|
+
end
|
9
|
+
|
10
|
+
task :release => [:build] do
|
11
|
+
deployGem
|
12
|
+
release
|
13
|
+
end
|
14
|
+
|
15
|
+
def deployGem
|
16
|
+
begin
|
17
|
+
puts "Pushing the gem to rubygems.org"
|
18
|
+
runCommand "gem push knife-tar*.gem"
|
19
|
+
ensure
|
20
|
+
system "rm -f knife-tar*.gem"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def release
|
25
|
+
|
26
|
+
#Tag the release
|
27
|
+
puts "Tagging the release"
|
28
|
+
runCommand "git tag -a #{rawVersion} -m 'Released #{rawVersion}'"
|
29
|
+
runCommand "git push origin #{rawVersion}"
|
30
|
+
|
31
|
+
# Update bump VERSION file
|
32
|
+
rawVersion = `cat VERSION`.chomp
|
33
|
+
versions = rawVersion.split "."
|
34
|
+
versions[1] = versions[1].to_i + 1
|
35
|
+
newVersion = versions.join "."
|
36
|
+
|
37
|
+
puts "Changing version from #{rawVersion} to #{newVersion}"
|
38
|
+
|
39
|
+
runCommand "echo '#{newVersion}' > VERSION"
|
40
|
+
|
41
|
+
#Commit the updated VERSION file
|
42
|
+
puts "Commiting the new VERSION file"
|
43
|
+
runCommand "git add VERSION"
|
44
|
+
runCommand "git commit -m 'Released #{rawVersions} and bumped version to #{newVersion}'"
|
45
|
+
runCommand "git push origin master"
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
def runCommand command
|
50
|
+
output = system command
|
51
|
+
unless output
|
52
|
+
# Removes changes to tracked files
|
53
|
+
system "git reset --hard"
|
54
|
+
|
55
|
+
# Removes any new un-tracked files
|
56
|
+
system "git clean -f -d"
|
57
|
+
|
58
|
+
raise "Command : #{command} failed"
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'chef/knife'
|
2
|
+
require 'chef/knife/core/object_loader'
|
3
|
+
require 'chef/json_compat'
|
4
|
+
require 'chef/api_client'
|
5
|
+
|
6
|
+
class Chef
|
7
|
+
class Knife
|
8
|
+
class ClientTarDownload < Chef::Knife
|
9
|
+
|
10
|
+
banner "knife client tar download tarPath [options]"
|
11
|
+
category "client tar"
|
12
|
+
|
13
|
+
def run
|
14
|
+
#Get Arguments
|
15
|
+
if @name_args.size != 1
|
16
|
+
ui.info("Please specify a tar path")
|
17
|
+
show_usage
|
18
|
+
exit 1
|
19
|
+
end
|
20
|
+
|
21
|
+
tar_file = Chef::TarFile.new(@name_args.first, true)
|
22
|
+
ClientTarDownload.download_clients tar_file
|
23
|
+
tarFile.save
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.download_clients(tar_file)
|
28
|
+
dir = tar_file.api_clients_path
|
29
|
+
Chef::ApiClient.list.each do |component_name, url|
|
30
|
+
Chef::Log.info("Backing up client #{component_name}")
|
31
|
+
component_obj = Chef::ApiClient.load(component_name)
|
32
|
+
File.open(File.join(dir, "#{component_name}.json"), "w") do |component_file|
|
33
|
+
component_file.print(component_obj.to_json)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'chef/knife'
|
2
|
+
require 'chef/knife/core/object_loader'
|
3
|
+
require 'chef/json_compat'
|
4
|
+
|
5
|
+
class Chef
|
6
|
+
class Knife
|
7
|
+
class ClientTarUpload < Chef::Knife
|
8
|
+
|
9
|
+
banner "knife client tar upload tarPath [options]"
|
10
|
+
category "client tar"
|
11
|
+
|
12
|
+
def run
|
13
|
+
#Get Arguments
|
14
|
+
if @name_args.size != 1
|
15
|
+
ui.info("Please specify a tar path")
|
16
|
+
show_usage
|
17
|
+
exit 1
|
18
|
+
end
|
19
|
+
|
20
|
+
tar_file = Chef::TarFile.new(@name_args.first)
|
21
|
+
ClientTarUpload.upload_clients tar_file
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.upload_clients(tar_file)
|
26
|
+
ui.confirm "This command will only work when running on chef-server or by updating the couchdb_url in your knife config to point to your couchdb instance. Are you sure you want to continue"
|
27
|
+
|
28
|
+
client_loader = Chef::Knife::Core::ObjectLoader.new(Chef::ApiClient, ui)
|
29
|
+
current_clients = Chef::ApiClient.list.keys
|
30
|
+
|
31
|
+
tar_file.api_clients.each do |api_client_path|
|
32
|
+
|
33
|
+
client = client_loader.load_from("clients", api_client_path)
|
34
|
+
|
35
|
+
# In order to 'update' a client we have to remove it first, so if the client exists destroy it
|
36
|
+
if current_clients.include? client.name
|
37
|
+
ApiClient.load(client.name).destroy
|
38
|
+
end
|
39
|
+
|
40
|
+
client.cdb_save
|
41
|
+
|
42
|
+
ui.info("Updated Client : #{client.name}")
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'chef/knife'
|
2
|
+
require 'chef/cookbook/metadata'
|
3
|
+
require 'chef/cookbook_uploader'
|
4
|
+
require 'chef/tar_file'
|
5
|
+
require 'chef/cookbook_version'
|
6
|
+
require 'chef/rest'
|
7
|
+
|
8
|
+
class Chef
|
9
|
+
class Knife
|
10
|
+
class CookbookTarDownload < Chef::Knife
|
11
|
+
|
12
|
+
banner "knife cookbook tar download tarPath (options)"
|
13
|
+
category "cookbook tar"
|
14
|
+
|
15
|
+
# This method will be executed when you run this knife command.
|
16
|
+
def run
|
17
|
+
|
18
|
+
#Get Arguments
|
19
|
+
if @name_args.size != 1
|
20
|
+
ui.info("Please specify a tarPath")
|
21
|
+
show_usage
|
22
|
+
exit 1
|
23
|
+
end
|
24
|
+
|
25
|
+
tar_file = Chef::TarFile.new(@name_args.first, true)
|
26
|
+
CookbookTarDownload.download_cookbooks tar_file
|
27
|
+
tar_file.save
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.download_cookbooks(tar_file)
|
32
|
+
#Gets the list of cookbooks and their versions
|
33
|
+
rest = Chef::REST.new(Chef::Config[:chef_server_url])
|
34
|
+
cookbook_versions = rest.get_rest('cookbooks?num_versions=all')
|
35
|
+
|
36
|
+
cookbook_versions.each do | cookbook_name, cookbook_hash |
|
37
|
+
cookbook_hash['versions'].each do | version_hash |
|
38
|
+
cookbook_download = Chef::Knife::CookbookDownload.new
|
39
|
+
cookbook_download.config[:download_directory] = tar_file.cookbooks_path
|
40
|
+
cookbook_download.name_args.push cookbook_name
|
41
|
+
cookbook_download.name_args.push version_hash["version"]
|
42
|
+
cookbook_download.run
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,178 @@
|
|
1
|
+
require 'chef/knife'
|
2
|
+
require 'chef/cookbook/metadata'
|
3
|
+
require 'chef/cookbook_uploader'
|
4
|
+
require 'chef/tar_file'
|
5
|
+
require 'tmp_directory'
|
6
|
+
|
7
|
+
class Chef
|
8
|
+
class Knife
|
9
|
+
class CookbookTarUpload < Chef::Knife
|
10
|
+
|
11
|
+
# This is the list of CookbookVersion's that are already uploaded to the chef-server
|
12
|
+
@@current_cookbooks = nil
|
13
|
+
|
14
|
+
banner "knife cookbook tar upload tarPath (options)"
|
15
|
+
category "cookbook tar"
|
16
|
+
|
17
|
+
# This method will be executed when you run this knife command.
|
18
|
+
def run
|
19
|
+
|
20
|
+
if @name_args.size != 1
|
21
|
+
ui.info("Please specify a tarPath")
|
22
|
+
show_usage
|
23
|
+
exit 1
|
24
|
+
end
|
25
|
+
|
26
|
+
tar_file = Chef::TarFile.new(@name_args.first)
|
27
|
+
CookbookTarUpload.upload_cookbooks tar_file
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.upload_cookbooks(tar_file)
|
32
|
+
# This is the list of cookbooks and their groupings, we upload all the cookbooks in a group at a time
|
33
|
+
cookbook_upload_groups = Array.new
|
34
|
+
|
35
|
+
cookbook_paths = tar_file.cookbooks
|
36
|
+
|
37
|
+
cookbook_group_index = 0
|
38
|
+
|
39
|
+
total_cookbooks = cookbook_paths.length
|
40
|
+
|
41
|
+
# Since we now allow you to upload multiple versions of the same cookbook we have to be smart about how we upload the cookbooks
|
42
|
+
# If we upload a cookbook without the proper dependency we will get errors
|
43
|
+
|
44
|
+
# So the strategy is to categorize cookbooks into groups based on their dependencies and what has been uploaded
|
45
|
+
# Then move the cookbooks to a tmp directory (renaming their directories if necessary) and upload each group in order
|
46
|
+
|
47
|
+
while !cookbook_paths.empty?
|
48
|
+
|
49
|
+
cookbook_upload_groups.push(Array.new)
|
50
|
+
|
51
|
+
# An array of current cookbook names we are uploading. This is used to ensure we dont upload the same cookbook
|
52
|
+
# (different version) in the same group
|
53
|
+
cookbookNamesToUpload = Array.new
|
54
|
+
|
55
|
+
cookbook_paths.each do |cookbook_path|
|
56
|
+
cookbookName = CookbookTarUpload.get_cookbook_name_from_path cookbook_path
|
57
|
+
|
58
|
+
# Verify we aren't uploading another version of the cookbook in this group
|
59
|
+
unless cookbookNamesToUpload.index(cookbookName)
|
60
|
+
|
61
|
+
# Check the cookbook has no dependencies or its dependencies have been uploaded
|
62
|
+
|
63
|
+
md = Chef::Cookbook::Metadata.new
|
64
|
+
md.from_file File.join(cookbook_path, "metadata.rb")
|
65
|
+
|
66
|
+
uploadable = true
|
67
|
+
md.dependencies.each do |cookbook_dependency, version_constraint|
|
68
|
+
|
69
|
+
# Verify we have uploaded the specific cookbook / version
|
70
|
+
unless CookbookTarUpload.is_dependency_uploaded? cookbook_dependency, version_constraint, cookbook_upload_groups
|
71
|
+
ui.error "Cookbook #{cookbookName} depends on cookbook '#{cookbook_dependency}' version '#{version_constraint}',"
|
72
|
+
ui.error "which is not currently being uploaded and cannot be found on the server."
|
73
|
+
uploadable = false
|
74
|
+
break
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
if uploadable
|
80
|
+
# Add the cookbook to the group
|
81
|
+
cookbook_upload_groups[cookbook_group_index].push cookbook_path
|
82
|
+
# Add the cookbook's name to our list
|
83
|
+
cookbookNamesToUpload.push(cookbookName)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# If we still have cookbooks that need to find a group but we did not add any to this group
|
89
|
+
# we have an error. This can be caused by a missing dependency or a circular dependency.
|
90
|
+
if cookbookNamesToUpload.empty?
|
91
|
+
raise "Unable to upload cookbooks"
|
92
|
+
end
|
93
|
+
|
94
|
+
# Remove the cookbooks we have added to this group
|
95
|
+
cookbook_upload_groups[cookbook_group_index].each do |cookbook_path|
|
96
|
+
cookbook_paths.delete cookbook_path
|
97
|
+
end
|
98
|
+
|
99
|
+
cookbook_group_index+=1
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
puts "#{total_cookbooks} cookbooks have been grouped into #{cookbook_upload_groups.length} groups"
|
104
|
+
puts "Uploading cookbooks ..."
|
105
|
+
|
106
|
+
# Upload all cookbooks one group at a time
|
107
|
+
cookbook_upload_groups.each do |cookbookGroup|
|
108
|
+
cookbookTmpPath = ::TmpDirectory.new("cookbooks").path
|
109
|
+
|
110
|
+
# Move cookbooks to tmp directory and rename if necessary
|
111
|
+
cookbookGroup.each do |cookbook_path|
|
112
|
+
FileUtils.cp_r cookbook_path, File.join(cookbookTmpPath, CookbookTarUpload.get_cookbook_name_from_path(cookbook_path))
|
113
|
+
end
|
114
|
+
|
115
|
+
#Upload cookbook group
|
116
|
+
cookbookUploader = Chef::Knife::CookbookUpload.new
|
117
|
+
cookbookUploader.config[:cookbook_path] = cookbookTmpPath
|
118
|
+
cookbookUploader.config[:all] = true
|
119
|
+
cookbookUploader.run
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
private
|
124
|
+
|
125
|
+
# Returns the name of the cookbook from its path which could include its version information
|
126
|
+
# (i.e. /var/chef/cookbooks/myCookbook-1.0.0 would return myCookbook)
|
127
|
+
def self.get_cookbook_name_from_path path
|
128
|
+
directory = File.basename(path)
|
129
|
+
index = directory =~ /(-[\d]+.[\d]+\.[\d]+\z|-[\d]+\.[\d]+\z)/
|
130
|
+
if index!=nil
|
131
|
+
return directory[0, index]
|
132
|
+
end
|
133
|
+
directory
|
134
|
+
end
|
135
|
+
|
136
|
+
# Given a cookbook's dependency information, and the current cookbooks that will be uploaded, determine if
|
137
|
+
# we have uploaded a valid version of that cookbook
|
138
|
+
def self.is_dependency_uploaded? cookbook_dependency, version_constraint, cookbook_upload_groups
|
139
|
+
vc = Chef::VersionConstraint.new(version_constraint)
|
140
|
+
|
141
|
+
cookbook_upload_groups.each do |cookbook_group|
|
142
|
+
cookbook_group.each do |cookbook_path|
|
143
|
+
if CookbookTarUpload.get_cookbook_name_from_path(cookbook_path)==cookbook_dependency
|
144
|
+
# Get the version of the cookbook that is already in a group
|
145
|
+
md = Chef::Cookbook::Metadata.new
|
146
|
+
md.from_file File.join(cookbook_path, "metadata.rb")
|
147
|
+
if vc.include? md.version
|
148
|
+
return true
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
# The dependency we are wanting is not part of an upload group so check if it already exists on the chef-server
|
155
|
+
if CookbookTarUpload.current_cookbooks.has_key? cookbook_dependency
|
156
|
+
CookbookTarUpload.current_cookbooks[cookbook_dependency].each do |cookbookVersions|
|
157
|
+
CookbookTarUpload.current_cookbooks[cookbook_dependency]["versions"].each do |cookbookVersion|
|
158
|
+
if vc.include? cookbookVersion["version"]
|
159
|
+
return true
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
false
|
166
|
+
end
|
167
|
+
|
168
|
+
def self.current_cookbooks
|
169
|
+
unless @@current_cookbooks
|
170
|
+
rest = Chef::REST.new(Chef::Config[:chef_server_url])
|
171
|
+
@@current_cookbooks = rest.get_rest('cookbooks?num_versions=all')
|
172
|
+
end
|
173
|
+
@@current_cookbooks
|
174
|
+
end
|
175
|
+
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|