simple_blobstore_server 1.5.0.pre.1113
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 +0 -0
- data/bin/simple_blobstore_server +32 -0
- data/lib/simple_blobstore_server/version.rb +3 -0
- data/lib/simple_blobstore_server.rb +140 -0
- metadata +84 -0
data/README
ADDED
File without changes
|
@@ -0,0 +1,32 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "simple_blobstore_server"
|
4
|
+
require "thin"
|
5
|
+
|
6
|
+
config_file = nil
|
7
|
+
|
8
|
+
opts = OptionParser.new do |opts|
|
9
|
+
opts.on("-c", "--config [ARG]", "Configuration File") do |opt|
|
10
|
+
config_file = opt
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
opts.parse!(ARGV.dup)
|
15
|
+
|
16
|
+
config_file ||= ::File.expand_path("../../config/simple_blobstore_server.yml", __FILE__)
|
17
|
+
config = Psych.load_file(config_file)
|
18
|
+
|
19
|
+
port = config["port"]
|
20
|
+
raise "Invalid port" unless port.kind_of?(Integer)
|
21
|
+
|
22
|
+
puts "Starting Simple Blobstore server on port: #{port}."
|
23
|
+
|
24
|
+
Thin::Logging.silent = true
|
25
|
+
server = Thin::Server.new('0.0.0.0', port) do
|
26
|
+
use Rack::CommonLogger
|
27
|
+
map "/" do
|
28
|
+
run Bosh::Blobstore::SimpleBlobstoreServer.new(config)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
server.threaded = true
|
32
|
+
server.start!
|
@@ -0,0 +1,140 @@
|
|
1
|
+
require "digest/sha1"
|
2
|
+
require "fileutils"
|
3
|
+
require "set"
|
4
|
+
require "optparse"
|
5
|
+
require "pp"
|
6
|
+
require "yaml"
|
7
|
+
|
8
|
+
require "sinatra"
|
9
|
+
require "securerandom"
|
10
|
+
|
11
|
+
module Bosh
|
12
|
+
module Blobstore
|
13
|
+
class SimpleBlobstoreServer < Sinatra::Base
|
14
|
+
|
15
|
+
BUFFER_SIZE = 16 * 1024
|
16
|
+
|
17
|
+
def initialize(config)
|
18
|
+
super
|
19
|
+
@path = config["path"]
|
20
|
+
@nginx_path = config["nginx_path"]
|
21
|
+
|
22
|
+
if File.exists?(@path)
|
23
|
+
raise "Invalid path" unless File.directory?(@path)
|
24
|
+
else
|
25
|
+
FileUtils.mkdir_p(@path)
|
26
|
+
end
|
27
|
+
|
28
|
+
raise "Invalid user list" unless config["users"].kind_of?(Hash)
|
29
|
+
@users = Set.new
|
30
|
+
config["users"].each do |username, password|
|
31
|
+
@users << [username, password]
|
32
|
+
end
|
33
|
+
raise "Must have at least one user" if @users.empty?
|
34
|
+
end
|
35
|
+
|
36
|
+
def get_file_name(object_id)
|
37
|
+
sha1 = Digest::SHA1.hexdigest(object_id)
|
38
|
+
File.join(@path, sha1[0, 2], object_id)
|
39
|
+
end
|
40
|
+
|
41
|
+
def get_nginx_path(object_id)
|
42
|
+
sha1 = Digest::SHA1.hexdigest(object_id)
|
43
|
+
"#{@nginx_path}/#{sha1[0, 2]}/#{object_id}"
|
44
|
+
end
|
45
|
+
|
46
|
+
def generate_object_id
|
47
|
+
SecureRandom.uuid
|
48
|
+
end
|
49
|
+
|
50
|
+
def protected!
|
51
|
+
unless authorized?
|
52
|
+
response['WWW-Authenticate'] = %(Basic realm="Authenticate")
|
53
|
+
throw(:halt, [401, "Not authorized\n"])
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def authorized?
|
58
|
+
@auth ||= Rack::Auth::Basic::Request.new(request.env)
|
59
|
+
@auth.provided? && @auth.basic? && @auth.credentials && @users.include?(@auth.credentials)
|
60
|
+
end
|
61
|
+
|
62
|
+
def create_file(object_id)
|
63
|
+
object_id ||= generate_object_id
|
64
|
+
file_name = get_file_name(object_id)
|
65
|
+
|
66
|
+
error(409) if File.exist?(file_name)
|
67
|
+
|
68
|
+
FileUtils.mkdir_p(File.dirname(file_name))
|
69
|
+
|
70
|
+
yield file_name
|
71
|
+
|
72
|
+
status(200)
|
73
|
+
content_type(:text)
|
74
|
+
object_id
|
75
|
+
end
|
76
|
+
|
77
|
+
def create(params)
|
78
|
+
if params[:content] && params[:content][:tempfile]
|
79
|
+
# Process uploads coming directly to the simple blobstore
|
80
|
+
create_file(params[:id]) do |file_name|
|
81
|
+
tempfile = params[:content][:tempfile]
|
82
|
+
FileUtils.copy_file(tempfile.path, file_name)
|
83
|
+
end
|
84
|
+
elsif params["content.name"] && params["content.path"]
|
85
|
+
# Process uploads arriving via nginx
|
86
|
+
create_file(params[:id]) do |file_name|
|
87
|
+
FileUtils.mv(params["content.path"], file_name)
|
88
|
+
end
|
89
|
+
else
|
90
|
+
error(400)
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
before do
|
96
|
+
protected!
|
97
|
+
end
|
98
|
+
|
99
|
+
post "/resources/:id" do
|
100
|
+
create(params)
|
101
|
+
end
|
102
|
+
|
103
|
+
post "/resources" do
|
104
|
+
create(params)
|
105
|
+
end
|
106
|
+
|
107
|
+
head "/resources/:id" do
|
108
|
+
file_name = get_file_name(params[:id])
|
109
|
+
File.exists?(file_name) ? status(200) : status(404)
|
110
|
+
end
|
111
|
+
|
112
|
+
get "/resources/:id" do
|
113
|
+
file_name = get_file_name(params[:id])
|
114
|
+
if File.exist?(file_name)
|
115
|
+
if @nginx_path
|
116
|
+
status(200)
|
117
|
+
content_type "application/octet-stream"
|
118
|
+
response["X-Accel-Redirect"] = get_nginx_path(params[:id])
|
119
|
+
nil
|
120
|
+
else
|
121
|
+
send_file(file_name)
|
122
|
+
end
|
123
|
+
else
|
124
|
+
error(404)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
delete "/resources/:id" do
|
129
|
+
file_name = get_file_name(params[:id])
|
130
|
+
if File.exist?(file_name)
|
131
|
+
status(204)
|
132
|
+
FileUtils.rm(file_name)
|
133
|
+
else
|
134
|
+
error(404)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
metadata
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: simple_blobstore_server
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.5.0.pre.1113
|
5
|
+
prerelease: 6
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- VMware
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-10-16 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: thin
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 1.5.0
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 1.5.0
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: sinatra
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 1.4.2
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 1.4.2
|
46
|
+
description: ! 'BOSH Simple Blobstore Server
|
47
|
+
|
48
|
+
cfd471'
|
49
|
+
email: support@cloudfoundry.com
|
50
|
+
executables:
|
51
|
+
- simple_blobstore_server
|
52
|
+
extensions: []
|
53
|
+
extra_rdoc_files: []
|
54
|
+
files:
|
55
|
+
- lib/simple_blobstore_server.rb
|
56
|
+
- lib/simple_blobstore_server/version.rb
|
57
|
+
- README
|
58
|
+
- bin/simple_blobstore_server
|
59
|
+
homepage: https://github.com/cloudfoundry/bosh
|
60
|
+
licenses:
|
61
|
+
- Apache 2.0
|
62
|
+
post_install_message:
|
63
|
+
rdoc_options: []
|
64
|
+
require_paths:
|
65
|
+
- lib
|
66
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
67
|
+
none: false
|
68
|
+
requirements:
|
69
|
+
- - ! '>='
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: 1.9.3
|
72
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>'
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 1.3.1
|
78
|
+
requirements: []
|
79
|
+
rubyforge_project:
|
80
|
+
rubygems_version: 1.8.23
|
81
|
+
signing_key:
|
82
|
+
specification_version: 3
|
83
|
+
summary: BOSH Simple Blobstore Server
|
84
|
+
test_files: []
|