wakame-vdc-dcmgr 10.11.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +202 -0
- data/NOTICE +1 -0
- data/Rakefile +142 -0
- data/bin/collector +46 -0
- data/config/dcmgr.conf.example +9 -0
- data/config/initializers/isono.rb +43 -0
- data/config/initializers/passenger.rb +6 -0
- data/config/initializers/sequel.rb +21 -0
- data/config/path_resolver.rb +12 -0
- data/lib/dcmgr.rb +115 -0
- data/lib/dcmgr/endpoints/core_api.rb +1004 -0
- data/lib/dcmgr/endpoints/core_api_mock.rb +816 -0
- data/lib/dcmgr/endpoints/errors.rb +55 -0
- data/lib/dcmgr/endpoints/metadata.rb +129 -0
- data/lib/dcmgr/logger.rb +44 -0
- data/lib/dcmgr/models/account.rb +104 -0
- data/lib/dcmgr/models/account_resource.rb +16 -0
- data/lib/dcmgr/models/base.rb +69 -0
- data/lib/dcmgr/models/base_new.rb +371 -0
- data/lib/dcmgr/models/frontend_system.rb +38 -0
- data/lib/dcmgr/models/host_pool.rb +102 -0
- data/lib/dcmgr/models/image.rb +46 -0
- data/lib/dcmgr/models/instance.rb +255 -0
- data/lib/dcmgr/models/instance_netfilter_group.rb +16 -0
- data/lib/dcmgr/models/instance_nic.rb +68 -0
- data/lib/dcmgr/models/instance_spec.rb +21 -0
- data/lib/dcmgr/models/ip_lease.rb +42 -0
- data/lib/dcmgr/models/netfilter_group.rb +88 -0
- data/lib/dcmgr/models/netfilter_rule.rb +21 -0
- data/lib/dcmgr/models/network.rb +32 -0
- data/lib/dcmgr/models/physical_host.rb +67 -0
- data/lib/dcmgr/models/request_log.rb +25 -0
- data/lib/dcmgr/models/ssh_key_pair.rb +55 -0
- data/lib/dcmgr/models/storage_pool.rb +134 -0
- data/lib/dcmgr/models/tag.rb +126 -0
- data/lib/dcmgr/models/tag_mapping.rb +28 -0
- data/lib/dcmgr/models/volume.rb +130 -0
- data/lib/dcmgr/models/volume_snapshot.rb +47 -0
- data/lib/dcmgr/node_modules/hva_collector.rb +134 -0
- data/lib/dcmgr/node_modules/sta_collector.rb +72 -0
- data/lib/dcmgr/scheduler.rb +12 -0
- data/lib/dcmgr/scheduler/find_last.rb +16 -0
- data/lib/dcmgr/scheduler/find_random.rb +16 -0
- data/lib/dcmgr/stm/instance.rb +25 -0
- data/lib/dcmgr/stm/snapshot_context.rb +33 -0
- data/lib/dcmgr/stm/volume_context.rb +65 -0
- data/lib/dcmgr/web/base.rb +21 -0
- data/lib/sinatra/accept_media_types.rb +128 -0
- data/lib/sinatra/lazy_auth.rb +56 -0
- data/lib/sinatra/rabbit.rb +278 -0
- data/lib/sinatra/respond_to.rb +272 -0
- data/lib/sinatra/sequel_transaction.rb +27 -0
- data/lib/sinatra/static_assets.rb +83 -0
- data/lib/sinatra/url_for.rb +44 -0
- data/web/api/config.ru +20 -0
- data/web/api/public/index.html +0 -0
- data/web/metadata/config.ru +20 -0
- data/web/metadata/public/index.html +0 -0
- metadata +326 -0
@@ -0,0 +1,72 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'isono'
|
3
|
+
|
4
|
+
module Dcmgr
|
5
|
+
module NodeModules
|
6
|
+
class StaCollector < Isono::NodeModules::Base
|
7
|
+
|
8
|
+
initialize_hook do
|
9
|
+
app = Isono::Rack::ObjectMethod.new(myinstance)
|
10
|
+
rpc = Isono::NodeModules::RpcChannel.new(node)
|
11
|
+
rpc.register_endpoint('sta-collector', Isono::Rack.build do
|
12
|
+
use Isono::Rack::DataStore
|
13
|
+
run proc { |req, res|
|
14
|
+
Thread.current[Models::BaseNew::LOCK_TABLES_KEY] = {}
|
15
|
+
app.call(req, res)
|
16
|
+
}
|
17
|
+
end)
|
18
|
+
end
|
19
|
+
|
20
|
+
terminate_hook do
|
21
|
+
end
|
22
|
+
|
23
|
+
def get_volume(volume_id)
|
24
|
+
Models::Volume.lock!
|
25
|
+
v = Dcmgr::Models::Volume[volume_id]
|
26
|
+
v.merge_pool_data
|
27
|
+
end
|
28
|
+
|
29
|
+
def get_snapshot(snapshot_id)
|
30
|
+
Models::VolumeSnapshot.lock!
|
31
|
+
vs = Dcmgr::Models::VolumeSnapshot[snapshot_id]
|
32
|
+
vs.to_hash_document
|
33
|
+
end
|
34
|
+
|
35
|
+
def update_volume(data)
|
36
|
+
Models::Volume.lock!
|
37
|
+
v = Dcmgr::Models::Volume[data[:volume_id]]
|
38
|
+
|
39
|
+
column = case data[:state]
|
40
|
+
when :creating
|
41
|
+
[:state, :export_path]
|
42
|
+
when :available
|
43
|
+
if !data[:transport_information].nil?
|
44
|
+
[:state, :transport_information]
|
45
|
+
else
|
46
|
+
[:state, :host_device_name, :instance_id, :detached_at]
|
47
|
+
end
|
48
|
+
when :attaching
|
49
|
+
[:state, :host_device_name]
|
50
|
+
when :attached
|
51
|
+
[:state, :guest_device_name, :attached_at]
|
52
|
+
when :detaching
|
53
|
+
[:state, :guest_device_name]
|
54
|
+
else
|
55
|
+
[:state]
|
56
|
+
end
|
57
|
+
|
58
|
+
v.set_fields(data, column).save
|
59
|
+
# do not respond model object.
|
60
|
+
nil
|
61
|
+
end
|
62
|
+
|
63
|
+
def update_snapshot(data)
|
64
|
+
Models::VolumeSnapshot.lock!
|
65
|
+
vs = Dcmgr::Models::VolumeSnapshot[data[:snapshot_id]]
|
66
|
+
vs.set_fields(data, [:state]).save
|
67
|
+
# do not respond model object.
|
68
|
+
nil
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
|
2
|
+
module Dcmgr
|
3
|
+
module PhysicalHostScheduler
|
4
|
+
class NoPhysicalHostError < StandardError; end
|
5
|
+
|
6
|
+
autoload :Algorithm1, 'dcmgr/scheduler/algorithm1'
|
7
|
+
autoload :Algorithm2, 'dcmgr/scheduler/algorithm2'
|
8
|
+
autoload :FindFirst, 'dcmgr/scheduler/find_first'
|
9
|
+
autoload :FindLast, 'dcmgr/scheduler/find_last'
|
10
|
+
autoload :FindRandom, 'dcmgr/scheduler/find_random'
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
|
2
|
+
module Dcmgr
|
3
|
+
module PhysicalHostScheduler
|
4
|
+
# This is a simple host scheduler which gets back a host found
|
5
|
+
# at the top of hosts list.
|
6
|
+
class FindLast
|
7
|
+
def assign_to_instance(hosts, instance)
|
8
|
+
Dcmgr::logger.debug "assign to instance (%d hosts)" % hosts.length
|
9
|
+
p 'hosts'
|
10
|
+
p hosts
|
11
|
+
return hosts.last
|
12
|
+
raise NoPhysicalHostError.new("can't assign physical host")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
|
2
|
+
module Dcmgr
|
3
|
+
module PhysicalHostScheduler
|
4
|
+
# This is a simple host scheduler which gets back a host found
|
5
|
+
# at the top of hosts list.
|
6
|
+
class FindRandom
|
7
|
+
def assign_to_instance(hosts, instance)
|
8
|
+
Dcmgr::logger.debug "assign to instance (%d hosts)" % hosts.length
|
9
|
+
hvc_host = hosts[ rand(hosts.length) ]
|
10
|
+
p 'hvc_host'
|
11
|
+
p hvc_host
|
12
|
+
raise NoPhysicalHostError.new("can't assign physical host")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'statemachine'
|
4
|
+
|
5
|
+
module Dcmgr::Stm
|
6
|
+
class Instance
|
7
|
+
STM = Statemachine.build {
|
8
|
+
startstate :pending
|
9
|
+
superstate :instance_condition do
|
10
|
+
trans :pending, :on_create, :starting
|
11
|
+
trans :starting, :on_started, :running
|
12
|
+
trans :running, :on_shutdown, :shuttingdown
|
13
|
+
trans :shuttingdown, :on_terminated, :terminated
|
14
|
+
|
15
|
+
event :on_fail, :failed
|
16
|
+
end
|
17
|
+
|
18
|
+
trans :failed, :on_fail, :failed
|
19
|
+
}
|
20
|
+
|
21
|
+
def initialize
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'statemachine'
|
3
|
+
|
4
|
+
module Dcmgr::Stm
|
5
|
+
class SnapshotContext < OpenStruct
|
6
|
+
|
7
|
+
attr_reader :stm
|
8
|
+
|
9
|
+
def initialize(snapshot_id=nil)
|
10
|
+
super({:snapshot_id=>snapshot_id})
|
11
|
+
@stm = Statemachine.build {
|
12
|
+
trans :registering, :on_create, :creating
|
13
|
+
trans :creating, :on_create, :available
|
14
|
+
trans :available, :on_delete, :deleting
|
15
|
+
trans :deleting, :on_delete, :deleted
|
16
|
+
|
17
|
+
trans :registering, :on_fail, :failed
|
18
|
+
trans :creating, :on_fail, :failed
|
19
|
+
trans :available, :on_fail, :failed
|
20
|
+
trans :deleting, :on_fail, :failed
|
21
|
+
}
|
22
|
+
@stm.context = self
|
23
|
+
end
|
24
|
+
|
25
|
+
def state
|
26
|
+
@stm.state
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_hash
|
30
|
+
@table.dup.merge({:state=>@stm.state})
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'statemachine'
|
3
|
+
|
4
|
+
module Dcmgr::Stm
|
5
|
+
class VolumeContext < OpenStruct
|
6
|
+
attr_reader :stm
|
7
|
+
|
8
|
+
def initialize(volume_id=nil)
|
9
|
+
super({:volume_id => volume_id,
|
10
|
+
:export_path => nil,
|
11
|
+
:transport_information => nil,
|
12
|
+
:instance_id => nil,
|
13
|
+
:host_device_name => nil,
|
14
|
+
:guest_device_name => nil,
|
15
|
+
:deleted_at => nil,
|
16
|
+
:attached_at => nil,
|
17
|
+
:detached_at => nil,
|
18
|
+
})
|
19
|
+
@stm = Statemachine.build {
|
20
|
+
startstate :registering
|
21
|
+
superstate :volume_condition do
|
22
|
+
trans :registering, :on_create, :creating
|
23
|
+
trans :creating, :on_register, :available
|
24
|
+
trans :available, :on_attach, :attaching
|
25
|
+
trans :attaching, :on_attach, :attached
|
26
|
+
trans :attached, :on_detach, :detaching
|
27
|
+
trans :detaching, :on_detach, :available
|
28
|
+
|
29
|
+
event :on_fail, :failed
|
30
|
+
event :on_deregister, :deregistering
|
31
|
+
end
|
32
|
+
|
33
|
+
trans :failed, :on_create, :creating
|
34
|
+
trans :failed, :on_register, :available
|
35
|
+
trans :failed, :on_fail, :failed
|
36
|
+
trans :failed, :on_deregister, :deleting
|
37
|
+
trans :failed, :on_delete, :deleted
|
38
|
+
trans :deregistering, :on_delete, :deleting
|
39
|
+
trans :deleting, :on_delete, :deleted
|
40
|
+
trans :deleted, :on_delete, :deleted
|
41
|
+
}
|
42
|
+
@stm.context = self
|
43
|
+
end
|
44
|
+
|
45
|
+
def state
|
46
|
+
@stm.state
|
47
|
+
end
|
48
|
+
|
49
|
+
def to_hash(hash={})
|
50
|
+
@table.dup.merge({:state=>@stm.state}).merge(hash)
|
51
|
+
end
|
52
|
+
|
53
|
+
def on_delete
|
54
|
+
self.deleted_at = Time.now
|
55
|
+
end
|
56
|
+
|
57
|
+
def on_attach
|
58
|
+
self.attached_at = Time.now
|
59
|
+
end
|
60
|
+
|
61
|
+
def on_detach
|
62
|
+
self.detached_at = Time.now
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'sinatra'
|
2
|
+
require 'sequel'
|
3
|
+
|
4
|
+
module Dcmgr::Web
|
5
|
+
class Base < Sinatra::Base
|
6
|
+
set :logger, false
|
7
|
+
helpers { include Dcmgr::Helpers }
|
8
|
+
|
9
|
+
def self.public_crud model
|
10
|
+
model.actions {|action, pattern, proc|
|
11
|
+
Dcmgr::logger.debug "REGISTER: %s %s" % [action, pattern]
|
12
|
+
self.send action, pattern, &proc
|
13
|
+
}
|
14
|
+
end
|
15
|
+
|
16
|
+
not_found do
|
17
|
+
logger.debug "not found: #{request.request_method} #{request.path}"
|
18
|
+
"not found"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
module Rack
|
2
|
+
class Request
|
3
|
+
# The media types of the HTTP_ACCEPT header ordered according to their
|
4
|
+
# "quality" (preference level), without any media type parameters.
|
5
|
+
#
|
6
|
+
# ===== Examples
|
7
|
+
#
|
8
|
+
# env['HTTP_ACCEPT'] #=> 'application/xml;q=0.8,text/html,text/plain;q=0.9'
|
9
|
+
#
|
10
|
+
# req = Rack::Request.new(env)
|
11
|
+
# req.accept_media_types #=> ['text/html', 'text/plain', 'application/xml']
|
12
|
+
# req.accept_media_types.prefered #=> 'text/html'
|
13
|
+
#
|
14
|
+
# For more information, see:
|
15
|
+
# * Acept header: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1
|
16
|
+
# * Quality values: http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.9
|
17
|
+
#
|
18
|
+
# ===== Returns
|
19
|
+
# AcceptMediaTypes:: ordered list of accept header's media types
|
20
|
+
#
|
21
|
+
def accept_media_types
|
22
|
+
@accept_media_types ||= Rack::AcceptMediaTypes.new(@env['HTTP_ACCEPT'])
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# AcceptMediaTypes is intended for wrapping env['HTTP_ACCEPT'].
|
27
|
+
#
|
28
|
+
# It allows ordering of its values (accepted media types) according to their
|
29
|
+
# "quality" (preference level).
|
30
|
+
#
|
31
|
+
# This wrapper is typically used to determine the request's prefered media
|
32
|
+
# type (see example below).
|
33
|
+
#
|
34
|
+
# ===== Examples
|
35
|
+
#
|
36
|
+
# env['HTTP_ACCEPT'] #=> 'application/xml;q=0.8,text/html,text/plain;q=0.9'
|
37
|
+
#
|
38
|
+
# types = Rack::AcceptMediaTypes.new(env['HTTP_ACCEPT'])
|
39
|
+
# types #=> ['text/html', 'text/plain', 'application/xml']
|
40
|
+
# types.prefered #=> 'text/html'
|
41
|
+
#
|
42
|
+
# ===== Notes
|
43
|
+
#
|
44
|
+
# For simplicity, media type parameters are striped, as they are seldom used
|
45
|
+
# in practice. Users who need them are excepted to parse the Accept header
|
46
|
+
# manually.
|
47
|
+
#
|
48
|
+
# ===== References
|
49
|
+
#
|
50
|
+
# HTTP 1.1 Specs:
|
51
|
+
# * http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1
|
52
|
+
# * http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.9
|
53
|
+
#
|
54
|
+
class AcceptMediaTypes < Array
|
55
|
+
|
56
|
+
#--
|
57
|
+
# NOTE
|
58
|
+
# Reason for special handling of nil accept header:
|
59
|
+
#
|
60
|
+
# "If no Accept header field is present, then it is assumed that the client
|
61
|
+
# accepts all media types."
|
62
|
+
#
|
63
|
+
def initialize(header)
|
64
|
+
if header.nil?
|
65
|
+
replace(['*/*'])
|
66
|
+
else
|
67
|
+
replace(order(header.gsub(/ /, '').split(/,/)))
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# The client's prefered media type.
|
72
|
+
def prefered
|
73
|
+
first
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
# Order media types by quality values, remove invalid types, and return media ranges.
|
79
|
+
#
|
80
|
+
def order(types) #:nodoc:
|
81
|
+
types.map {|type| AcceptMediaType.new(type) }.reverse.sort.reverse.select {|type| type.valid? }.map {|type| type.range }
|
82
|
+
end
|
83
|
+
|
84
|
+
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1
|
85
|
+
#
|
86
|
+
class AcceptMediaType #:nodoc:
|
87
|
+
include Comparable
|
88
|
+
|
89
|
+
# media-range = ( "*/*"
|
90
|
+
# | ( type "/" "*" )
|
91
|
+
# | ( type "/" subtype )
|
92
|
+
# ) *( ";" parameter )
|
93
|
+
attr_accessor :range
|
94
|
+
|
95
|
+
# qvalue = ( "0" [ "." 0*3DIGIT ] )
|
96
|
+
# | ( "1" [ "." 0*3("0") ] )
|
97
|
+
attr_accessor :quality
|
98
|
+
|
99
|
+
def initialize(type)
|
100
|
+
self.range, *params = type.split(';')
|
101
|
+
self.quality = extract_quality(params)
|
102
|
+
end
|
103
|
+
|
104
|
+
def <=>(type)
|
105
|
+
self.quality <=> type.quality
|
106
|
+
end
|
107
|
+
|
108
|
+
# "A weight is normalized to a real number in the range 0 through 1,
|
109
|
+
# where 0 is the minimum and 1 the maximum value. If a parameter has a
|
110
|
+
# quality value of 0, then content with this parameter is `not
|
111
|
+
# acceptable' for the client."
|
112
|
+
#
|
113
|
+
def valid?
|
114
|
+
self.quality.between?(0.1, 1)
|
115
|
+
end
|
116
|
+
|
117
|
+
private
|
118
|
+
# Extract value from 'q=FLOAT' parameter if present, otherwise assume 1
|
119
|
+
#
|
120
|
+
# "The default value is q=1."
|
121
|
+
#
|
122
|
+
def extract_quality(params)
|
123
|
+
q = params.detect {|p| p.match(/q=\d\.?\d{0,3}/) }
|
124
|
+
q ? q.split('=').last.to_f : 1.0
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
|
3
|
+
# Lazy Basic HTTP authentication. Authentication is only forced when the
|
4
|
+
# credentials are actually needed.
|
5
|
+
module Sinatra
|
6
|
+
module LazyAuth
|
7
|
+
class LazyCredentials
|
8
|
+
def initialize(app)
|
9
|
+
@app = app
|
10
|
+
@provided = false
|
11
|
+
end
|
12
|
+
|
13
|
+
def user
|
14
|
+
credentials!
|
15
|
+
@user
|
16
|
+
end
|
17
|
+
|
18
|
+
def password
|
19
|
+
credentials!
|
20
|
+
@password
|
21
|
+
end
|
22
|
+
|
23
|
+
def provided?
|
24
|
+
@provided
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
def credentials!
|
29
|
+
unless provided?
|
30
|
+
auth = Rack::Auth::Basic::Request.new(@app.request.env)
|
31
|
+
unless auth.provided? && auth.basic? && auth.credentials
|
32
|
+
@app.authorize!
|
33
|
+
end
|
34
|
+
@user = auth.credentials[0]
|
35
|
+
@password = auth.credentials[1]
|
36
|
+
@provided = true
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
def authorize!
|
43
|
+
r = "#{DRIVER}-deltacloud@#{HOSTNAME}"
|
44
|
+
response['WWW-Authenticate'] = %(Basic realm="#{r}")
|
45
|
+
throw(:halt, [401, "Not authorized\n"])
|
46
|
+
end
|
47
|
+
|
48
|
+
# Request the current user's credentials. Actual credentials are only
|
49
|
+
# requested when an attempt is made to get the user name or password
|
50
|
+
def credentials
|
51
|
+
LazyCredentials.new(self)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
helpers LazyAuth
|
56
|
+
end
|