puppet-library 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.md ADDED
@@ -0,0 +1,89 @@
1
+ # Puppet Library
2
+
3
+ A server for your Puppet modules. Compatible with [librarian-puppet](http://librarian-puppet.com).
4
+
5
+ [![Build Status](https://travis-ci.org/drrb/puppet-library.png?branch=master)](https://travis-ci.org/drrb/puppet-library)
6
+ [![Coverage Status](https://coveralls.io/repos/drrb/puppet-library/badge.png)](https://coveralls.io/r/drrb/puppet-library)
7
+
8
+ Puppet library serves packaged (`tar.gz`) modules from a directory of your choosing in the same format as [the Puppet Forge](http://forge.puppetlabs.com).
9
+
10
+ ## Installation
11
+
12
+ Install the server as a Gem:
13
+
14
+ $ gem install puppet-library
15
+
16
+ ## Getting Started
17
+
18
+ Create a module directory and add the modules to it
19
+
20
+ $ mkdir modules
21
+ $ wget -P modules/ forge.puppetlabs.com/system/releases/p/puppetlabs/puppetlabs-apache-0.9.0.tar.gz
22
+ $ wget -P modules/ forge.puppetlabs.com/system/releases/p/puppetlabs/puppetlabs-concat-1.0.0.tar.gz
23
+ $ wget -P modules/ forge.puppetlabs.com/system/releases/p/puppetlabs/puppetlabs-stdlib-2.4.0.tar.gz
24
+
25
+ Start the server
26
+
27
+ $ puppet-library
28
+
29
+ Point librarian-puppet to the server
30
+
31
+ $ cat > Puppetfile <<EOF
32
+ forge 'http://localhost:9292'
33
+
34
+ mod 'puppetlabs/apache', '0.9.0'
35
+ EOF
36
+
37
+ Resolve and download the modules
38
+
39
+ $ librarian-puppet install
40
+
41
+ ## Usage
42
+
43
+ Run the server
44
+
45
+ $ puppet-library
46
+
47
+ Serve modules from a specific directory
48
+
49
+ $ puppet-library --module-dir /var/puppet-modules
50
+
51
+ Serve modules on a specific port
52
+
53
+ $ puppet-library --port 8888
54
+
55
+ See all options
56
+
57
+ $ puppet-library --help
58
+
59
+ ## Contributing
60
+
61
+ 1. Fork it
62
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
63
+ 3. Make your changes, and add tests for them
64
+ 4. Test your changes (`rake`)
65
+ 5. Commit your changes (`git commit -am 'Add some feature'`)
66
+ 6. Push to the branch (`git push origin my-new-feature`)
67
+ 7. Create new Pull Request
68
+
69
+ ## Acknowledgements
70
+
71
+ This project was inspired by [dalen/simple-puppet-forge](https://github.com/dalen/simple-puppet-forge).
72
+
73
+ ## License
74
+
75
+ Puppet Library
76
+ Copyright (C) 2013 drrb
77
+
78
+ This program is free software: you can redistribute it and/or modify
79
+ it under the terms of the GNU General Public License as published by
80
+ the Free Software Foundation, either version 3 of the License, or
81
+ (at your option) any later version.
82
+
83
+ This program is distributed in the hope that it will be useful,
84
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
85
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
86
+ GNU General Public License for more details.
87
+
88
+ You should have received a copy of the GNU General Public License
89
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
data/Rakefile ADDED
@@ -0,0 +1,50 @@
1
+ # -*- encoding: utf-8 -*-
2
+ # Puppet Library
3
+ # Copyright (C) 2013 drrb
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ require 'bundler/gem_tasks'
19
+ require 'rspec/core/rake_task'
20
+ require 'coveralls/rake/task'
21
+
22
+ RSpec::Core::RakeTask.new(:spec)
23
+ Coveralls::RakeTask.new
24
+
25
+ task :default => [:spec, 'coveralls:push']
26
+
27
+ desc "Check it works on all local rubies"
28
+ task :verify do
29
+ system "rvm all do rake spec check-license"
30
+ end
31
+
32
+ desc "Check all files for license headers"
33
+ task "check-license" do
34
+ puts "Checking that all program files contain license headers"
35
+
36
+ files = `git ls-files`.split "\n"
37
+ ignored_files = File.read(".licenseignore").split("\n") << ".licenseignore"
38
+ offending_files = files.reject { |file| File.read(file).include? "WITHOUT ANY WARRANTY" } - ignored_files
39
+ if offending_files.empty?
40
+ puts "Done"
41
+ else
42
+ abort("ERROR: THE FOLLOWING FILES HAVE NO LICENSE HEADERS: \n" + offending_files.join("\n"))
43
+ end
44
+ end
45
+
46
+ desc "Print the version number"
47
+ task "version" do
48
+ puts PuppetLibrary::VERSION
49
+ end
50
+
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env ruby
2
+ # Puppet Library
3
+ # Copyright (C) 2013 drrb
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ lib_path = File.join(File.dirname(__FILE__), '..', 'lib')
19
+ $LOAD_PATH.unshift lib_path unless $LOAD_PATH.include? lib_path
20
+
21
+ require "puppet_library"
22
+ require 'optparse'
23
+
24
+ module PuppetLibrary
25
+ options = {}
26
+ OptionParser.new do |opts|
27
+ opts.banner = "Usage: #{File.basename $0} [options]"
28
+
29
+ options[:port] = "9292"
30
+ opts.on("-p", "--port [PORT]", "Port to listen on (defaults to #{options[:port]}") do |port|
31
+ options[:port] = port
32
+ end
33
+
34
+ options[:hostname] = "0.0.0.0"
35
+ opts.on("-b", "--bind-host [HOSTNAME]", "Host name to bind to (defaults to #{options[:hostname]}") do |hostname|
36
+ options[:hostname] = hostname
37
+ end
38
+
39
+ options[:module_dir] = "./modules"
40
+ opts.on("-m", "--module-dir [DIR]", "Directory containing the modules (defaults to #{options[:module_dir]})") do |module_dir|
41
+ options[:module_dir] = module_dir
42
+ end
43
+ end.parse!
44
+
45
+ server = Server.new(ModuleRepo.new(options[:module_dir]))
46
+
47
+ dispatch = Rack::Builder.app do
48
+ map '/' do
49
+ run Server.new
50
+ end
51
+ end
52
+
53
+ Rack::Server.start({
54
+ app: dispatch,
55
+ Host: options[:hostname],
56
+ Port: options[:port]
57
+ })
58
+ end
data/config.ru ADDED
@@ -0,0 +1,20 @@
1
+ # -*- encoding: utf-8 -*-
2
+ # Puppet Library
3
+ # Copyright (C) 2013 drrb
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ require 'puppet_library'
19
+
20
+ run PuppetLibrary::Server
@@ -0,0 +1,19 @@
1
+ # -*- encoding: utf-8 -*-
2
+ # Puppet Library
3
+ # Copyright (C) 2013 drrb
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ require "puppet_library/server"
19
+ require "puppet_library/version"
@@ -0,0 +1,44 @@
1
+ # Puppet Library
2
+ # Copyright (C) 2013 drrb
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+ require 'rubygems/package'
17
+ require 'zlib'
18
+
19
+ module PuppetLibrary
20
+ class ModuleRepo
21
+ def initialize(module_dir)
22
+ @module_dir = module_dir
23
+ end
24
+
25
+ def get_module(author, name, version)
26
+ file_name = "#{author}-#{name}-#{version}.tar.gz"
27
+ path = File.join(File.expand_path(@module_dir), file_name)
28
+ if File.exist? path
29
+ File.open(path, 'r')
30
+ else
31
+ nil
32
+ end
33
+ end
34
+
35
+ def get_metadata(author, module_name)
36
+ Dir["#{@module_dir}/#{author}-#{module_name}*"].map do |module_path|
37
+ tar = Gem::Package::TarReader.new(Zlib::GzipReader.open(module_path))
38
+ tar.rewind
39
+ metadata_file = tar.find {|e| e.full_name =~ /[^\/]+\/metadata\.json/}
40
+ JSON.parse(metadata_file.read)
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,151 @@
1
+ # -*- encoding: utf-8 -*-
2
+ # Puppet Library
3
+ # Copyright (C) 2013 drrb
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+ require 'sinatra/base'
18
+ require 'json'
19
+
20
+ require 'puppet_library/module_repo'
21
+
22
+ class Hash
23
+ def deep_merge(other)
24
+ merge(other) do |key, old_val, new_val|
25
+ if old_val.instance_of? Array
26
+ old_val + new_val
27
+ else
28
+ new_val
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ module PuppetLibrary
35
+
36
+ class ModuleMetadata
37
+
38
+ def initialize(metadata)
39
+ @metadata = metadata
40
+ end
41
+
42
+ def author
43
+ @metadata["name"][/^[^-]+/]
44
+ end
45
+
46
+ def name
47
+ @metadata["name"].sub(/^[^-]+-/, "")
48
+ end
49
+
50
+ def full_name
51
+ @metadata["name"].sub("-", "/")
52
+ end
53
+
54
+ def version
55
+ @metadata["version"]
56
+ end
57
+
58
+ def dependencies
59
+ @metadata["dependencies"]
60
+ end
61
+
62
+ def dependency_names
63
+ dependencies.map {|d| d["name"]}
64
+ end
65
+
66
+ def to_info
67
+ {
68
+ "author" => author,
69
+ "full_name" => full_name,
70
+ "name" => name,
71
+ "desc" => @metadata["description"],
72
+ "releases" => [ { "version" => version } ]
73
+ }
74
+ end
75
+
76
+ def to_version
77
+ {
78
+ "file" => "/modules/#{author}-#{name}-#{version}.tar.gz",
79
+ "version" => version,
80
+ "dependencies" => dependencies.map {|m| [ m["name"], m["version_requirement"] ]}
81
+ }
82
+ end
83
+ end
84
+
85
+ class Server < Sinatra::Base
86
+
87
+ def initialize(module_repo = ModuleRepo.new("modules"))
88
+ super(nil)
89
+ @repo = module_repo
90
+ end
91
+
92
+ configure do
93
+ enable :logging
94
+ end
95
+
96
+ get "/:author/:module.json" do
97
+ author = params[:author]
98
+ module_name = params[:module]
99
+ modules = get_metadata(author, module_name)
100
+ if modules.empty?
101
+ status 410
102
+ {"error" => "Could not find module \"#{module_name}\""}.to_json
103
+ else
104
+ modules.map do |metadata|
105
+ metadata.to_info
106
+ end.inject({}) do |merged, map|
107
+ merged.deep_merge(map)
108
+ end.to_json
109
+ end
110
+ end
111
+
112
+ get "/api/v1/releases.json" do
113
+ full_name = params[:module]
114
+ module_queue = [full_name]
115
+ modules_versions = {}
116
+ while module_full_name = module_queue.shift
117
+ next if modules_versions[module_full_name]
118
+ author, module_name = module_full_name.split "/"
119
+ module_versions = get_metadata(author, module_name)
120
+ dependencies = module_versions.map {|v| v.dependency_names }.flatten
121
+ module_queue += dependencies
122
+ modules_versions[module_full_name] = module_versions.map { |v| v.to_version }
123
+ end
124
+
125
+ if modules_versions.values == [[]]
126
+ status 410
127
+ {"error" => "Module #{full_name} not found"}.to_json
128
+ else
129
+ modules_versions.to_json
130
+ end
131
+ end
132
+
133
+ get "/modules/:author-:module-:version.tar.gz" do
134
+ author = params[:author]
135
+ name = params[:module]
136
+ version = params[:version]
137
+ buffer = @repo.get_module(author, name, version)
138
+ content_type "application/octet-stream"
139
+ if buffer.nil?
140
+ status 404
141
+ else
142
+ attachment "#{author}-#{name}-#{version}.tar.gz"
143
+ buffer
144
+ end
145
+ end
146
+
147
+ def get_metadata(author, module_name)
148
+ @repo.get_metadata(author, module_name).map {|metadata| ModuleMetadata.new(metadata)}
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,20 @@
1
+ # -*- encoding: utf-8 -*-
2
+ # Puppet Library
3
+ # Copyright (C) 2013 drrb
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ module PuppetLibrary
19
+ VERSION = "0.0.1"
20
+ end