knife-tar 1.3.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.
- 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
|