bosh_openstack_registry 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 +3 -0
- data/Rakefile +50 -0
- data/bin/migrate +41 -0
- data/bin/openstack_registry +38 -0
- data/lib/openstack_registry/api_controller.rb +67 -0
- data/lib/openstack_registry/config.rb +81 -0
- data/lib/openstack_registry/errors.rb +20 -0
- data/lib/openstack_registry/models/openstack_server.rb +12 -0
- data/lib/openstack_registry/models.rb +8 -0
- data/lib/openstack_registry/runner.rb +56 -0
- data/lib/openstack_registry/server_manager.rb +52 -0
- data/lib/openstack_registry/version.rb +7 -0
- data/lib/openstack_registry/yaml_helper.rb +24 -0
- data/lib/openstack_registry.rb +25 -0
- data/spec/assets/sample_config.yml +18 -0
- data/spec/spec_helper.rb +114 -0
- data/spec/unit/api_controller_spec.rb +74 -0
- data/spec/unit/config_spec.rb +56 -0
- data/spec/unit/runner_spec.rb +82 -0
- data/spec/unit/server_manager_spec.rb +69 -0
- metadata +157 -0
data/README
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
# Copyright (c) 2009-2012 VMware, Inc.
|
2
|
+
|
3
|
+
$:.unshift(File.expand_path("../../rake", __FILE__))
|
4
|
+
|
5
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __FILE__)
|
6
|
+
|
7
|
+
require "rubygems"
|
8
|
+
require "bundler"
|
9
|
+
Bundler.setup(:default, :test)
|
10
|
+
|
11
|
+
require "rake"
|
12
|
+
begin
|
13
|
+
require "rspec/core/rake_task"
|
14
|
+
rescue LoadError
|
15
|
+
end
|
16
|
+
|
17
|
+
require "bundler_task"
|
18
|
+
require "ci_task"
|
19
|
+
|
20
|
+
gem_helper = Bundler::GemHelper.new(Dir.pwd)
|
21
|
+
|
22
|
+
desc "Build OpenStack Registry gem into the pkg directory"
|
23
|
+
task "build" do
|
24
|
+
gem_helper.build_gem
|
25
|
+
end
|
26
|
+
|
27
|
+
desc "Build and install OpenStack Registry into system gems"
|
28
|
+
task "install" do
|
29
|
+
Rake::Task["bundler:install"].invoke
|
30
|
+
gem_helper.install_gem
|
31
|
+
end
|
32
|
+
|
33
|
+
BundlerTask.new
|
34
|
+
|
35
|
+
if defined?(RSpec)
|
36
|
+
namespace :spec do
|
37
|
+
desc "Run Unit Tests"
|
38
|
+
rspec_task = RSpec::Core::RakeTask.new(:unit) do |t|
|
39
|
+
t.pattern = "spec/unit/**/*_spec.rb"
|
40
|
+
t.rspec_opts = %w(--format progress --colour)
|
41
|
+
end
|
42
|
+
|
43
|
+
CiTask.new do |task|
|
44
|
+
task.rspec_task = rspec_task
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
desc "Run tests"
|
49
|
+
task :spec => %w(spec:unit)
|
50
|
+
end
|
data/bin/migrate
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
ENV["BUNDLE_GEMFILE"] = File.expand_path("../../Gemfile", __FILE__)
|
4
|
+
|
5
|
+
require "rubygems"
|
6
|
+
require "bundler/setup"
|
7
|
+
require "logger"
|
8
|
+
require "sequel"
|
9
|
+
|
10
|
+
$:.unshift(File.dirname(__FILE__) + "/../lib")
|
11
|
+
|
12
|
+
require "openstack_registry"
|
13
|
+
|
14
|
+
config_file = nil
|
15
|
+
|
16
|
+
opts = OptionParser.new do |opts|
|
17
|
+
opts.on("-c", "--config FILE", "configuration file") do |opt|
|
18
|
+
config_file = opt
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
opts.parse!(ARGV.dup)
|
23
|
+
|
24
|
+
if config_file.nil?
|
25
|
+
puts opts
|
26
|
+
exit 1
|
27
|
+
end
|
28
|
+
|
29
|
+
include Bosh::OpenstackRegistry::YamlHelper
|
30
|
+
|
31
|
+
config = load_yaml_file(config_file)
|
32
|
+
|
33
|
+
db = Bosh::OpenstackRegistry.connect_db(config["db"])
|
34
|
+
migrations_dir = File.expand_path("../../db/migrations", __FILE__)
|
35
|
+
|
36
|
+
options = {
|
37
|
+
:table => "openstack_registry_schema"
|
38
|
+
}
|
39
|
+
|
40
|
+
Sequel.extension :migration
|
41
|
+
Sequel::TimestampMigrator.run(db, migrations_dir, options)
|
@@ -0,0 +1,38 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
gemfile = File.expand_path("../../Gemfile", __FILE__)
|
4
|
+
|
5
|
+
if File.exists?(gemfile)
|
6
|
+
ENV["BUNDLE_GEMFILE"] = gemfile
|
7
|
+
require "rubygems"
|
8
|
+
require "bundler/setup"
|
9
|
+
end
|
10
|
+
|
11
|
+
$:.unshift(File.expand_path("../../lib", __FILE__))
|
12
|
+
|
13
|
+
require "openstack_registry"
|
14
|
+
require "optparse"
|
15
|
+
|
16
|
+
config_file = nil
|
17
|
+
|
18
|
+
opts = OptionParser.new do |opts|
|
19
|
+
opts.on("-c", "--config FILE", "configuration file") do |opt|
|
20
|
+
config_file = opt
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
opts.parse!(ARGV.dup)
|
25
|
+
|
26
|
+
if config_file.nil?
|
27
|
+
puts opts
|
28
|
+
exit 1
|
29
|
+
end
|
30
|
+
|
31
|
+
runner = Bosh::OpenstackRegistry::Runner.new(config_file)
|
32
|
+
|
33
|
+
Signal.trap("INT") do
|
34
|
+
runner.stop
|
35
|
+
exit(1)
|
36
|
+
end
|
37
|
+
|
38
|
+
runner.run
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# Copyright (c) 2009-2012 VMware, Inc.
|
2
|
+
|
3
|
+
module Bosh::OpenstackRegistry
|
4
|
+
|
5
|
+
class ApiController < Sinatra::Base
|
6
|
+
|
7
|
+
not_found do
|
8
|
+
json(:status => "not_found")
|
9
|
+
end
|
10
|
+
|
11
|
+
error do
|
12
|
+
exception = request.env["sinatra.error"]
|
13
|
+
@logger.error(exception)
|
14
|
+
status(500)
|
15
|
+
json(:status => "error")
|
16
|
+
end
|
17
|
+
|
18
|
+
get "/servers/:server_id/settings" do
|
19
|
+
ip_check = authorized? ? nil : request.ip
|
20
|
+
settings = @server_manager.read_settings(params[:server_id])
|
21
|
+
json(:status => "ok", :settings => settings)
|
22
|
+
end
|
23
|
+
|
24
|
+
put "/servers/:server_id/settings" do
|
25
|
+
protected!
|
26
|
+
@server_manager.update_settings(params[:server_id], request.body.read)
|
27
|
+
json(:status => "ok")
|
28
|
+
end
|
29
|
+
|
30
|
+
delete "/servers/:server_id/settings" do
|
31
|
+
protected!
|
32
|
+
@server_manager.delete_settings(params[:server_id])
|
33
|
+
json(:status => "ok")
|
34
|
+
end
|
35
|
+
|
36
|
+
def initialize
|
37
|
+
super
|
38
|
+
@logger = Bosh::OpenstackRegistry.logger
|
39
|
+
|
40
|
+
@users = Set.new
|
41
|
+
@users << [Bosh::OpenstackRegistry.http_user,
|
42
|
+
Bosh::OpenstackRegistry.http_password]
|
43
|
+
@server_manager = ServerManager.new
|
44
|
+
end
|
45
|
+
|
46
|
+
def protected!
|
47
|
+
unless authorized?
|
48
|
+
headers("WWW-Authenticate" => 'Basic realm="OpenStack Registry"')
|
49
|
+
halt(401, json("status" => "access_denied"))
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def authorized?
|
54
|
+
@auth ||= Rack::Auth::Basic::Request.new(request.env)
|
55
|
+
@auth.provided? &&
|
56
|
+
@auth.basic? &&
|
57
|
+
@auth.credentials &&
|
58
|
+
@users.include?(@auth.credentials)
|
59
|
+
end
|
60
|
+
|
61
|
+
def json(payload)
|
62
|
+
Yajl::Encoder.encode(payload)
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# Copyright (c) 2009-2012 VMware, Inc.
|
2
|
+
|
3
|
+
module Bosh::OpenstackRegistry
|
4
|
+
|
5
|
+
class << self
|
6
|
+
|
7
|
+
attr_accessor :logger
|
8
|
+
attr_accessor :http_port
|
9
|
+
attr_accessor :http_user
|
10
|
+
attr_accessor :http_password
|
11
|
+
attr_accessor :db
|
12
|
+
|
13
|
+
attr_writer :openstack
|
14
|
+
|
15
|
+
def configure(config)
|
16
|
+
validate_config(config)
|
17
|
+
|
18
|
+
@logger ||= Logger.new(config["logfile"] || STDOUT)
|
19
|
+
|
20
|
+
if config["loglevel"].kind_of?(String)
|
21
|
+
@logger.level = Logger.const_get(config["loglevel"].upcase)
|
22
|
+
end
|
23
|
+
|
24
|
+
@http_port = config["http"]["port"]
|
25
|
+
@http_user = config["http"]["user"]
|
26
|
+
@http_password = config["http"]["password"]
|
27
|
+
|
28
|
+
@openstack_properties = config["openstack"]
|
29
|
+
|
30
|
+
@openstack_options = {
|
31
|
+
:provider => "OpenStack",
|
32
|
+
:openstack_auth_url => @openstack_properties["auth_url"],
|
33
|
+
:openstack_username => @openstack_properties["username"],
|
34
|
+
:openstack_api_key => @openstack_properties["api_key"],
|
35
|
+
:openstack_tenant => @openstack_properties["tenant"]
|
36
|
+
}
|
37
|
+
|
38
|
+
@db = connect_db(config["db"])
|
39
|
+
end
|
40
|
+
|
41
|
+
def openstack
|
42
|
+
openstack ||= Fog::Compute.new(@openstack_options)
|
43
|
+
end
|
44
|
+
|
45
|
+
def connect_db(db_config)
|
46
|
+
connection_options = {
|
47
|
+
:max_connections => db_config["max_connections"],
|
48
|
+
:pool_timeout => db_config["pool_timeout"]
|
49
|
+
}
|
50
|
+
|
51
|
+
db = Sequel.connect(db_config["database"], connection_options)
|
52
|
+
db.logger = @logger
|
53
|
+
db.sql_log_level = :debug
|
54
|
+
db
|
55
|
+
end
|
56
|
+
|
57
|
+
def validate_config(config)
|
58
|
+
unless config.is_a?(Hash)
|
59
|
+
raise ConfigError, "Invalid config format, Hash expected, " \
|
60
|
+
"#{config.class} given"
|
61
|
+
end
|
62
|
+
|
63
|
+
unless config.has_key?("http") && config["http"].is_a?(Hash)
|
64
|
+
raise ConfigError, "HTTP configuration is missing from " \
|
65
|
+
"config file"
|
66
|
+
end
|
67
|
+
|
68
|
+
unless config.has_key?("db") && config["db"].is_a?(Hash)
|
69
|
+
raise ConfigError, "Database configuration is missing from " \
|
70
|
+
"config file"
|
71
|
+
end
|
72
|
+
|
73
|
+
unless config.has_key?("openstack") && config["openstack"].is_a?(Hash)
|
74
|
+
raise ConfigError, "OpenStack configuration is missing from " \
|
75
|
+
"config file"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# Copyright (c) 2009-2012 VMware, Inc.
|
2
|
+
|
3
|
+
module Bosh::OpenstackRegistry
|
4
|
+
|
5
|
+
class Error < StandardError
|
6
|
+
def self.code(code = 500)
|
7
|
+
define_method(:code) { code }
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class FatalError < Error; end
|
12
|
+
|
13
|
+
class ConfigError < Error; end
|
14
|
+
class ConnectionError < Error; end
|
15
|
+
|
16
|
+
class OpenstackError < Error; end
|
17
|
+
|
18
|
+
class ServerError < Error; end
|
19
|
+
class ServerNotFound < Error; code(404); end
|
20
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# Copyright (c) 2009-2012 VMware, Inc.
|
2
|
+
|
3
|
+
module Bosh::OpenstackRegistry
|
4
|
+
class Runner
|
5
|
+
include YamlHelper
|
6
|
+
|
7
|
+
def initialize(config_file)
|
8
|
+
Bosh::OpenstackRegistry.configure(load_yaml_file(config_file))
|
9
|
+
|
10
|
+
@logger = Bosh::OpenstackRegistry.logger
|
11
|
+
@http_port = Bosh::OpenstackRegistry.http_port
|
12
|
+
@http_user = Bosh::OpenstackRegistry.http_user
|
13
|
+
@http_password = Bosh::OpenstackRegistry.http_password
|
14
|
+
end
|
15
|
+
|
16
|
+
def run
|
17
|
+
@logger.info("BOSH OpenStack Registry starting...")
|
18
|
+
EM.kqueue if EM.kqueue?
|
19
|
+
EM.epoll if EM.epoll?
|
20
|
+
|
21
|
+
EM.error_handler { |e| handle_em_error(e) }
|
22
|
+
|
23
|
+
EM.run do
|
24
|
+
start_http_server
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def stop
|
29
|
+
@logger.info("BOSH OpenStack Registry shutting down...")
|
30
|
+
@http_server.stop! if @http_server
|
31
|
+
EM.stop
|
32
|
+
end
|
33
|
+
|
34
|
+
def start_http_server
|
35
|
+
@logger.info "HTTP server is starting on port #{@http_port}..."
|
36
|
+
@http_server = Thin::Server.new("0.0.0.0", @http_port, :signals => false) do
|
37
|
+
Thin::Logging.silent = true
|
38
|
+
map "/" do
|
39
|
+
run Bosh::OpenstackRegistry::ApiController.new
|
40
|
+
end
|
41
|
+
end
|
42
|
+
@http_server.start!
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def handle_em_error(e)
|
48
|
+
@logger.send(level, e.to_s)
|
49
|
+
if e.respond_to?(:backtrace) && e.backtrace.respond_to?(:join)
|
50
|
+
@logger.send(level, e.backtrace.join("\n"))
|
51
|
+
end
|
52
|
+
stop
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# Copyright (c) 2009-2012 VMware, Inc.
|
2
|
+
|
3
|
+
module Bosh::OpenstackRegistry
|
4
|
+
|
5
|
+
class ServerManager
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@logger = Bosh::OpenstackRegistry.logger
|
9
|
+
@openstack = Bosh::OpenstackRegistry.openstack
|
10
|
+
end
|
11
|
+
|
12
|
+
##
|
13
|
+
# Updates server settings
|
14
|
+
# @param [String] server_id OpenStack server id (server record
|
15
|
+
# will be created in DB if it doesn't already exist)
|
16
|
+
# @param [String] settings New settings for the server
|
17
|
+
def update_settings(server_id, settings)
|
18
|
+
params = {
|
19
|
+
:server_id => server_id
|
20
|
+
}
|
21
|
+
|
22
|
+
server = Models::OpenstackServer[params] || Models::OpenstackServer.new(params)
|
23
|
+
server.settings = settings
|
24
|
+
server.save
|
25
|
+
end
|
26
|
+
|
27
|
+
##
|
28
|
+
# Reads server settings
|
29
|
+
# @param [String] server_id OpenStack server id
|
30
|
+
def read_settings(server_id)
|
31
|
+
get_server(server_id).settings
|
32
|
+
end
|
33
|
+
|
34
|
+
def delete_settings(server_id)
|
35
|
+
get_server(server_id).destroy
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def get_server(server_id)
|
41
|
+
server = Models::OpenstackServer[:server_id => server_id]
|
42
|
+
|
43
|
+
if server.nil?
|
44
|
+
raise ServerNotFound, "Can't find server `#{server_id}'"
|
45
|
+
end
|
46
|
+
|
47
|
+
server
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# Copyright (c) 2009-2012 VMware, Inc.
|
2
|
+
|
3
|
+
module Bosh::OpenstackRegistry
|
4
|
+
module YamlHelper
|
5
|
+
|
6
|
+
def load_yaml_file(path, expected_type = Hash)
|
7
|
+
unless File.exists?(path)
|
8
|
+
raise(ConfigError, "Cannot find file `#{path}'")
|
9
|
+
end
|
10
|
+
|
11
|
+
yaml = YAML.load_file(path)
|
12
|
+
|
13
|
+
if expected_type && !yaml.is_a?(expected_type)
|
14
|
+
raise ConfigError, "Incorrect file format in `#{path}', " \
|
15
|
+
"#{expected_type} expected"
|
16
|
+
end
|
17
|
+
|
18
|
+
yaml
|
19
|
+
rescue SystemCallError => e
|
20
|
+
raise ConfigError, "Cannot load YAML file at `#{path}': #{e}"
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# Copyright (c) 2009-2012 VMware, Inc.
|
2
|
+
|
3
|
+
module Bosh
|
4
|
+
module OpenstackRegistry
|
5
|
+
autoload :Models, "openstack_registry/models"
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
require "fog"
|
10
|
+
require "logger"
|
11
|
+
require "sequel"
|
12
|
+
require "sinatra/base"
|
13
|
+
require "thin"
|
14
|
+
require "yajl"
|
15
|
+
|
16
|
+
require "openstack_registry/yaml_helper"
|
17
|
+
|
18
|
+
require "openstack_registry/api_controller"
|
19
|
+
require "openstack_registry/config"
|
20
|
+
require "openstack_registry/errors"
|
21
|
+
require "openstack_registry/server_manager"
|
22
|
+
require "openstack_registry/runner"
|
23
|
+
require "openstack_registry/version"
|
24
|
+
|
25
|
+
Sequel::Model.plugin :validation_helpers
|
@@ -0,0 +1,18 @@
|
|
1
|
+
---
|
2
|
+
loglevel: debug
|
3
|
+
|
4
|
+
http:
|
5
|
+
port: 25695
|
6
|
+
user: admin
|
7
|
+
password: admin
|
8
|
+
|
9
|
+
db:
|
10
|
+
database: "sqlite:///:memory:"
|
11
|
+
max_connections: 32
|
12
|
+
pool_timeout: 10
|
13
|
+
|
14
|
+
openstack:
|
15
|
+
auth_url: "http://127.0.0.1:5000/v2.0/tokens"
|
16
|
+
username: foo
|
17
|
+
api_key: bar
|
18
|
+
tenant: foo
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
# Copyright (c) 2009-2012 VMware, Inc.
|
2
|
+
|
3
|
+
$:.unshift(File.expand_path("../../lib", __FILE__))
|
4
|
+
|
5
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", __FILE__)
|
6
|
+
|
7
|
+
require "rubygems"
|
8
|
+
require "bundler"
|
9
|
+
Bundler.setup(:default, :test)
|
10
|
+
|
11
|
+
require "fileutils"
|
12
|
+
require "logger"
|
13
|
+
require "tmpdir"
|
14
|
+
|
15
|
+
require "rspec"
|
16
|
+
require "rack/test"
|
17
|
+
|
18
|
+
module SpecHelper
|
19
|
+
class << self
|
20
|
+
attr_accessor :logger
|
21
|
+
attr_accessor :temp_dir
|
22
|
+
|
23
|
+
def init
|
24
|
+
ENV["RACK_ENV"] = "test"
|
25
|
+
configure_logging
|
26
|
+
configure_temp_dir
|
27
|
+
|
28
|
+
require "openstack_registry"
|
29
|
+
init_database
|
30
|
+
end
|
31
|
+
|
32
|
+
def configure_logging
|
33
|
+
if ENV["DEBUG"]
|
34
|
+
@logger = Logger.new(STDOUT)
|
35
|
+
else
|
36
|
+
path = File.expand_path("../spec.log", __FILE__)
|
37
|
+
log_file = File.open(path, "w")
|
38
|
+
log_file.sync = true
|
39
|
+
@logger = Logger.new(log_file)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def configure_temp_dir
|
44
|
+
@temp_dir = Dir.mktmpdir
|
45
|
+
ENV["TMPDIR"] = @temp_dir
|
46
|
+
FileUtils.mkdir_p(@temp_dir)
|
47
|
+
at_exit { FileUtils.rm_rf(@temp_dir) }
|
48
|
+
end
|
49
|
+
|
50
|
+
def init_database
|
51
|
+
@migrations_dir = File.expand_path("../../db/migrations", __FILE__)
|
52
|
+
|
53
|
+
Sequel.extension :migration
|
54
|
+
|
55
|
+
@db = Sequel.sqlite(:database => nil, :max_connections => 32, :pool_timeout => 10)
|
56
|
+
@db.loggers << @logger
|
57
|
+
Bosh::OpenstackRegistry.db = @db
|
58
|
+
|
59
|
+
run_migrations
|
60
|
+
end
|
61
|
+
|
62
|
+
def run_migrations
|
63
|
+
Sequel::Migrator.apply(@db, @migrations_dir, nil)
|
64
|
+
end
|
65
|
+
|
66
|
+
def reset_database
|
67
|
+
@db.execute("PRAGMA foreign_keys = OFF")
|
68
|
+
@db.tables.each do |table|
|
69
|
+
@db.drop_table(table)
|
70
|
+
end
|
71
|
+
@db.execute("PRAGMA foreign_keys = ON")
|
72
|
+
end
|
73
|
+
|
74
|
+
def reset
|
75
|
+
reset_database
|
76
|
+
run_migrations
|
77
|
+
|
78
|
+
Bosh::OpenstackRegistry.db = @db
|
79
|
+
Bosh::OpenstackRegistry.logger = @logger
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
SpecHelper.init
|
85
|
+
|
86
|
+
def valid_config
|
87
|
+
{
|
88
|
+
"logfile" => nil,
|
89
|
+
"loglevel" => "debug",
|
90
|
+
"http" => {
|
91
|
+
"user" => "admin",
|
92
|
+
"password" => "admin",
|
93
|
+
"port" => 25777
|
94
|
+
},
|
95
|
+
"db" => {
|
96
|
+
"max_connections" => 433,
|
97
|
+
"pool_timeout" => 227,
|
98
|
+
"database" => "sqlite:///:memory:"
|
99
|
+
},
|
100
|
+
"openstack" => {
|
101
|
+
"auth_url" => "http://127.0.0.1:5000/v2.0/tokens",
|
102
|
+
"username" => "foo",
|
103
|
+
"api_key" => "bar",
|
104
|
+
"tenant" => "foo"
|
105
|
+
}
|
106
|
+
}
|
107
|
+
end
|
108
|
+
|
109
|
+
RSpec.configure do |rspec|
|
110
|
+
rspec.before(:each) do
|
111
|
+
SpecHelper.reset
|
112
|
+
Bosh::OpenstackRegistry.logger = Logger.new(StringIO.new)
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# Copyright (c) 2009-2012 VMware, Inc.
|
2
|
+
|
3
|
+
require File.expand_path("../../spec_helper", __FILE__)
|
4
|
+
|
5
|
+
describe Bosh::OpenstackRegistry::ApiController do
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
Bosh::OpenstackRegistry.http_user = "admin"
|
9
|
+
Bosh::OpenstackRegistry.http_password = "admin"
|
10
|
+
|
11
|
+
@server_manager = mock("server manager")
|
12
|
+
Bosh::OpenstackRegistry::ServerManager.stub!(:new).and_return(@server_manager)
|
13
|
+
|
14
|
+
rack_mock = Rack::MockSession.new(Bosh::OpenstackRegistry::ApiController.new)
|
15
|
+
@session = Rack::Test::Session.new(rack_mock)
|
16
|
+
end
|
17
|
+
|
18
|
+
def expect_json_response(response, status, body)
|
19
|
+
response.status.should == status
|
20
|
+
Yajl::Parser.parse(response.body).should == body
|
21
|
+
end
|
22
|
+
|
23
|
+
it "returns settings for given OpenStack server (IP check)" do
|
24
|
+
@server_manager.should_receive(:read_settings).
|
25
|
+
with("foo").and_return("bar")
|
26
|
+
|
27
|
+
@session.get("/servers/foo/settings")
|
28
|
+
|
29
|
+
expect_json_response(@session.last_response, 200,
|
30
|
+
{ "status" => "ok", "settings" => "bar" })
|
31
|
+
end
|
32
|
+
|
33
|
+
it "returns settings (authorized user, no IP check)" do
|
34
|
+
@server_manager.should_receive(:read_settings).
|
35
|
+
with("foo").and_return("bar")
|
36
|
+
|
37
|
+
@session.basic_authorize("admin", "admin")
|
38
|
+
@session.get("/servers/foo/settings")
|
39
|
+
|
40
|
+
expect_json_response(@session.last_response, 200,
|
41
|
+
{ "status" => "ok", "settings" => "bar" })
|
42
|
+
end
|
43
|
+
|
44
|
+
it "updates settings" do
|
45
|
+
@session.put("/servers/foo/settings", {}, { :input => "bar" })
|
46
|
+
expect_json_response(@session.last_response, 401,
|
47
|
+
{ "status" => "access_denied" })
|
48
|
+
|
49
|
+
@server_manager.should_receive(:update_settings).
|
50
|
+
with("foo", "bar").and_return(true)
|
51
|
+
|
52
|
+
@session.basic_authorize("admin", "admin")
|
53
|
+
@session.put("/servers/foo/settings", {}, { :input => "bar" })
|
54
|
+
|
55
|
+
expect_json_response(@session.last_response, 200,
|
56
|
+
{ "status" => "ok" })
|
57
|
+
end
|
58
|
+
|
59
|
+
it "deletes settings" do
|
60
|
+
@session.delete("/servers/foo/settings")
|
61
|
+
expect_json_response(@session.last_response, 401,
|
62
|
+
{ "status" => "access_denied" })
|
63
|
+
|
64
|
+
@server_manager.should_receive(:delete_settings).
|
65
|
+
with("foo").and_return(true)
|
66
|
+
|
67
|
+
@session.basic_authorize("admin", "admin")
|
68
|
+
@session.delete("/servers/foo/settings")
|
69
|
+
|
70
|
+
expect_json_response(@session.last_response, 200,
|
71
|
+
{ "status" => "ok" })
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# Copyright (c) 2009-2012 VMware, Inc.
|
2
|
+
|
3
|
+
require File.expand_path("../../spec_helper", __FILE__)
|
4
|
+
|
5
|
+
describe Bosh::OpenstackRegistry do
|
6
|
+
|
7
|
+
describe "configuring OpenStack registry" do
|
8
|
+
it "reads provided configuration file and sets singletons" do
|
9
|
+
Bosh::OpenstackRegistry.configure(valid_config)
|
10
|
+
|
11
|
+
logger = Bosh::OpenstackRegistry.logger
|
12
|
+
|
13
|
+
logger.should be_kind_of(Logger)
|
14
|
+
logger.level.should == Logger::DEBUG
|
15
|
+
|
16
|
+
Bosh::OpenstackRegistry.http_port.should == 25777
|
17
|
+
Bosh::OpenstackRegistry.http_user.should == "admin"
|
18
|
+
Bosh::OpenstackRegistry.http_password.should == "admin"
|
19
|
+
|
20
|
+
db = Bosh::OpenstackRegistry.db
|
21
|
+
db.should be_kind_of(Sequel::SQLite::Database)
|
22
|
+
db.opts[:database].should == "/:memory:"
|
23
|
+
db.opts[:max_connections].should == 433
|
24
|
+
db.opts[:pool_timeout].should == 227
|
25
|
+
end
|
26
|
+
|
27
|
+
it "validates configuration file" do
|
28
|
+
expect {
|
29
|
+
Bosh::OpenstackRegistry.configure("foobar")
|
30
|
+
}.to raise_error(Bosh::OpenstackRegistry::ConfigError,
|
31
|
+
/Invalid config format/)
|
32
|
+
|
33
|
+
config = valid_config.merge("http" => nil)
|
34
|
+
|
35
|
+
expect {
|
36
|
+
Bosh::OpenstackRegistry.configure(config)
|
37
|
+
}.to raise_error(Bosh::OpenstackRegistry::ConfigError,
|
38
|
+
/HTTP configuration is missing/)
|
39
|
+
|
40
|
+
config = valid_config.merge("db" => nil)
|
41
|
+
|
42
|
+
expect {
|
43
|
+
Bosh::OpenstackRegistry.configure(config)
|
44
|
+
}.to raise_error(Bosh::OpenstackRegistry::ConfigError,
|
45
|
+
/Database configuration is missing/)
|
46
|
+
|
47
|
+
config = valid_config.merge("openstack" => nil)
|
48
|
+
|
49
|
+
expect {
|
50
|
+
Bosh::OpenstackRegistry.configure(config)
|
51
|
+
}.to raise_error(Bosh::OpenstackRegistry::ConfigError,
|
52
|
+
/OpenStack configuration is missing/)
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# Copyright (c) 2009-2012 VMware, Inc.
|
2
|
+
|
3
|
+
require File.expand_path("../../spec_helper", __FILE__)
|
4
|
+
|
5
|
+
describe Bosh::OpenstackRegistry::Runner do
|
6
|
+
|
7
|
+
def make_runner(config_file)
|
8
|
+
Bosh::OpenstackRegistry::Runner.new(config_file)
|
9
|
+
end
|
10
|
+
|
11
|
+
def write_config(file, config)
|
12
|
+
File.open(file, "w") do |f|
|
13
|
+
YAML.dump(config, f)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "initializing" do
|
18
|
+
it "configures OpenStack registry using provided file" do
|
19
|
+
config_file = Tempfile.new("config")
|
20
|
+
config = { "key" => "value" }
|
21
|
+
write_config(config_file.path, config)
|
22
|
+
|
23
|
+
Bosh::OpenstackRegistry.should_receive(:configure).with(config)
|
24
|
+
make_runner(config_file.path)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "fails if config file not found" do
|
28
|
+
expect {
|
29
|
+
make_runner("foo")
|
30
|
+
}.to raise_error(Bosh::OpenstackRegistry::ConfigError, "Cannot find file `foo'")
|
31
|
+
end
|
32
|
+
|
33
|
+
it "fails when config file has incorrect format" do
|
34
|
+
config_file = Tempfile.new("config")
|
35
|
+
config = "foo"
|
36
|
+
write_config(config_file.path, config)
|
37
|
+
|
38
|
+
expect {
|
39
|
+
make_runner(config_file.path)
|
40
|
+
}.to raise_error(Bosh::OpenstackRegistry::ConfigError, /Incorrect file format/)
|
41
|
+
end
|
42
|
+
|
43
|
+
it "fails when some syscall fails" do
|
44
|
+
config_file = Tempfile.new("config")
|
45
|
+
write_config(config_file.path, { "foo" => "bar" })
|
46
|
+
|
47
|
+
YAML.stub!(:load_file).and_raise(SystemCallError.new("baz"))
|
48
|
+
|
49
|
+
expect {
|
50
|
+
make_runner(config_file.path)
|
51
|
+
}.to raise_error(Bosh::OpenstackRegistry::ConfigError, /baz/)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe "running/stopping" do
|
56
|
+
before(:each) do
|
57
|
+
@config_file = Tempfile.new("config")
|
58
|
+
write_config(@config_file.path, valid_config)
|
59
|
+
end
|
60
|
+
|
61
|
+
it "spins up/shuts down reactor and HTTP server" do
|
62
|
+
runner = make_runner(@config_file)
|
63
|
+
mock_thin = mock("thin")
|
64
|
+
|
65
|
+
EM.should_receive(:run).and_yield
|
66
|
+
|
67
|
+
Thin::Server.should_receive(:new).
|
68
|
+
with("0.0.0.0", 25777, :signals => false).
|
69
|
+
and_return(mock_thin)
|
70
|
+
|
71
|
+
mock_thin.should_receive(:start!)
|
72
|
+
|
73
|
+
runner.run
|
74
|
+
|
75
|
+
mock_thin.should_receive(:stop!)
|
76
|
+
EM.should_receive(:stop)
|
77
|
+
|
78
|
+
runner.stop
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# Copyright (c) 2009-2012 VMware, Inc.
|
2
|
+
|
3
|
+
require File.expand_path("../../spec_helper", __FILE__)
|
4
|
+
|
5
|
+
describe Bosh::OpenstackRegistry::ServerManager do
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
openstack = double(Fog::Compute)
|
9
|
+
Fog::Compute.stub(:new).and_return(openstack)
|
10
|
+
@openstack = mock("openstack")
|
11
|
+
Bosh::OpenstackRegistry.openstack = @openstack
|
12
|
+
end
|
13
|
+
|
14
|
+
let(:manager) do
|
15
|
+
Bosh::OpenstackRegistry::ServerManager.new
|
16
|
+
end
|
17
|
+
|
18
|
+
def create_server(params)
|
19
|
+
Bosh::OpenstackRegistry::Models::OpenstackServer.create(params)
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "reading settings" do
|
23
|
+
it "returns settings" do
|
24
|
+
create_server(:server_id => "foo", :settings => "bar")
|
25
|
+
manager.read_settings("foo").should == "bar"
|
26
|
+
end
|
27
|
+
|
28
|
+
it "raises an error if server not found" do
|
29
|
+
expect {
|
30
|
+
manager.read_settings("foo")
|
31
|
+
}.to raise_error(Bosh::OpenstackRegistry::ServerNotFound,
|
32
|
+
"Can't find server `foo'")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "updating settings" do
|
37
|
+
it "updates settings (new server)" do
|
38
|
+
manager.update_settings("foo", "baz")
|
39
|
+
manager.read_settings("foo").should == "baz"
|
40
|
+
end
|
41
|
+
|
42
|
+
it "updates settings (existing server)" do
|
43
|
+
create_server(:server_id => "foo", :settings => "bar")
|
44
|
+
manager.read_settings("foo").should == "bar"
|
45
|
+
manager.update_settings("foo", "baz")
|
46
|
+
manager.read_settings("foo").should == "baz"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "deleting settings" do
|
51
|
+
it "deletes settings" do
|
52
|
+
manager.update_settings("foo", "baz")
|
53
|
+
manager.delete_settings("foo")
|
54
|
+
|
55
|
+
expect {
|
56
|
+
manager.read_settings("foo")
|
57
|
+
}.to raise_error(Bosh::OpenstackRegistry::ServerNotFound,
|
58
|
+
"Can't find server `foo'")
|
59
|
+
end
|
60
|
+
|
61
|
+
it "raises an error if server not found" do
|
62
|
+
expect {
|
63
|
+
manager.delete_settings("foo")
|
64
|
+
}.to raise_error(Bosh::OpenstackRegistry::ServerNotFound,
|
65
|
+
"Can't find server `foo'")
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
metadata
ADDED
@@ -0,0 +1,157 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bosh_openstack_registry
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- VMware
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-08-09 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: sequel
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '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: '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: '0'
|
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: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: thin
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: yajl-ruby
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :runtime
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: fog
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ~>
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: 1.4.0
|
86
|
+
type: :runtime
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ~>
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: 1.4.0
|
94
|
+
description: BOSH OpenStack registry
|
95
|
+
email: support@vmware.com
|
96
|
+
executables:
|
97
|
+
- openstack_registry
|
98
|
+
extensions: []
|
99
|
+
extra_rdoc_files: []
|
100
|
+
files:
|
101
|
+
- bin/migrate
|
102
|
+
- bin/openstack_registry
|
103
|
+
- lib/openstack_registry.rb
|
104
|
+
- lib/openstack_registry/api_controller.rb
|
105
|
+
- lib/openstack_registry/config.rb
|
106
|
+
- lib/openstack_registry/errors.rb
|
107
|
+
- lib/openstack_registry/models.rb
|
108
|
+
- lib/openstack_registry/models/openstack_server.rb
|
109
|
+
- lib/openstack_registry/runner.rb
|
110
|
+
- lib/openstack_registry/server_manager.rb
|
111
|
+
- lib/openstack_registry/version.rb
|
112
|
+
- lib/openstack_registry/yaml_helper.rb
|
113
|
+
- README
|
114
|
+
- Rakefile
|
115
|
+
- spec/assets/sample_config.yml
|
116
|
+
- spec/spec_helper.rb
|
117
|
+
- spec/unit/api_controller_spec.rb
|
118
|
+
- spec/unit/config_spec.rb
|
119
|
+
- spec/unit/runner_spec.rb
|
120
|
+
- spec/unit/server_manager_spec.rb
|
121
|
+
homepage: http://www.vmware.com
|
122
|
+
licenses: []
|
123
|
+
post_install_message:
|
124
|
+
rdoc_options: []
|
125
|
+
require_paths:
|
126
|
+
- lib
|
127
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
128
|
+
none: false
|
129
|
+
requirements:
|
130
|
+
- - ! '>='
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: '0'
|
133
|
+
segments:
|
134
|
+
- 0
|
135
|
+
hash: -1851942175393583791
|
136
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ! '>='
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: '0'
|
142
|
+
segments:
|
143
|
+
- 0
|
144
|
+
hash: -1851942175393583791
|
145
|
+
requirements: []
|
146
|
+
rubyforge_project:
|
147
|
+
rubygems_version: 1.8.24
|
148
|
+
signing_key:
|
149
|
+
specification_version: 3
|
150
|
+
summary: BOSH OpenStack registry
|
151
|
+
test_files:
|
152
|
+
- spec/assets/sample_config.yml
|
153
|
+
- spec/spec_helper.rb
|
154
|
+
- spec/unit/api_controller_spec.rb
|
155
|
+
- spec/unit/config_spec.rb
|
156
|
+
- spec/unit/runner_spec.rb
|
157
|
+
- spec/unit/server_manager_spec.rb
|