berkshelf-store 0.2.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 +15 -0
- data/.gitignore +2 -0
- data/Gemfile +5 -0
- data/README.md +83 -0
- data/Rakefile +44 -0
- data/berkshelf-store.gemspec +26 -0
- data/bin/berkshelf-store +49 -0
- data/lib/berkshelf-store/backends/filesystem.rb +138 -0
- data/lib/berkshelf-store/backends.rb +5 -0
- data/lib/berkshelf-store/webservice.rb +100 -0
- data/lib/berkshelf-store.rb +5 -0
- data/test/data/arbo/cookbooks/apache2/1.10.4/data.json +1 -0
- data/test/data/arbo/cookbooks/couchbase/1.1.0/data.json +1 -0
- data/test/data/arbo/cookbooks/couchbase/1.2.0/data.json +1 -0
- data/test/data/catalog.json +69 -0
- data/test/data/tarballs/apache2-v1.10.4.tar.gz +0 -0
- data/test/data/tarballs/couchbase-v1.1.0.tar.gz +0 -0
- data/test/data/tarballs/couchbase-v1.2.0.tar.gz +0 -0
- data/test/data/tarballs/not_a_cookbook.tgz +0 -0
- data/test/test_berkshelf-store_backends_filesystem.rb +76 -0
- data/ui/static/bootstrap/css/bootstrap-theme.css +347 -0
- data/ui/static/bootstrap/css/bootstrap-theme.css.map +1 -0
- data/ui/static/bootstrap/css/bootstrap-theme.min.css +7 -0
- data/ui/static/bootstrap/css/bootstrap.css +5785 -0
- data/ui/static/bootstrap/css/bootstrap.css.map +1 -0
- data/ui/static/bootstrap/css/bootstrap.min.css +7 -0
- data/ui/static/bootstrap/fonts/glyphicons-halflings-regular.eot +0 -0
- data/ui/static/bootstrap/fonts/glyphicons-halflings-regular.svg +229 -0
- data/ui/static/bootstrap/fonts/glyphicons-halflings-regular.ttf +0 -0
- data/ui/static/bootstrap/fonts/glyphicons-halflings-regular.woff +0 -0
- data/ui/static/bootstrap/js/bootstrap.js +1951 -0
- data/ui/static/bootstrap/js/bootstrap.min.js +6 -0
- data/ui/static/jquery/jquery.min.js +4 -0
- data/ui/static/jquery_file_upload/CONTRIBUTING.md +42 -0
- data/ui/static/jquery_file_upload/Gruntfile.js +37 -0
- data/ui/static/jquery_file_upload/README.md +123 -0
- data/ui/static/jquery_file_upload/angularjs.html +211 -0
- data/ui/static/jquery_file_upload/basic-plus.html +226 -0
- data/ui/static/jquery_file_upload/basic.html +136 -0
- data/ui/static/jquery_file_upload/blueimp-file-upload.jquery.json +50 -0
- data/ui/static/jquery_file_upload/bower.json +85 -0
- data/ui/static/jquery_file_upload/cors/postmessage.html +75 -0
- data/ui/static/jquery_file_upload/cors/result.html +24 -0
- data/ui/static/jquery_file_upload/css/demo-ie8.css +21 -0
- data/ui/static/jquery_file_upload/css/demo.css +67 -0
- data/ui/static/jquery_file_upload/css/jquery.fileupload-noscript.css +22 -0
- data/ui/static/jquery_file_upload/css/jquery.fileupload-ui-noscript.css +17 -0
- data/ui/static/jquery_file_upload/css/jquery.fileupload-ui.css +57 -0
- data/ui/static/jquery_file_upload/css/jquery.fileupload.css +36 -0
- data/ui/static/jquery_file_upload/css/style.css +15 -0
- data/ui/static/jquery_file_upload/img/loading.gif +0 -0
- data/ui/static/jquery_file_upload/img/progressbar.gif +0 -0
- data/ui/static/jquery_file_upload/index.html +255 -0
- data/ui/static/jquery_file_upload/jquery-ui.html +250 -0
- data/ui/static/jquery_file_upload/js/app.js +101 -0
- data/ui/static/jquery_file_upload/js/cors/jquery.postmessage-transport.js +117 -0
- data/ui/static/jquery_file_upload/js/cors/jquery.xdr-transport.js +86 -0
- data/ui/static/jquery_file_upload/js/jquery.fileupload-angular.js +429 -0
- data/ui/static/jquery_file_upload/js/jquery.fileupload-audio.js +106 -0
- data/ui/static/jquery_file_upload/js/jquery.fileupload-image.js +315 -0
- data/ui/static/jquery_file_upload/js/jquery.fileupload-jquery-ui.js +152 -0
- data/ui/static/jquery_file_upload/js/jquery.fileupload-process.js +172 -0
- data/ui/static/jquery_file_upload/js/jquery.fileupload-ui.js +699 -0
- data/ui/static/jquery_file_upload/js/jquery.fileupload-validate.js +119 -0
- data/ui/static/jquery_file_upload/js/jquery.fileupload-video.js +106 -0
- data/ui/static/jquery_file_upload/js/jquery.fileupload.js +1426 -0
- data/ui/static/jquery_file_upload/js/jquery.iframe-transport.js +214 -0
- data/ui/static/jquery_file_upload/js/main.js +75 -0
- data/ui/static/jquery_file_upload/js/vendor/jquery.ui.widget.js +530 -0
- data/ui/static/jquery_file_upload/package.json +54 -0
- data/ui/static/jquery_file_upload/server/gae-go/app/main.go +296 -0
- data/ui/static/jquery_file_upload/server/gae-go/app.yaml +12 -0
- data/ui/static/jquery_file_upload/server/gae-go/static/favicon.ico +0 -0
- data/ui/static/jquery_file_upload/server/gae-go/static/robots.txt +2 -0
- data/ui/static/jquery_file_upload/server/gae-python/app.yaml +16 -0
- data/ui/static/jquery_file_upload/server/gae-python/main.py +170 -0
- data/ui/static/jquery_file_upload/server/gae-python/static/favicon.ico +0 -0
- data/ui/static/jquery_file_upload/server/gae-python/static/robots.txt +2 -0
- data/ui/static/jquery_file_upload/server/node/package.json +41 -0
- data/ui/static/jquery_file_upload/server/node/server.js +292 -0
- data/ui/static/jquery_file_upload/server/php/UploadHandler.php +1330 -0
- data/ui/static/jquery_file_upload/server/php/index.php +15 -0
- data/ui/static/jquery_file_upload/test/index.html +166 -0
- data/ui/static/jquery_file_upload/test/test.js +1288 -0
- data/ui/views/catalog.erb +20 -0
- data/ui/views/doc.erb +23 -0
- data/ui/views/layout.erb +47 -0
- data/ui/views/upload.erb +46 -0
- metadata +210 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
OWQ4NTk2YzFkM2Q5NDg5Y2Y1YTRhODIxYzM1ZjIwNDM1ZjkzYzVjNg==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
MmMzMTQ2N2ZlMTQ4MmVkMTg1MDA0MWUwODYyNmM1ZWFjNDMyODVkMw==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
MzAxMzljYTA1MWQ4N2I1ZWJkMjhmNjU5MWFjMThkYTZhNTJmMGRiMmM5MjI1
|
10
|
+
NjNjMWY3YjVhODMwNTZjNDlkNzQ1OTcxNjFkZTAyNGI0OGQwNDYwNTQzZTc2
|
11
|
+
NzI5ZWNlNDNiYThlNWU0ODE5NWQ2ZjRlYjRhZjljNDJlNGJmZTQ=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
YWYzYjMyZjFlZmIzOTY5NzJmOWQ2OWI4MjZjNzNmZjRhNTdjZmY3YmM2NTgy
|
14
|
+
MTk4NTU0ZGY0MTk5OWZlOTczYzcxMDI5NDRiNWM5MWI0ZDVkOTAxMmU3NWQx
|
15
|
+
N2NjMzNiZTQ5NDc5ODAxMTEzZjI3YjhhY2EyYWE5NzZkNTAzNDc=
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
berkshelf-store
|
2
|
+
===============
|
3
|
+
|
4
|
+
A cookbook store compatible with berkshelf API.
|
5
|
+
|
6
|
+
Currently it is a simple webservice :
|
7
|
+
* POST /v1/cookbooks/$Name/$Version
|
8
|
+
* cookbook param contains tgz
|
9
|
+
* GET /v1/universe
|
10
|
+
* this is berkshelf API
|
11
|
+
* GET /v1/cookbooks/$Name/$Version/$Name-$Version.tgz
|
12
|
+
* this is how berkshelf gets the cookbook
|
13
|
+
|
14
|
+
Storage is a simple directory tree (easy to backup)
|
15
|
+
|
16
|
+
Status
|
17
|
+
------
|
18
|
+
|
19
|
+
work in progress...
|
20
|
+
|
21
|
+
It is my first ruby project, any advise is welcome :)
|
22
|
+
|
23
|
+
Why would I need this ?
|
24
|
+
-----------------------
|
25
|
+
|
26
|
+
If you have private cookbooks or a validation process for public cookboks, you need an internal storage.
|
27
|
+
|
28
|
+
If you use chef-solo, knife-solo and/or more than one chef-server, you'll need a central catalog of your cookbooks.
|
29
|
+
|
30
|
+
Yes there is berkshelf-api, but it needs a chef server :
|
31
|
+
* A litle overkill if you do no plan to really use it.
|
32
|
+
* not a uniform service
|
33
|
+
* upload via chef
|
34
|
+
* read via berkshelf
|
35
|
+
|
36
|
+
Install
|
37
|
+
-------
|
38
|
+
|
39
|
+
gem build berkshelf-store.gemspec
|
40
|
+
gem install berkshelf-store-*.gem
|
41
|
+
|
42
|
+
|
43
|
+
Usage
|
44
|
+
-----
|
45
|
+
|
46
|
+
### Launch the deamon
|
47
|
+
|
48
|
+
Usage: berkshelf-store.rb [options]
|
49
|
+
-D, --datadir DIRECTORY Data directory (default: ./datadir)
|
50
|
+
-T, --tmpdir DIRECTORY Tmp directory (default: ./tmpdir)
|
51
|
+
-b, --bind IP bind IP (default: 127.0.0.1)
|
52
|
+
-p, --port PORT port to listen on (default: 80)
|
53
|
+
-l, --logger TYPE file, syslog, stderr (default: syslog)
|
54
|
+
-L, --logger-conf TYPE file: filename, syslog: program.facility, stderr n/a (default: berkshelf-store.daemon)
|
55
|
+
|
56
|
+
Example:
|
57
|
+
|
58
|
+
berkshelf-store -D /var/lib/berkshelf-store -T /var/tmp/berkshelf-store --bind 0.0.0.0 -l stderr
|
59
|
+
|
60
|
+
### upload some cookbooks
|
61
|
+
|
62
|
+
curl -F cookbook=@/path/to/the/cookbook.tgz http://localhost/v1/cookbooks/cookbookname/cookbookversion
|
63
|
+
|
64
|
+
### use it with berkshelf
|
65
|
+
|
66
|
+
in the berkfile:
|
67
|
+
|
68
|
+
source "http://localhost/v1"
|
69
|
+
|
70
|
+
cookbook "cookbookname"
|
71
|
+
|
72
|
+
TODO:
|
73
|
+
-----
|
74
|
+
|
75
|
+
by priority
|
76
|
+
|
77
|
+
- more Comments and tests
|
78
|
+
- cli (knife or beks plugin) for uploading
|
79
|
+
- Auth
|
80
|
+
- ACL (limit uploads by cookbook/users/groups)
|
81
|
+
- UI
|
82
|
+
- multi-tenancy ?
|
83
|
+
- clusterized/cloudified backend (mongo, S3, whatelse ?)
|
data/Rakefile
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'rake/testtask'
|
2
|
+
require 'net/http'
|
3
|
+
|
4
|
+
STATICDIR='ui/static'
|
5
|
+
|
6
|
+
desc "Run tests"
|
7
|
+
Rake::TestTask.new do |t|
|
8
|
+
t.libs << 'test'
|
9
|
+
t.test_files = FileList['test/test*.rb']
|
10
|
+
t.verbose = true
|
11
|
+
end
|
12
|
+
|
13
|
+
task :default => :build
|
14
|
+
|
15
|
+
task :build => [ :test, :vendor ] do
|
16
|
+
system "gem build berkshelf-store.gemspec"
|
17
|
+
end
|
18
|
+
|
19
|
+
directory "#{STATICDIR}"
|
20
|
+
task :vendor => [ "#{STATICDIR}/bootstrap", "#{STATICDIR}/jquery/jquery.min.js", "#{STATICDIR}/jquery_file_upload" ] do
|
21
|
+
puts "Vendored"
|
22
|
+
end
|
23
|
+
|
24
|
+
desc "Get bootstrap"
|
25
|
+
directory "#{STATICDIR}/bootstrap" do
|
26
|
+
version = "3.1.1"
|
27
|
+
system "wget https://github.com/twbs/bootstrap/releases/download/v#{version}/bootstrap-#{version}-dist.zip -O #{STATICDIR}/bootstrap.zip"
|
28
|
+
system "cd #{STATICDIR}; unzip bootstrap.zip; mv bootstrap-#{version}-dist bootstrap; rm bootstrap.zip"
|
29
|
+
end
|
30
|
+
|
31
|
+
desc "Get jquery"
|
32
|
+
file "#{STATICDIR}/jquery/jquery.min.js" do
|
33
|
+
version = "1.11.1"
|
34
|
+
system "mkdir #{STATICDIR}/jquery"
|
35
|
+
system "wget http://code.jquery.com/jquery-#{version}.min.js -O #{STATICDIR}/jquery/jquery.min.js"
|
36
|
+
end
|
37
|
+
|
38
|
+
desc "Get jquery file upload"
|
39
|
+
directory "#{STATICDIR}/jquery_file_upload" do
|
40
|
+
version = "9.5.7"
|
41
|
+
system "wget https://github.com/blueimp/jQuery-File-Upload/archive/#{version}.tar.gz -O #{STATICDIR}/jquery_file_upload.tgz"
|
42
|
+
system "cd #{STATICDIR}; tar xvzf jquery_file_upload.tgz; mv jQuery-File-Upload-#{version} jquery_file_upload; rm jquery_file_upload.tgz"
|
43
|
+
end
|
44
|
+
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = "berkshelf-store"
|
6
|
+
s.version = "0.2.0"
|
7
|
+
s.authors = ["Guillaume Zitta"]
|
8
|
+
s.email = ["github.guillaume@zitta.fr"]
|
9
|
+
s.homepage = "https://github.com/gza/berkshelf-store"
|
10
|
+
s.summary = "A cookbook store based on the berkshelf API"
|
11
|
+
s.description = s.summary
|
12
|
+
|
13
|
+
s.rubyforge_project = "berkshelf-store"
|
14
|
+
|
15
|
+
s.files = `git ls-files`.split("\n") + Dir.glob("{ui}/**/*")
|
16
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
17
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
18
|
+
s.require_paths = ["lib"]
|
19
|
+
|
20
|
+
s.add_dependency 'syslog-logger'
|
21
|
+
s.add_dependency 'ridley'
|
22
|
+
s.add_dependency 'sinatra', '>=1.4.5'
|
23
|
+
s.add_dependency 'sinatra-contrib', '>=1.4.2'
|
24
|
+
|
25
|
+
s.add_development_dependency 'rake'
|
26
|
+
end
|
data/bin/berkshelf-store
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$:.push File.expand_path("../../lib", __FILE__)
|
3
|
+
|
4
|
+
require 'optparse'
|
5
|
+
require 'berkshelf-store'
|
6
|
+
|
7
|
+
options = {
|
8
|
+
datadir:"./datadir",
|
9
|
+
tmpdir:"./tmpdir",
|
10
|
+
bind:"127.0.0.1",
|
11
|
+
port:"80",
|
12
|
+
logger_type:"syslog",
|
13
|
+
logger_conf:"berkshelf-store.daemon"
|
14
|
+
}
|
15
|
+
|
16
|
+
OptionParser.new do |opts|
|
17
|
+
opts.banner = "Usage: berkshelf-store.rb [options]"
|
18
|
+
|
19
|
+
opts.on("-D", "--datadir DIRECTORY", "Data directory (default: #{options[:datadir]})") do |d|
|
20
|
+
options[:datadir] = d
|
21
|
+
end
|
22
|
+
|
23
|
+
opts.on("-T", "--tmpdir DIRECTORY", "Tmp directory (default: #{options[:tmpdir]})") do |t|
|
24
|
+
options[:tmpdir] = t
|
25
|
+
end
|
26
|
+
|
27
|
+
opts.on("-b", "--bind IP", "bind IP (default: #{options[:bind]})") do |ip|
|
28
|
+
options[:bind] = ip
|
29
|
+
end
|
30
|
+
|
31
|
+
opts.on("-p", "--port PORT", "port to listen on (default: #{options[:port]})") do |p|
|
32
|
+
options[:port] = p
|
33
|
+
end
|
34
|
+
|
35
|
+
opts.on("-l", "--logger TYPE", "file, syslog, stderr (default: #{options[:logger_type]})") do |l|
|
36
|
+
options[:logger_type] = l
|
37
|
+
end
|
38
|
+
|
39
|
+
opts.on("-L", "--logger-conf TYPE", "file: filename, syslog: program.facility, stderr n/a (default: #{options[:logger_conf]})") do |lc|
|
40
|
+
options[:logger_conf] = lc
|
41
|
+
end
|
42
|
+
end.parse!
|
43
|
+
|
44
|
+
#The only way I found to pass options to configure
|
45
|
+
ENV['LOGGER_TYPE'] ||= options.delete(:logger_type)
|
46
|
+
ENV['LOGGER_CONF'] ||= options.delete(:logger_conf)
|
47
|
+
|
48
|
+
#remaining options will be available as settings
|
49
|
+
BerkshelfStore::Webservice.run!(options)
|
@@ -0,0 +1,138 @@
|
|
1
|
+
require 'digest'
|
2
|
+
require 'json'
|
3
|
+
require 'fileutils'
|
4
|
+
require 'ridley'
|
5
|
+
|
6
|
+
module BerkshelfStore::Backends
|
7
|
+
class Filesystem
|
8
|
+
|
9
|
+
@error = ''
|
10
|
+
|
11
|
+
def initialize(path, tmp)
|
12
|
+
@path = path
|
13
|
+
@tmp = tmp
|
14
|
+
end
|
15
|
+
|
16
|
+
def check_filename(filename)
|
17
|
+
#do minimal checks
|
18
|
+
true
|
19
|
+
end
|
20
|
+
|
21
|
+
def store(content, name, version)
|
22
|
+
data = {}
|
23
|
+
|
24
|
+
digest = Digest::SHA256.hexdigest(content)
|
25
|
+
tmp_dir = "#{@tmp}/#{digest}"
|
26
|
+
|
27
|
+
FileUtils.mkdir_p "#{tmp_dir}/cookbook"
|
28
|
+
|
29
|
+
#extract cookbook
|
30
|
+
if write_tmp_file("#{tmp_dir}/cookbook.tgz", content)
|
31
|
+
cmd = "tar --gzip --extract --file=\"#{tmp_dir}/cookbook.tgz\" -C \"#{tmp_dir}/cookbook\""
|
32
|
+
%x{#{cmd}}
|
33
|
+
|
34
|
+
if $?.exitstatus != 0
|
35
|
+
return {"fail" => "Failed to extract metadata.rb from tarball"}
|
36
|
+
end
|
37
|
+
else
|
38
|
+
return {"fail" => "Unable to write cookbook #{tmp_dir}/cookbook.tgz"}
|
39
|
+
end
|
40
|
+
|
41
|
+
#locate check cookbook
|
42
|
+
search_root = Dir["#{tmp_dir}/cookbook/*/metadata.rb"]
|
43
|
+
if search_root.size != 1
|
44
|
+
return {"fail" => "tgz don't contains one and only on */metadata.rb"}
|
45
|
+
end
|
46
|
+
cookbook_dir = File.dirname(search_root[0])
|
47
|
+
|
48
|
+
#Extract information
|
49
|
+
begin
|
50
|
+
cookbook = Ridley::Chef::Cookbook.from_path(cookbook_dir)
|
51
|
+
data = cookbook_data(cookbook)
|
52
|
+
rescue Exception => e
|
53
|
+
return {"fail" => "Information extraction failed #{e}"}
|
54
|
+
end
|
55
|
+
|
56
|
+
begin
|
57
|
+
data_dir = "#{@path}/#{name}/#{version}"
|
58
|
+
FileUtils.mkdir_p "#{data_dir}"
|
59
|
+
rescue SystemCallError => e
|
60
|
+
return {"fail" => "#{data_dir} creation failed #{e}"}
|
61
|
+
end
|
62
|
+
|
63
|
+
begin
|
64
|
+
json_file = File.open("#{data_dir}/data.json", "w")
|
65
|
+
json_file.write(data.to_json)
|
66
|
+
json_file.close
|
67
|
+
rescue Exception => e
|
68
|
+
return {"fail" => "#{data_dir}/data.json creation failed #{e}"}
|
69
|
+
end
|
70
|
+
|
71
|
+
begin
|
72
|
+
File.rename("#{tmp_dir}/cookbook.tgz", "#{data_dir}/#{name}-#{version}.tgz")
|
73
|
+
rescue Exception => e
|
74
|
+
return {"fail" => "tarball store failed #{e}"}
|
75
|
+
end
|
76
|
+
|
77
|
+
return data
|
78
|
+
end
|
79
|
+
|
80
|
+
def cookbook_data(cookbook)
|
81
|
+
platforms = cookbook.metadata.platforms || Hash.new
|
82
|
+
dependencies = cookbook.metadata.dependencies || Hash.new
|
83
|
+
|
84
|
+
name = cookbook.cookbook_name.to_s
|
85
|
+
version = cookbook.version.to_s
|
86
|
+
|
87
|
+
path = "/#{name}/#{version}/#{name}-#{version}.tgz"
|
88
|
+
|
89
|
+
retval = {
|
90
|
+
"name" => name,
|
91
|
+
"version" => version,
|
92
|
+
"data" => {
|
93
|
+
"endpoint_priority" => 0,
|
94
|
+
"platforms" => platforms,
|
95
|
+
"dependencies" => dependencies,
|
96
|
+
"location_type" => 'uri',
|
97
|
+
"location_path" => path
|
98
|
+
}
|
99
|
+
}
|
100
|
+
return retval
|
101
|
+
end
|
102
|
+
|
103
|
+
def write_tmp_file(name, content)
|
104
|
+
begin
|
105
|
+
tarfile = File.open("#{name}", "w")
|
106
|
+
tarfile.write(content)
|
107
|
+
rescue IOError => e
|
108
|
+
@error="Failed to write temp file #{name}"
|
109
|
+
return false
|
110
|
+
ensure
|
111
|
+
tarfile.close unless tarfile == nil
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def last_error
|
116
|
+
@error
|
117
|
+
end
|
118
|
+
|
119
|
+
def get_json(name, version)
|
120
|
+
File.open("#{@path}/#{name}/#{version}/data.json", "r").read
|
121
|
+
end
|
122
|
+
|
123
|
+
def get_tarball(name, version)
|
124
|
+
File.open("#{@path}/#{name}/#{version}/#{name}-#{version}.tgz").read
|
125
|
+
end
|
126
|
+
|
127
|
+
def get_catalog(prefix)
|
128
|
+
retval = {}
|
129
|
+
Dir["#{@path}/*/*/data.json"].each do |json_file|
|
130
|
+
data = JSON.parse(File.read("#{json_file}"))
|
131
|
+
data['data']['location_path'] = "#{prefix}#{data['data']['location_path']}"
|
132
|
+
retval[data['name']] ||= Hash.new
|
133
|
+
retval[data['name']][data['version']] = data['data']
|
134
|
+
end
|
135
|
+
retval
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
require 'sinatra/json'
|
3
|
+
require 'syslog-logger'
|
4
|
+
require 'logger'
|
5
|
+
|
6
|
+
#require 'berkshelf-store'
|
7
|
+
::Logger.class_eval { alias :write :'<<' }
|
8
|
+
::Logger::Syslog.class_eval { alias :write :'<<' }
|
9
|
+
|
10
|
+
module BerkshelfStore
|
11
|
+
class Webservice < Sinatra::Base
|
12
|
+
helpers Sinatra::JSON
|
13
|
+
|
14
|
+
helpers do
|
15
|
+
def logger
|
16
|
+
settings.logger
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
configure do
|
21
|
+
logger_type = ENV['LOGGER_TYPE'].to_s
|
22
|
+
logger_conf = ENV['LOGGER_CONF'].to_s
|
23
|
+
if logger_type == "file"
|
24
|
+
logger = Logger.new(File.open("#{logger_conf}", 'a'))
|
25
|
+
elsif logger_type == "stderr"
|
26
|
+
logger = Logger.new(STDERR)
|
27
|
+
elsif logger_type == "syslog"
|
28
|
+
programname = logger_conf.split(".")[0]
|
29
|
+
facility = eval("Syslog::LOG_#{logger_conf.to_s.split(".")[1].upcase}")
|
30
|
+
logger = Logger::Syslog.new(programname, facility)
|
31
|
+
end
|
32
|
+
use ::Rack::CommonLogger, logger
|
33
|
+
set :logger, logger
|
34
|
+
|
35
|
+
#static files (UI) stuff
|
36
|
+
#et :public_folder, BerkshelfStore::ROOT + '/www/static'
|
37
|
+
|
38
|
+
end
|
39
|
+
set :prefix, "/"
|
40
|
+
set :public_folder, BerkshelfStore::ROOT + '/ui/static'
|
41
|
+
set :views, BerkshelfStore::ROOT + '/ui/views'
|
42
|
+
|
43
|
+
|
44
|
+
get "/ping" do
|
45
|
+
logger.info 'ping'
|
46
|
+
json({'info' => 'berkshelf-store',
|
47
|
+
'version' => 'it would be nice to show it :)',
|
48
|
+
'status' => 'seems to work :)'})
|
49
|
+
end
|
50
|
+
|
51
|
+
get "/v1/universe" do
|
52
|
+
cookbooks_url_prefix = "#{request.base_url}/v1/cookbooks"
|
53
|
+
storage = BerkshelfStore::Backends::Filesystem.new(settings.datadir, settings.tmpdir)
|
54
|
+
json(storage.get_catalog(cookbooks_url_prefix))
|
55
|
+
end
|
56
|
+
|
57
|
+
get "/v1/cookbooks/:name/:version/:filename" do
|
58
|
+
if params[:filename] == "#{params[:name]}-#{params[:version]}.tgz"
|
59
|
+
storage = BerkshelfStore::Backends::Filesystem.new(settings.datadir, settings.tmpdir)
|
60
|
+
storage.get_tarball(params[:name],params[:version])
|
61
|
+
else
|
62
|
+
halt 400, json({'fail' => 'cookbook name should be name-version.tgz'})
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
post "/v1/cookbooks/:name/:version" do
|
67
|
+
if params.key?("cookbook") && params.key?("name") && params.key?("version")
|
68
|
+
storage = BerkshelfStore::Backends::Filesystem.new(settings.datadir, settings.tmpdir)
|
69
|
+
cookbook_data = storage.store(params["cookbook"][:tempfile].read, params[:name], params[:version])
|
70
|
+
if cookbook_data.key?('name')
|
71
|
+
json cookbook_data
|
72
|
+
else
|
73
|
+
halt 500, json(cookbook_data)
|
74
|
+
end
|
75
|
+
else
|
76
|
+
halt 400, json({'fail' => 'Wrong parameters'})
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
get "/" do
|
81
|
+
redirect "/index.html"
|
82
|
+
end
|
83
|
+
|
84
|
+
get "/:name.html" do
|
85
|
+
@site_prefix="#{request.base_url}"
|
86
|
+
@ws_prefix="/v1"
|
87
|
+
@active="#{params[:name]}"
|
88
|
+
if params[:name] == 'index'
|
89
|
+
erb :catalog
|
90
|
+
elsif params[:name] == 'upload'
|
91
|
+
erb :upload
|
92
|
+
elsif params[:name] == 'doc'
|
93
|
+
erb :doc
|
94
|
+
else
|
95
|
+
halt 404, "<h1>page #{params[:name]}.html not found</h1>"
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
{"name":"apache2","version":"1.10.4","data":{"endpoint_priority":0,"platforms":{"amazon":">= 0.0.0","arch":">= 0.0.0","centos":">= 0.0.0","debian":">= 0.0.0","fedora":">= 0.0.0","freebsd":">= 0.0.0","redhat":">= 0.0.0","scientific":">= 0.0.0","ubuntu":">= 0.0.0"},"dependencies":{"iptables":">= 0.0.0","logrotate":">= 0.0.0","pacman":">= 0.0.0"},"location_type":"uri","location_path":"/apache2/1.10.4/apache2-1.10.4.tgz"}}
|
@@ -0,0 +1 @@
|
|
1
|
+
{"name":"couchbase","version":"1.1.0","data":{"endpoint_priority":0,"platforms":{"debian":">= 0.0.0","ubuntu":">= 0.0.0","centos":">= 0.0.0","redhat":">= 0.0.0","oracle":">= 0.0.0","amazon":">= 0.0.0","scientific":">= 0.0.0","windows":">= 0.0.0"},"dependencies":{"apt":">= 0.0.0","openssl":">= 0.0.0","windows":">= 0.0.0","yum":">= 0.0.0"},"location_type":"uri","location_path":"/couchbase/1.1.0/couchbase-1.1.0.tgz"}}
|
@@ -0,0 +1 @@
|
|
1
|
+
{"name":"couchbase","version":"1.2.0","data":{"endpoint_priority":0,"platforms":{"debian":">= 0.0.0","ubuntu":">= 0.0.0","centos":">= 0.0.0","redhat":">= 0.0.0","oracle":">= 0.0.0","amazon":">= 0.0.0","scientific":">= 0.0.0","windows":">= 0.0.0"},"dependencies":{"apt":">= 0.0.0","openssl":">= 0.0.0","windows":">= 0.0.0","yum":">= 0.0.0"},"location_type":"uri","location_path":"/couchbase/1.2.0/couchbase-1.2.0.tgz"}}
|
@@ -0,0 +1,69 @@
|
|
1
|
+
{
|
2
|
+
"apache2": {
|
3
|
+
"1.10.4": {
|
4
|
+
"dependencies": {
|
5
|
+
"iptables": ">= 0.0.0",
|
6
|
+
"logrotate": ">= 0.0.0",
|
7
|
+
"pacman": ">= 0.0.0"
|
8
|
+
},
|
9
|
+
"endpoint_priority": 0,
|
10
|
+
"location_path": "http://localhost/apache2/1.10.4/apache2-1.10.4.tgz",
|
11
|
+
"location_type": "uri",
|
12
|
+
"platforms": {
|
13
|
+
"amazon": ">= 0.0.0",
|
14
|
+
"arch": ">= 0.0.0",
|
15
|
+
"centos": ">= 0.0.0",
|
16
|
+
"debian": ">= 0.0.0",
|
17
|
+
"fedora": ">= 0.0.0",
|
18
|
+
"freebsd": ">= 0.0.0",
|
19
|
+
"redhat": ">= 0.0.0",
|
20
|
+
"scientific": ">= 0.0.0",
|
21
|
+
"ubuntu": ">= 0.0.0"
|
22
|
+
}
|
23
|
+
}
|
24
|
+
},
|
25
|
+
"couchbase": {
|
26
|
+
"1.1.0": {
|
27
|
+
"dependencies": {
|
28
|
+
"apt": ">= 0.0.0",
|
29
|
+
"openssl": ">= 0.0.0",
|
30
|
+
"windows": ">= 0.0.0",
|
31
|
+
"yum": ">= 0.0.0"
|
32
|
+
},
|
33
|
+
"endpoint_priority": 0,
|
34
|
+
"location_path": "http://localhost/couchbase/1.1.0/couchbase-1.1.0.tgz",
|
35
|
+
"location_type": "uri",
|
36
|
+
"platforms": {
|
37
|
+
"amazon": ">= 0.0.0",
|
38
|
+
"centos": ">= 0.0.0",
|
39
|
+
"debian": ">= 0.0.0",
|
40
|
+
"oracle": ">= 0.0.0",
|
41
|
+
"redhat": ">= 0.0.0",
|
42
|
+
"scientific": ">= 0.0.0",
|
43
|
+
"ubuntu": ">= 0.0.0",
|
44
|
+
"windows": ">= 0.0.0"
|
45
|
+
}
|
46
|
+
},
|
47
|
+
"1.2.0": {
|
48
|
+
"dependencies": {
|
49
|
+
"apt": ">= 0.0.0",
|
50
|
+
"openssl": ">= 0.0.0",
|
51
|
+
"windows": ">= 0.0.0",
|
52
|
+
"yum": ">= 0.0.0"
|
53
|
+
},
|
54
|
+
"endpoint_priority": 0,
|
55
|
+
"location_path": "http://localhost/couchbase/1.2.0/couchbase-1.2.0.tgz",
|
56
|
+
"location_type": "uri",
|
57
|
+
"platforms": {
|
58
|
+
"amazon": ">= 0.0.0",
|
59
|
+
"centos": ">= 0.0.0",
|
60
|
+
"debian": ">= 0.0.0",
|
61
|
+
"oracle": ">= 0.0.0",
|
62
|
+
"redhat": ">= 0.0.0",
|
63
|
+
"scientific": ">= 0.0.0",
|
64
|
+
"ubuntu": ">= 0.0.0",
|
65
|
+
"windows": ">= 0.0.0"
|
66
|
+
}
|
67
|
+
}
|
68
|
+
}
|
69
|
+
}
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'test/unit'
|
3
|
+
require 'berkshelf-store'
|
4
|
+
|
5
|
+
class BerkshelfRepoBackendsFilesystemTest < Test::Unit::TestCase
|
6
|
+
|
7
|
+
def setup
|
8
|
+
@test_dir = File.dirname(__FILE__)
|
9
|
+
@tarballs = "#{@test_dir}/data/tarballs"
|
10
|
+
@dataarbo = "#{@test_dir}/data/arbo"
|
11
|
+
@tmp="#{@test_dir}/tmp/tmp"
|
12
|
+
@path="#{@test_dir}/tmp/path"
|
13
|
+
|
14
|
+
#test_cases
|
15
|
+
@test_case = Hash.new
|
16
|
+
@test_case[:couchbase_1_2_0] = Hash.new
|
17
|
+
@test_case[:couchbase_1_2_0][:name] = 'couchbase'
|
18
|
+
@test_case[:couchbase_1_2_0][:version] = '1.2.0'
|
19
|
+
@test_case[:couchbase_1_2_0][:content] = File.read("#{@tarballs}/couchbase-v1.2.0.tar.gz")
|
20
|
+
@test_case[:couchbase_1_2_0][:json] = File.read("#{@dataarbo}/cookbooks/couchbase/1.2.0/data.json")
|
21
|
+
end
|
22
|
+
|
23
|
+
def clean
|
24
|
+
FileUtils.rm_rf(@tmp)
|
25
|
+
FileUtils.mkdir_p(@tmp)
|
26
|
+
FileUtils.rm_rf(@path)
|
27
|
+
FileUtils.mkdir_p(@path)
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_store
|
31
|
+
clean()
|
32
|
+
|
33
|
+
@test_case.values.each do |cookbook|
|
34
|
+
repo=BerkshelfStore::Backends::Filesystem.new(@path,@tmp)
|
35
|
+
|
36
|
+
cbdir = "#{@path}/#{cookbook[:name]}/#{cookbook[:version]}"
|
37
|
+
#Must not exists before
|
38
|
+
assert(! File.exists?(cbdir))
|
39
|
+
|
40
|
+
result_store = repo.store(cookbook[:content], cookbook[:name], cookbook[:version])
|
41
|
+
|
42
|
+
assert(File.exists?(cbdir))
|
43
|
+
assert(File.exists?("#{cbdir}/#{cookbook[:name]}-#{cookbook[:version]}.tgz"))
|
44
|
+
assert(File.exists?("#{cbdir}/data.json"))
|
45
|
+
|
46
|
+
assert( result_store )
|
47
|
+
|
48
|
+
generated_data = JSON.parse(File.read("#{cbdir}/data.json"))
|
49
|
+
control_data = JSON.parse(cookbook[:json])
|
50
|
+
assert_equal(control_data, generated_data)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_store_bad_tgz
|
55
|
+
clean()
|
56
|
+
repo=BerkshelfStore::Backends::Filesystem.new(@path,@tmp)
|
57
|
+
result_store = repo.store("this is not tgz data, hi hi", "toto", "0.0.0")
|
58
|
+
assert( result_store.key?('fail') )
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_store_not_cookbook_tgz
|
62
|
+
clean()
|
63
|
+
repo=BerkshelfStore::Backends::Filesystem.new(@path,@tmp)
|
64
|
+
result_store = repo.store(File.read("#{@tarballs}/not_a_cookbook.tgz"), "toto", "0.0.0")
|
65
|
+
assert( result_store.key?('fail') )
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_get_catalog
|
69
|
+
clean()
|
70
|
+
|
71
|
+
repo=BerkshelfStore::Backends::Filesystem.new("#{@dataarbo}/cookbooks", @tmp)
|
72
|
+
generated_data = repo.get_catalog("http://localhost")
|
73
|
+
control_data = JSON.parse(File.read("#{@test_dir}/data/catalog.json"))
|
74
|
+
assert_equal(control_data, generated_data)
|
75
|
+
end
|
76
|
+
end
|