puppet-forge-server 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,38 @@
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ # Copyright 2014 North Development AB
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ module PuppetForgeServer::Api::V3
18
+ module Releases
19
+ def get_releases(metadata)
20
+ metadata.map do |element|
21
+ name = element[:metadata].name.sub(/^[^-]+-/, '')
22
+
23
+ {
24
+ :uri => "/v3/releases/#{element[:metadata].name}-#{element[:metadata].version}",
25
+ :module => {
26
+ :uri => "/v3/modules/#{element[:metadata].name}",
27
+ :name => name
28
+ },
29
+ :metadata => element[:metadata].to_hash,
30
+ :version => element[:metadata].version,
31
+ :tags => element[:tags] ? element[:tags] : [element[:metadata].author, name],
32
+ :file_uri => "/v3/files#{element[:path]}",
33
+ :file_md5 => element[:checksum]
34
+ }
35
+ end.version_sort_by { |r| r[:version] }.reverse
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,67 @@
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ # Copyright 2014 North Development AB
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ require 'sinatra/base'
18
+ require 'json'
19
+
20
+ module PuppetForgeServer::App
21
+ class Version1 < Sinatra::Base
22
+ include PuppetForgeServer::Api::V1::Releases
23
+ include PuppetForgeServer::Api::V1::Modules
24
+ include PuppetForgeServer::Utils::Buffer
25
+
26
+ def initialize(backends)
27
+ super(nil)
28
+ @backends = backends
29
+ end
30
+
31
+ get '/api/v1/releases.json' do
32
+ unless params[:module]
33
+ halt 400, {'error' => 'The number of version constraints in the query does not match the number of module names'}.to_json
34
+ end
35
+
36
+ author, name = params[:module].split '/'
37
+ version = params[:version] if params[:version]
38
+
39
+ metadata = @backends.map do |backend|
40
+ backend.get_metadata(author, name, {:version => version, :with_checksum => false})
41
+ end.flatten.uniq
42
+
43
+ halt 400, {'errors' => ["'#{params[:module]}' is not a valid module slug"]}.to_json if metadata.empty?
44
+
45
+ {"#{author}/#{name}" => get_releases(metadata)}.to_json
46
+ end
47
+
48
+ get '/api/v1/files/*' do
49
+ captures = params[:captures].first
50
+ buffer = get_buffer(@backends, captures)
51
+
52
+ halt 404, {'errors' => ['404 Not found']}.to_json unless buffer
53
+
54
+ content_type 'application/octet-stream'
55
+ attachment captures.split('/').last
56
+ download buffer
57
+ end
58
+
59
+ get '/modules.json' do
60
+ query = params[:q]
61
+ metadata = @backends.map do |backend|
62
+ backend.query_metadata(query, {:with_checksum => false})
63
+ end.flatten.uniq
64
+ get_modules(metadata).to_json
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,68 @@
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ # Copyright 2014 North Development AB
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ require 'sinatra/base'
18
+
19
+ module PuppetForgeServer::App
20
+ class Version3 < Sinatra::Base
21
+ include PuppetForgeServer::Api::V3::Releases
22
+ include PuppetForgeServer::Api::V3::Modules
23
+ include PuppetForgeServer::Utils::Buffer
24
+
25
+ def initialize(backends)
26
+ super(nil)
27
+ @backends = backends
28
+ end
29
+
30
+ get '/v3/releases' do
31
+ halt 400, {'error' => 'The number of version constraints in the query does not match the number of module names'}.to_json unless params[:module]
32
+
33
+ author, name, version = params[:module].split '-'
34
+ metadata = @backends.map do |backend|
35
+ backend.get_metadata(author, name, {:version => version})
36
+ end.flatten.uniq
37
+
38
+ halt 404, {'pagination' => {'next' => false}, 'results' => []}.to_json if metadata.empty?
39
+ {'pagination' => {'next' => false}, 'results' => get_releases(metadata)}.to_json
40
+ end
41
+
42
+ get '/v3/files/*' do
43
+ captures = params[:captures].first
44
+ buffer = get_buffer(@backends, captures)
45
+
46
+ halt 404, {'errors' => ['404 Not found']}.to_json unless buffer
47
+
48
+ content_type 'application/octet-stream'
49
+ attachment captures.split('/').last
50
+ download buffer
51
+ end
52
+
53
+ get '/v3/modules/:author-:name' do
54
+ author = params[:author]
55
+ name = params[:name]
56
+
57
+ halt 400, {'errors' => "'#{params[:module]}' is not a valid module slug"}.to_json unless author && name
58
+
59
+ metadata = @backends.map do |backend|
60
+ backend.get_metadata(author, name)
61
+ end.flatten.uniq
62
+
63
+ halt 404, {'errors' => ['404 Not found']}.to_json if metadata.empty?
64
+
65
+ get_modules(metadata).to_json
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,67 @@
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ # Copyright 2014 North Development AB
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ require 'digest/md5'
18
+ require 'pathname'
19
+
20
+ module PuppetForgeServer::Backends
21
+ class Directory
22
+ include PuppetForgeServer::Utils::Archiver
23
+
24
+ # Give highest priority to locally hosted modules
25
+ @@PRIORITY = 0
26
+ attr_reader :PRIORITY
27
+
28
+ def initialize(url)
29
+ @module_dir = url
30
+ end
31
+
32
+ def query_metadata(query, options = {})
33
+ get_file_metadata("*#{query}*.tar.gz", options)
34
+ end
35
+
36
+ def get_metadata(author, name, options = {})
37
+ version = options[:version] ? options[:version] : '*'
38
+ get_file_metadata("#{author}-#{name}-#{version}.tar.gz", options)
39
+ end
40
+
41
+ def get_file_buffer(relative_path)
42
+ path = File.join(File.expand_path(@module_dir), relative_path)
43
+ File.open(path, 'r') if File.exist?(path)
44
+ end
45
+
46
+ private
47
+ def read_metadata(archive_path)
48
+ metadata_file = read_entry(archive_path, %r[[^/]+/metadata\.json$])
49
+ JSON.parse(metadata_file)
50
+ rescue => error
51
+ warn "Error reading from module archive #{archive_path}: #{error}"
52
+ return nil
53
+ end
54
+
55
+ def get_file_metadata(file_name, options)
56
+ options = ({:with_checksum => true}).merge(options)
57
+ Dir["#{@module_dir}/**/#{file_name}"].map do |path|
58
+ checksum = Digest::MD5.hexdigest(File.read(path)) if options[:with_checksum] == true
59
+ {
60
+ :metadata => PuppetForgeServer::Models::Metadata.new(read_metadata(path)),
61
+ :checksum => checksum,
62
+ :path => "/#{Pathname.new(path).relative_path_from(Pathname.new(@module_dir))}"
63
+ }
64
+ end.compact
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,63 @@
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ # Copyright 2014 North Development AB
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ require 'json'
18
+ require 'digest/sha1'
19
+
20
+ module PuppetForgeServer::Backends
21
+ class Proxy
22
+
23
+ def initialize(url, cache_dir, http_client)
24
+ @url = url
25
+ @cache_dir = File.join(cache_dir, Digest::SHA1.hexdigest(@url))
26
+ @http_client = http_client
27
+
28
+ # Create directory structure for all alphabetic letters
29
+ (10...36).each do |i|
30
+ FileUtils.mkdir_p(File.join(@cache_dir, i.to_s(36)))
31
+ end
32
+ end
33
+
34
+ def get_file_buffer(relative_path)
35
+ file_name = relative_path.split('/').last
36
+ File.join(@cache_dir, file_name[0], file_name)
37
+ path = Dir["#{@cache_dir}/**/#{file_name}"].first
38
+ unless File.exist?("#{path}")
39
+ buffer = download("/#{relative_path}")
40
+ File.open(File.join(@cache_dir, file_name[0], file_name), 'wb') do |file|
41
+ file.write(buffer.read)
42
+ end
43
+ path = File.join(@cache_dir, file_name[0], file_name)
44
+ end
45
+ File.open(path, 'rb')
46
+ rescue OpenURI::HTTPError
47
+ # ignore
48
+ end
49
+
50
+ protected
51
+ def get(relative_url)
52
+ @http_client.get(url(relative_url))
53
+ end
54
+
55
+ def download(relative_url)
56
+ @http_client.download(url(relative_url))
57
+ end
58
+
59
+ def url(relative_url)
60
+ @url + relative_url
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,69 @@
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ # Copyright 2014 North Development AB
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ require 'json'
18
+ require 'digest/md5'
19
+
20
+ module PuppetForgeServer::Backends
21
+ class ProxyV1 < PuppetForgeServer::Backends::Proxy
22
+
23
+ # Priority should be lower than v3 API proxies as v3 requires less API calls
24
+ @@PRIORITY = 15
25
+ attr_reader :PRIORITY
26
+
27
+ def initialize(url, cache_dir, http_client = PuppetForgeServer::Http::HttpClient.new)
28
+ super(url, cache_dir, http_client)
29
+ end
30
+
31
+ def get_metadata(author, name, options = {})
32
+ options = ({:with_checksum => true}).merge(options)
33
+ query ="#{author}/#{name}"
34
+ get_module_metadata(JSON.parse(get("/modules.json?q=#{query}")).select { |e| e['full_name'].match("#{query}") }, options)
35
+ end
36
+
37
+ def query_metadata(query, options = {})
38
+ options = ({:with_checksum => true}).merge(options)
39
+ get_module_metadata(JSON.parse(get("/modules.json?q=#{query}")).select { |e| e['full_name'].match("*#{query}*") }, options)
40
+ end
41
+
42
+ private
43
+ def read_metadata(element, release)
44
+ element['project_page'] = element['project_url']
45
+ element['name'] = element['full_name'] ? element['full_name'].gsub('/', '-') : element['name']
46
+ element['description'] = element['desc']
47
+ element['version'] = release['version'] ? release['version'] : element['version']
48
+ element['dependencies'] = release['dependencies'] ? release['dependencies'] : []
49
+ %w(project_url full_name releases tag_list desc).each { |key| element.delete(key) }
50
+ element
51
+ end
52
+
53
+ def get_module_metadata(modules, options)
54
+ modules.map do |element|
55
+ version = options['version'] ? "&version=#{options['version']}" : ''
56
+ JSON.parse(get("/api/v1/releases.json?module=#{element['author']}/#{element['name']}#{version}")).values.first.map do |release|
57
+ tags = element['tag_list'] ? element['tag_list'] : nil
58
+ raw_metadata = read_metadata(element, release)
59
+ {
60
+ :metadata => PuppetForgeServer::Models::Metadata.new(raw_metadata),
61
+ :checksum => options[:with_checksum] ? Digest::MD5.hexdigest(File.read(get_file_buffer(release['file']))) : nil,
62
+ :path => "#{release['file']}",
63
+ :tags => tags
64
+ }
65
+ end
66
+ end.compact
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,63 @@
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ # Copyright 2014 North Development AB
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ require 'json'
18
+
19
+ module PuppetForgeServer::Backends
20
+ class ProxyV3 < PuppetForgeServer::Backends::Proxy
21
+
22
+ @@PRIORITY = 10
23
+ attr_reader :PRIORITY
24
+
25
+ def initialize(url, cache_dir, http_client = PuppetForgeServer::Http::HttpClient.new)
26
+ super(url, cache_dir, http_client)
27
+ end
28
+
29
+ def get_metadata(author, name, options = {})
30
+ options = ({:with_checksum => true}).merge(options)
31
+ query ="#{author}-#{name}"
32
+ releases = options[:version] ? [JSON.parse(get("/v3/releases/#{query}-#{options[:version]}"))] : get_all_release_pages("/v3/releases?module=#{query}")
33
+ get_release_metadata(releases)
34
+ end
35
+
36
+ def query_metadata(query, options = {})
37
+ author, name = query.split('-')
38
+ get_metadata(author, name, options) if author && name
39
+ end
40
+
41
+ private
42
+ def get_all_release_pages(next_page)
43
+ releases = []
44
+ begin
45
+ result = JSON.parse(get(next_page))
46
+ releases += result['results']
47
+ next_page = result['pagination']['next']
48
+ end while next_page
49
+ releases
50
+ end
51
+
52
+ def get_release_metadata(releases)
53
+ releases.map do |element|
54
+ {
55
+ :metadata => PuppetForgeServer::Models::Metadata.new(element['metadata']),
56
+ :checksum => element['file_md5'],
57
+ :path => element['file_uri'],
58
+ :tags => element['tags']
59
+ }
60
+ end.compact
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,20 @@
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ # Copyright 2014 North Development AB
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ module PuppetForgeServer::Errors
18
+ class Expected
19
+ end
20
+ end