puppet-library 0.0.2 → 0.1.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 +4 -4
- data/.travis.yml +0 -1
- data/README.md +23 -5
- data/Rakefile +18 -4
- data/TODO.yml +14 -3
- data/config.ru +7 -3
- data/lib/puppet_library.rb +5 -1
- data/lib/puppet_library/forge.rb +100 -0
- data/lib/puppet_library/http/cache.rb +61 -0
- data/lib/puppet_library/http/http_client.rb +35 -0
- data/lib/puppet_library/http/url.rb +27 -0
- data/lib/puppet_library/module_metadata.rb +9 -4
- data/lib/puppet_library/module_repo/proxy.rb +87 -0
- data/lib/puppet_library/puppet_library.rb +30 -20
- data/lib/puppet_library/server.rb +10 -67
- data/lib/puppet_library/util.rb +2 -2
- data/lib/puppet_library/version.rb +1 -1
- data/puppet-library.gemspec +3 -1
- data/spec/forge_spec.rb +147 -0
- data/spec/http/cache_spec.rb +63 -0
- data/spec/http/http_client_spec.rb +44 -0
- data/spec/http/url_spec.rb +39 -0
- data/spec/module_repo/directory_spec.rb +9 -5
- data/spec/module_repo/proxy_spec.rb +105 -0
- data/spec/module_spec_helper.rb +3 -1
- data/spec/puppet_library_spec.rb +64 -15
- data/spec/server_spec.rb +45 -77
- data/spec/spec_helper.rb +2 -0
- data/test/librarian_puppet_integration_test.rb +111 -0
- metadata +47 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dd852d5afc9f767f3adbd20e96a3d6ba37fec092
|
4
|
+
data.tar.gz: 9030ad628af928e81289963f28e9df751a4240b6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a168548b6050b5d34d121b1191f74dfe5a84e11024714f07d753828ef72894ef3b039ffbbd8c3c7a125179b29c4862ea8d4de17f2c45a3e0cf60527d48ae723a
|
7
|
+
data.tar.gz: 1c130b6732c99488fffc95442bca7b3604b0ae38213aba4415b185dd79514b705ee76cdc8710f1b53054f5428c54143b54ae80ec987c7a243888f51752602c5f
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -1,11 +1,19 @@
|
|
1
1
|
# Puppet Library
|
2
2
|
|
3
|
-
A server for your Puppet modules. Compatible with [librarian-puppet](http://librarian-puppet.com).
|
3
|
+
A private server for your Puppet modules. Compatible with [librarian-puppet](http://librarian-puppet.com).
|
4
4
|
|
5
5
|
[](https://travis-ci.org/drrb/puppet-library)
|
6
6
|
[](https://coveralls.io/r/drrb/puppet-library)
|
7
|
+
[](https://codeclimate.com/github/drrb/puppet-library)
|
7
8
|
|
8
|
-
|
9
|
+
[](http://badge.fury.io/rb/puppet-library)
|
10
|
+
[](https://gemnasium.com/drrb/puppet-library)
|
11
|
+
|
12
|
+
Puppet Library serves Puppet modules in the same format as [the Puppet Forge](http://forge.puppetlabs.com). This allows you to create a private Puppet Forge and manage all the modules you use completely within your infrastructure.
|
13
|
+
|
14
|
+
Plugins can be created to serve modules from arbitrary sources. Puppet Library contains built-in support for:
|
15
|
+
- serving packaged (`.tar.gz`) modules from a directory (or directories) of your choosing
|
16
|
+
- proxying a remote forge (or forges)
|
9
17
|
|
10
18
|
## Installation
|
11
19
|
|
@@ -13,6 +21,12 @@ Install the server as a Gem:
|
|
13
21
|
|
14
22
|
$ gem install puppet-library
|
15
23
|
|
24
|
+
Or, to get the latest, you can install from source
|
25
|
+
|
26
|
+
$ git clone https://github.com/drrb/puppet-library.git
|
27
|
+
$ cd puppet-library
|
28
|
+
$ rake install
|
29
|
+
|
16
30
|
## Getting Started
|
17
31
|
|
18
32
|
Create a module directory and add the modules to it
|
@@ -24,7 +38,7 @@ Create a module directory and add the modules to it
|
|
24
38
|
|
25
39
|
Start the server
|
26
40
|
|
27
|
-
$ puppet-library
|
41
|
+
$ puppet-library --port 9292 --module-dir ./modules
|
28
42
|
|
29
43
|
Point librarian-puppet to the server
|
30
44
|
|
@@ -40,7 +54,7 @@ Resolve and download the modules
|
|
40
54
|
|
41
55
|
## Usage
|
42
56
|
|
43
|
-
Run the server
|
57
|
+
Run the server (proxies the Puppet Forge by default)
|
44
58
|
|
45
59
|
$ puppet-library
|
46
60
|
|
@@ -48,6 +62,10 @@ Serve modules from a specific directory
|
|
48
62
|
|
49
63
|
$ puppet-library --module-dir /var/puppet-modules
|
50
64
|
|
65
|
+
Serve modules from a remote forge as a proxy
|
66
|
+
|
67
|
+
$ puppet-library --proxy http://forge.puppetlabs.com
|
68
|
+
|
51
69
|
Serve modules on a specific port
|
52
70
|
|
53
71
|
$ puppet-library --port 8888
|
@@ -73,7 +91,7 @@ This project was inspired by [dalen/simple-puppet-forge](https://github.com/dale
|
|
73
91
|
## License
|
74
92
|
|
75
93
|
Puppet Library
|
76
|
-
Copyright (C)
|
94
|
+
Copyright (C) 2014 drrb
|
77
95
|
|
78
96
|
This program is free software: you can redistribute it and/or modify
|
79
97
|
it under the terms of the GNU General Public License as published by
|
data/Rakefile
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
2
|
# Puppet Library
|
3
|
-
# Copyright (C)
|
3
|
+
# Copyright (C) 2014 drrb
|
4
4
|
#
|
5
5
|
# This program is free software: you can redistribute it and/or modify
|
6
6
|
# it under the terms of the GNU General Public License as published by
|
@@ -19,14 +19,28 @@ require 'bundler/gem_tasks'
|
|
19
19
|
require 'rspec/core/rake_task'
|
20
20
|
require 'coveralls/rake/task'
|
21
21
|
|
22
|
-
|
22
|
+
if RUBY_VERSION.start_with? "1.8"
|
23
|
+
# The integration test doesn't work on Ruby 1.8.
|
24
|
+
DEFAULT_TEST_TASK = :spec
|
25
|
+
else
|
26
|
+
DEFAULT_TEST_TASK = :test
|
27
|
+
end
|
28
|
+
|
23
29
|
Coveralls::RakeTask.new
|
24
30
|
|
25
|
-
|
31
|
+
desc "Run the specs"
|
32
|
+
RSpec::Core::RakeTask.new(:spec)
|
33
|
+
|
34
|
+
desc "Run all the tests"
|
35
|
+
RSpec::Core::RakeTask.new(:test) do |rspec|
|
36
|
+
rspec.pattern = "{spec,test}/**/*_{spec,integration_test}.rb"
|
37
|
+
end
|
38
|
+
|
39
|
+
task :default => [DEFAULT_TEST_TASK, 'coveralls:push']
|
26
40
|
|
27
41
|
desc "Check it works on all local rubies"
|
28
42
|
task :verify do
|
29
|
-
system "rvm all do rake
|
43
|
+
system "rvm all do rake test"
|
30
44
|
end
|
31
45
|
|
32
46
|
desc "Check all files for license headers"
|
data/TODO.yml
CHANGED
@@ -1,5 +1,16 @@
|
|
1
|
-
|
2
|
-
- Configure embedded server (currently uses the default Rack server)
|
3
|
-
- Proxy another repository
|
1
|
+
features:
|
4
2
|
- Use config from a config file
|
3
|
+
- Allow proxy to cache downloaded modules/API calls on disk
|
4
|
+
- |
|
5
|
+
Accept --cache-dir option to specify a parent cache directory (people
|
6
|
+
will need to embed the server or use a config file for more control)
|
7
|
+
- Validate repo dirs (make sure they're readable)
|
8
|
+
- Allow failover between module repositories
|
5
9
|
- Document usage with Passenger
|
10
|
+
- Web UI
|
11
|
+
- Authentication
|
12
|
+
|
13
|
+
dubious_features:
|
14
|
+
- Make proxy cache TTL configurable
|
15
|
+
- REST API to clear proxy cache
|
16
|
+
- REST API to upload modules
|
data/config.ru
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
2
|
# Puppet Library
|
3
|
-
# Copyright (C)
|
3
|
+
# Copyright (C) 2014 drrb
|
4
4
|
#
|
5
5
|
# This program is free software: you can redistribute it and/or modify
|
6
6
|
# it under the terms of the GNU General Public License as published by
|
@@ -18,5 +18,9 @@
|
|
18
18
|
require 'rubygems'
|
19
19
|
require 'puppet_library'
|
20
20
|
|
21
|
-
PuppetLibrary::Server.
|
22
|
-
|
21
|
+
server = PuppetLibrary::Server.set_up do |library|
|
22
|
+
library.module_repo PuppetLibrary::ModuleRepo::Proxy.new("http://forge.puppetlabs.com")
|
23
|
+
library.module_repo PuppetLibrary::ModuleRepo::Directory.new("/var/lib/modules")
|
24
|
+
end
|
25
|
+
|
26
|
+
run server
|
data/lib/puppet_library.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
2
|
# Puppet Library
|
3
|
-
# Copyright (C)
|
3
|
+
# Copyright (C) 2014 drrb
|
4
4
|
#
|
5
5
|
# This program is free software: you can redistribute it and/or modify
|
6
6
|
# it under the terms of the GNU General Public License as published by
|
@@ -19,7 +19,11 @@ require 'puppet_library/version'
|
|
19
19
|
|
20
20
|
require 'puppet_library/puppet_library'
|
21
21
|
require 'puppet_library/server'
|
22
|
+
require 'puppet_library/http/cache'
|
23
|
+
require 'puppet_library/http/http_client'
|
24
|
+
require 'puppet_library/http/url'
|
22
25
|
require 'puppet_library/module_metadata'
|
23
26
|
require 'puppet_library/module_repo/directory'
|
24
27
|
require 'puppet_library/module_repo/multi'
|
28
|
+
require 'puppet_library/module_repo/proxy'
|
25
29
|
require 'puppet_library/util'
|
@@ -0,0 +1,100 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
# Puppet Library
|
3
|
+
# Copyright (C) 2014 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
|
+
class Array
|
19
|
+
def deep_merge
|
20
|
+
inject({}) do |merged, map|
|
21
|
+
merged.deep_merge(map)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class Hash
|
27
|
+
def deep_merge(other)
|
28
|
+
merge(other) do |key, old_val, new_val|
|
29
|
+
if old_val.instance_of? Array
|
30
|
+
old_val + new_val
|
31
|
+
else
|
32
|
+
new_val
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
module PuppetLibrary
|
39
|
+
class ModuleNotFound < Exception
|
40
|
+
end
|
41
|
+
|
42
|
+
class Forge
|
43
|
+
class Config
|
44
|
+
def initialize(module_repo)
|
45
|
+
@module_repo = module_repo
|
46
|
+
end
|
47
|
+
|
48
|
+
def module_repo(repo)
|
49
|
+
@module_repo.add_repo repo
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.configure(&config_block)
|
54
|
+
module_repo = ModuleRepo::Multi.new
|
55
|
+
yield(Config.new(module_repo))
|
56
|
+
Forge.new(module_repo)
|
57
|
+
end
|
58
|
+
|
59
|
+
def initialize(module_repo)
|
60
|
+
@repo = module_repo
|
61
|
+
end
|
62
|
+
|
63
|
+
def get_module_metadata(author, name)
|
64
|
+
modules = get_metadata(author, name)
|
65
|
+
|
66
|
+
raise ModuleNotFound if modules.empty?
|
67
|
+
|
68
|
+
module_infos = modules.map { |m| m.to_info }
|
69
|
+
module_infos.deep_merge
|
70
|
+
end
|
71
|
+
|
72
|
+
def get_module_metadata_with_dependencies(author, name)
|
73
|
+
full_name = "#{author}/#{name}"
|
74
|
+
|
75
|
+
collect_dependencies_versions(full_name).tap do |versions|
|
76
|
+
raise ModuleNotFound if versions[full_name].empty?
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def collect_dependencies_versions(module_full_name, metadata = {})
|
81
|
+
author, module_name = module_full_name.split "/"
|
82
|
+
module_versions = get_metadata(author, module_name)
|
83
|
+
metadata[module_full_name] = module_versions.map {|v| v.to_version }
|
84
|
+
|
85
|
+
dependencies = module_versions.map {|v| v.dependency_names }.flatten
|
86
|
+
dependencies.each do |dependency|
|
87
|
+
collect_dependencies_versions(dependency, metadata) unless metadata.include? dependency
|
88
|
+
end
|
89
|
+
return metadata
|
90
|
+
end
|
91
|
+
|
92
|
+
def get_module_buffer(author, name, version)
|
93
|
+
@repo.get_module(author, name, version) or raise ModuleNotFound
|
94
|
+
end
|
95
|
+
|
96
|
+
def get_metadata(author, module_name)
|
97
|
+
@repo.get_metadata(author, module_name).map {|metadata| ModuleMetadata.new(metadata)}
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
# Puppet Library
|
3
|
+
# Copyright (C) 2014 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::Http
|
19
|
+
class Cache
|
20
|
+
ARBITRARY_CACHE_TTL_MILLIS = 10 * 1000
|
21
|
+
def initialize(millis_to_live = ARBITRARY_CACHE_TTL_MILLIS)
|
22
|
+
@reaper = Reaper.new(millis_to_live)
|
23
|
+
@cache = {}
|
24
|
+
end
|
25
|
+
|
26
|
+
def get(key)
|
27
|
+
entry = @cache[key]
|
28
|
+
if entry
|
29
|
+
return entry.value unless @reaper.wants_to_kill? entry
|
30
|
+
end
|
31
|
+
|
32
|
+
value = yield
|
33
|
+
@cache[key] = Entry.new(value)
|
34
|
+
return value
|
35
|
+
end
|
36
|
+
|
37
|
+
class Entry
|
38
|
+
attr_accessor :value
|
39
|
+
|
40
|
+
def initialize(value)
|
41
|
+
@birth = Time.now
|
42
|
+
@value = value
|
43
|
+
end
|
44
|
+
|
45
|
+
def age_millis
|
46
|
+
age_seconds = Time.now - @birth
|
47
|
+
age_seconds * 1000
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
class Reaper
|
52
|
+
def initialize(millis_to_live)
|
53
|
+
@millis_to_live = millis_to_live
|
54
|
+
end
|
55
|
+
|
56
|
+
def wants_to_kill?(entry)
|
57
|
+
entry.age_millis > @millis_to_live
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
# Puppet Library
|
3
|
+
# Copyright (C) 2014 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 'open-uri'
|
19
|
+
|
20
|
+
module PuppetLibrary::Http
|
21
|
+
class HttpClient
|
22
|
+
def get(url)
|
23
|
+
open_uri(url).read
|
24
|
+
end
|
25
|
+
|
26
|
+
def download(url)
|
27
|
+
open_uri(url)
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
def open_uri(url)
|
32
|
+
open(url)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
# Puppet Library
|
3
|
+
# Copyright (C) 2014 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::Http
|
19
|
+
class Url
|
20
|
+
def self.normalize(uri_string)
|
21
|
+
unless uri_string =~ /^https?/
|
22
|
+
uri_string = "http://#{uri_string}"
|
23
|
+
end
|
24
|
+
uri_string.sub /\/$/, ""
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
2
|
# Puppet Library
|
3
|
-
# Copyright (C)
|
3
|
+
# Copyright (C) 2014 drrb
|
4
4
|
#
|
5
5
|
# This program is free software: you can redistribute it and/or modify
|
6
6
|
# it under the terms of the GNU General Public License as published by
|
@@ -17,7 +17,6 @@
|
|
17
17
|
|
18
18
|
module PuppetLibrary
|
19
19
|
class ModuleMetadata
|
20
|
-
|
21
20
|
def initialize(metadata)
|
22
21
|
@metadata = metadata
|
23
22
|
end
|
@@ -42,6 +41,10 @@ module PuppetLibrary
|
|
42
41
|
@metadata["dependencies"]
|
43
42
|
end
|
44
43
|
|
44
|
+
def description
|
45
|
+
@metadata["description"]
|
46
|
+
end
|
47
|
+
|
45
48
|
def dependency_names
|
46
49
|
dependencies.map {|d| d["name"]}
|
47
50
|
end
|
@@ -51,7 +54,7 @@ module PuppetLibrary
|
|
51
54
|
"author" => author,
|
52
55
|
"full_name" => full_name,
|
53
56
|
"name" => name,
|
54
|
-
"desc" =>
|
57
|
+
"desc" => description,
|
55
58
|
"releases" => [ { "version" => version } ]
|
56
59
|
}
|
57
60
|
end
|
@@ -60,7 +63,9 @@ module PuppetLibrary
|
|
60
63
|
{
|
61
64
|
"file" => "/modules/#{author}-#{name}-#{version}.tar.gz",
|
62
65
|
"version" => version,
|
63
|
-
|
66
|
+
"dependencies" => dependencies.map do |dependency|
|
67
|
+
[ dependency["name"], dependency["version_requirement"] ]
|
68
|
+
end
|
64
69
|
}
|
65
70
|
end
|
66
71
|
end
|