wakame-vdc-dcmgr 10.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. data/LICENSE +202 -0
  2. data/NOTICE +1 -0
  3. data/Rakefile +142 -0
  4. data/bin/collector +46 -0
  5. data/config/dcmgr.conf.example +9 -0
  6. data/config/initializers/isono.rb +43 -0
  7. data/config/initializers/passenger.rb +6 -0
  8. data/config/initializers/sequel.rb +21 -0
  9. data/config/path_resolver.rb +12 -0
  10. data/lib/dcmgr.rb +115 -0
  11. data/lib/dcmgr/endpoints/core_api.rb +1004 -0
  12. data/lib/dcmgr/endpoints/core_api_mock.rb +816 -0
  13. data/lib/dcmgr/endpoints/errors.rb +55 -0
  14. data/lib/dcmgr/endpoints/metadata.rb +129 -0
  15. data/lib/dcmgr/logger.rb +44 -0
  16. data/lib/dcmgr/models/account.rb +104 -0
  17. data/lib/dcmgr/models/account_resource.rb +16 -0
  18. data/lib/dcmgr/models/base.rb +69 -0
  19. data/lib/dcmgr/models/base_new.rb +371 -0
  20. data/lib/dcmgr/models/frontend_system.rb +38 -0
  21. data/lib/dcmgr/models/host_pool.rb +102 -0
  22. data/lib/dcmgr/models/image.rb +46 -0
  23. data/lib/dcmgr/models/instance.rb +255 -0
  24. data/lib/dcmgr/models/instance_netfilter_group.rb +16 -0
  25. data/lib/dcmgr/models/instance_nic.rb +68 -0
  26. data/lib/dcmgr/models/instance_spec.rb +21 -0
  27. data/lib/dcmgr/models/ip_lease.rb +42 -0
  28. data/lib/dcmgr/models/netfilter_group.rb +88 -0
  29. data/lib/dcmgr/models/netfilter_rule.rb +21 -0
  30. data/lib/dcmgr/models/network.rb +32 -0
  31. data/lib/dcmgr/models/physical_host.rb +67 -0
  32. data/lib/dcmgr/models/request_log.rb +25 -0
  33. data/lib/dcmgr/models/ssh_key_pair.rb +55 -0
  34. data/lib/dcmgr/models/storage_pool.rb +134 -0
  35. data/lib/dcmgr/models/tag.rb +126 -0
  36. data/lib/dcmgr/models/tag_mapping.rb +28 -0
  37. data/lib/dcmgr/models/volume.rb +130 -0
  38. data/lib/dcmgr/models/volume_snapshot.rb +47 -0
  39. data/lib/dcmgr/node_modules/hva_collector.rb +134 -0
  40. data/lib/dcmgr/node_modules/sta_collector.rb +72 -0
  41. data/lib/dcmgr/scheduler.rb +12 -0
  42. data/lib/dcmgr/scheduler/find_last.rb +16 -0
  43. data/lib/dcmgr/scheduler/find_random.rb +16 -0
  44. data/lib/dcmgr/stm/instance.rb +25 -0
  45. data/lib/dcmgr/stm/snapshot_context.rb +33 -0
  46. data/lib/dcmgr/stm/volume_context.rb +65 -0
  47. data/lib/dcmgr/web/base.rb +21 -0
  48. data/lib/sinatra/accept_media_types.rb +128 -0
  49. data/lib/sinatra/lazy_auth.rb +56 -0
  50. data/lib/sinatra/rabbit.rb +278 -0
  51. data/lib/sinatra/respond_to.rb +272 -0
  52. data/lib/sinatra/sequel_transaction.rb +27 -0
  53. data/lib/sinatra/static_assets.rb +83 -0
  54. data/lib/sinatra/url_for.rb +44 -0
  55. data/web/api/config.ru +20 -0
  56. data/web/api/public/index.html +0 -0
  57. data/web/metadata/config.ru +20 -0
  58. data/web/metadata/public/index.html +0 -0
  59. metadata +326 -0
@@ -0,0 +1,68 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Dcmgr::Models
4
+ # Network interface for running instance.
5
+ class InstanceNic < BaseNew
6
+ taggable 'nic'
7
+
8
+ inheritable_schema do
9
+ Fixnum :instance_id, :null=>false
10
+ String :vif, :null=>false, :size=>50
11
+ String :mac_addr, :null=>false, :size=>12
12
+
13
+ index :mac_addr, {:unique=>true}
14
+ end
15
+ with_timestamps
16
+
17
+ many_to_one :instance
18
+ one_to_one :ip, :class=>IpLease
19
+
20
+ def to_hash
21
+ h = values.dup.merge(super)
22
+ h.delete(:instance_id)
23
+ h
24
+ end
25
+
26
+ def before_validation
27
+ super
28
+ m = normalize_mac_addr(self[:mac_addr])
29
+ if m.size == 6
30
+ # mac_addr looks like to only have vendor ID part so that
31
+ # generate unique value for node ID part.
32
+ mvendor = m
33
+ begin
34
+ m = mvendor + ("%02x%02x%02x" % [rand(0xff),rand(0xff),rand(0xff)])
35
+ end while self.class.find(:mac_addr=> m)
36
+ self[:mac_addr] = m
37
+ end
38
+ true
39
+ end
40
+
41
+ def validate
42
+ super
43
+
44
+ unless self.mac_addr.size == 12
45
+ errors.add(:mac_addr, "Invalid mac address length: #{self.mac_addr}")
46
+ end
47
+
48
+ unless self.mac_addr =~ /^[0-9a-f]{12}$/
49
+ errors.add(:mac_addr, "Invalid mac address syntax: #{self.mac_addr}")
50
+ end
51
+ end
52
+
53
+ def pretty_mac_addr(delim=':')
54
+ self.mac_addr.unpack('A2'*6).join(delim)
55
+ end
56
+
57
+ private
58
+ def normalize_mac_addr(str)
59
+ str = str.downcase.gsub(/[^0-9a-f]/, '')
60
+ raise "invalid mac address data: #{str}" if str.size > 12
61
+ # TODO: put more checks on the mac address.
62
+ # i.e. single 0 to double 00
63
+ str
64
+ end
65
+
66
+
67
+ end
68
+ end
@@ -0,0 +1,21 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Dcmgr::Models
4
+ class InstanceSpec < AccountResource
5
+ taggable 'is'
6
+
7
+ inheritable_schema do
8
+ String :hypervisor, :null=>false
9
+ String :arch, :null=>false
10
+
11
+ Fixnum :cpu_cores, :null=>false, :unsigned=>true
12
+ Fixnum :memory_size, :null=>false, :unsigned=>true
13
+ Text :config, :null=>false, :default=>''
14
+ end
15
+ with_timestamps
16
+
17
+ def to_hash
18
+ super.merge({:config=>config.to_s})
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,42 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'ipaddress'
4
+
5
+ module Dcmgr::Models
6
+ # IP address lease information
7
+ class IpLease < BaseNew
8
+
9
+ inheritable_schema do
10
+ Fixnum :instance_nic_id, :null=>false
11
+ Fixnum :network_id, :null=>false
12
+ String :ipv4, :size=>50
13
+
14
+ index :ipv4, {:unique=>true}
15
+ end
16
+ with_timestamps
17
+
18
+ many_to_one :instance_nic
19
+ many_to_one :network
20
+
21
+ def self.lease(instance_nic)
22
+ raise TypeError unless instance_nic.is_a?(InstanceNic)
23
+ # TODO: consider the case of multiple nics on multiple network.
24
+ network = instance_nic.instance.host_pool.network
25
+ gwaddr = IPAddress::IPv4.new("#{network.ipv4_gw}/#{network.prefix}")
26
+ reserved = [gwaddr]
27
+ reserved << IPAddress::IPv4.new(network.dhcp_server)
28
+ reserved << IPAddress::IPv4.new(network.dns_server)
29
+ if network.metadata_server
30
+ reserved << IPAddress::IPv4.new(network.metadata_server)
31
+ end
32
+ reserved = reserved.map {|i| i.to_u32 }
33
+ # use SELECT FOR UPDATE to lock rows within same network.
34
+ addrs = (gwaddr.first.to_u32 .. gwaddr.last.to_u32).to_a -
35
+ reserved - network.ip_lease_dataset.for_update.all.map {|i| IPAddress::IPv4.new(i.ipv4).to_u32 }
36
+ raise "Out of IP address in this network segment: #{gwaddr.network.to_s}/#{gwaddr.prefix}" if addrs.empty?
37
+
38
+ leaseaddr = IPAddress::IPv4.parse_u32(addrs[rand(addrs.size).to_i])
39
+ create(:ipv4=>leaseaddr.to_s, :network_id=>network.id, :instance_nic_id=>instance_nic.id)
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,88 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Dcmgr::Models
4
+ class NetfilterGroup < AccountResource
5
+ taggable 'ng'
6
+ with_timestamps
7
+
8
+ inheritable_schema do
9
+ String :name, :null=>false
10
+ String :description
11
+ Text :rule
12
+ index [:account_id, :name], {:unique=>true}
13
+ end
14
+
15
+ one_to_many :netfilter_rules
16
+ one_to_many :instance_netfilter_groups
17
+
18
+ def to_hash
19
+ h = super
20
+ h = h.merge({
21
+ :rule => rule.to_s,
22
+ :rules => netfilter_rules.map { |rule| rule.to_hash },
23
+ })
24
+ #{
25
+ #:id => self.canonical_uuid,
26
+ #:name => name,
27
+ #:description => description,
28
+ #:rules => netfilter_rules.map { |rule| rule.to_hash },
29
+ #}
30
+ end
31
+
32
+ def to_tiny_hash
33
+ {
34
+ :name => self.name,
35
+ :uuid => self.canonical_uuid,
36
+ }
37
+ end
38
+
39
+ def self.create_group(account_id, params)
40
+ grp = self.create(:account_id => account_id,
41
+ :name => params[:name],
42
+ :rule => params[:rule],
43
+ :description => params[:description])
44
+ grp.build_rule
45
+ grp
46
+ end
47
+
48
+ def flush_rule
49
+ NetfilterRule.filter(:netfilter_group_id => self.id).destroy
50
+ end
51
+
52
+ def destroy_group
53
+ self.flush_rule
54
+ self.destroy
55
+ end
56
+
57
+ def rebuild_rule
58
+ self.flush_rule
59
+ self.build_rule
60
+ end
61
+
62
+ def build_rule
63
+ return if self.rule.nil?
64
+
65
+ self.rule.split("\n").each { |permission|
66
+ # [ToDo]
67
+ # to make strong parser
68
+ next if permission =~ /\A#/
69
+ next if permission.length == 0
70
+
71
+ # [format] protocol,source,destination
72
+ # - protocol: tcp|udp|icmp
73
+ # - source: IPAddr|CIDR|Owner:Group
74
+ # - destination: port|icmp-type
75
+ NetfilterRule.create(:netfilter_group_id => self.id,
76
+ :permission => permission)
77
+
78
+ }
79
+ end
80
+
81
+ def instances
82
+ self.instance_netfilter_groups.map { |instance_netfilter_group|
83
+ instance_netfilter_group.instance
84
+ }
85
+ end
86
+
87
+ end
88
+ end
@@ -0,0 +1,21 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Dcmgr::Models
4
+ class NetfilterRule < BaseNew
5
+ with_timestamps
6
+
7
+ inheritable_schema do
8
+ Fixnum :netfilter_group_id, :null=>false
9
+ String :permission, :null=>false
10
+ end
11
+
12
+ many_to_one :netfilter_group
13
+
14
+ def to_hash
15
+ {
16
+ :permission => permission,
17
+ }
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,32 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Dcmgr::Models
4
+ # Network definitions in the DC.
5
+ class Network < BaseNew
6
+
7
+ inheritable_schema do
8
+ String :name, :null=>false
9
+ String :ipv4_gw, :null=>false
10
+ Fixnum :prefix, :null=>false, :default=>24, :unsigned=>true
11
+ String :domain_name, :null=>false
12
+ String :dns_server, :null=>false
13
+ String :dhcp_server, :null=>false
14
+ String :metadata_server
15
+ Text :description
16
+ index :name, {:unique=>true}
17
+ end
18
+ with_timestamps
19
+
20
+ many_to_one :host_pool
21
+ one_to_many :ip_lease
22
+
23
+ def validate
24
+ super
25
+ end
26
+
27
+ def to_hash
28
+ values.dup.merge({:description=>description.to_s})
29
+ end
30
+
31
+ end
32
+ end
@@ -0,0 +1,67 @@
1
+ module Dcmgr
2
+ module Models
3
+ class PhysicalHost < Base
4
+ set_dataset :physical_hosts
5
+ set_prefix_uuid 'PH'
6
+
7
+ one_to_many :hv_agents
8
+
9
+ many_to_many :tags, :join_table=>:tag_mappings, :left_key=>:target_id, :conditions=>{:target_type=>TagMapping::TYPE_PHYSICAL_HOST}
10
+ many_to_many :location_tags, :class=>:Tag, :right_key=>:tag_id, :join_table=>:tag_mappings, :left_key=>:target_id, :conditions=>{:target_type=>TagMapping::TYPE_PHYSICAL_HOST_LOCATION}
11
+
12
+ many_to_one :relate_user, :class=>:User
13
+
14
+ def self.enable_hosts
15
+ filter(~:id => TagMapping.filter(:target_type=>TagMapping::TYPE_PHYSICAL_HOST).select(:target_id)).order_by(:id).all
16
+ end
17
+
18
+ def self.assign(instance)
19
+ Dcmgr::scheduler.assign_to_instance(enable_hosts, instance)
20
+ end
21
+
22
+ def before_create
23
+ super
24
+ end
25
+
26
+ def after_create
27
+ super
28
+ TagMapping.create(:tag_id=>Tag.system_tag(:STANDBY_INSTANCE).id,
29
+ :target_type=>TagMapping::TYPE_PHYSICAL_HOST,
30
+ :target_id=>self.id)
31
+ end
32
+
33
+ def instances
34
+ self.hv_agents.map{|hva| hva.instances}.flatten
35
+ end
36
+
37
+ def create_location_tag(name, account)
38
+ TagMapping.create(:tag_id=>Tag.create(:name=>name, :account=>account).id,
39
+ :target_type=>TagMapping::TYPE_PHYSICAL_HOST_LOCATION,
40
+ :target_id=>self.id)
41
+ end
42
+
43
+ def space_cpu_mhz
44
+ setup_space unless @space_cpu_mhz
45
+ @space_cpu_mhz
46
+ end
47
+
48
+ def setup_space
49
+
50
+ need_cpu_mhz = instances.inject(0) {|v, ins| v + ins.need_cpu_mhz}
51
+ space_cpu_mhz = cpu_mhz - need_cpu_mhz
52
+ # 10 % down
53
+ @space_cpu_mhz = space_cpu_mhz * 0.9
54
+
55
+ need_memory = instances.inject(0) {|v, ins| v + ins.need_memory}
56
+ space_memory = memory - need_memory
57
+ # 10 % down
58
+ @space_memory = space_memory * 0.9
59
+ end
60
+
61
+ def space_memory
62
+ setup_space unless @space_memory
63
+ @space_memory
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,25 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Dcmgr::Models
4
+ class RequestLog < BaseNew
5
+
6
+ inheritable_schema do
7
+ String :request_id, :null=>false, :size=>40, :unique=>true
8
+ Fixnum :frontend_system_id, :null=>false
9
+ Fixnum :account_id, :null=>false
10
+ String :requester_symbol, :null=>false, :size=>100
11
+ # HTTP Response Code
12
+ Fixnum :response_status, :null=>false
13
+ String :response_msg
14
+ String :api_path, :null=>false
15
+ String :params, :null=>false
16
+ Time :requested_at
17
+ Time :responsed_at
18
+ end
19
+
20
+ def after_initialize
21
+ self[:request_id] #
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,55 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'tmpdir'
4
+
5
+ module Dcmgr::Models
6
+ # SSH Key database for account.
7
+ class SshKeyPair < AccountResource
8
+ taggable 'ssh'
9
+
10
+ inheritable_schema do
11
+ String :name, :size=>100, :null=>false
12
+ Text :public_key, :null=>false
13
+ Text :private_key, :null=>true
14
+
15
+ index [:account_id, :name], {:unique=>true}
16
+ end
17
+ with_timestamps
18
+
19
+ def validate
20
+ end
21
+
22
+ def before_destroy
23
+ # TODO: check running instances which are associated to ssh key
24
+ # pairs. reject deletion if exist.
25
+ end
26
+
27
+ #
28
+ # @return [Hash] {:private_key=>'pkey string',
29
+ # :public_key=>'pubkey string'}
30
+ def self.generate_key_pair()
31
+ pkey = File.expand_path(randstr, Dir.tmpdir)
32
+ pubkey = pkey + '.pub'
33
+ begin
34
+ system("ssh-keygen -q -t rsa -C '' -N '' -f %s >/dev/null" % [pkey])
35
+ unless $?.exitstatus == 0
36
+ raise "Failed to run ssh-keygen: exitcode=#{$?.exitstatus}"
37
+ end
38
+
39
+ {:private_key=>IO.read(pkey),
40
+ :public_key=>IO.read(pubkey)}
41
+ rescue
42
+ # clean up tmp key files
43
+ [pkey, pubkey].each { |i|
44
+ File.unlink(i) if File.exist?(i)
45
+ }
46
+ end
47
+ end
48
+
49
+ private
50
+ def self.randstr
51
+ Array.new(10) { (('a'..'z').to_a + (0..9).to_a)[rand(36)] }.join
52
+ end
53
+
54
+ end
55
+ end
@@ -0,0 +1,134 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'statemachine'
3
+
4
+ module Dcmgr::Models
5
+ class StoragePool < AccountResource
6
+ taggable 'sp'
7
+ with_timestamps
8
+
9
+ STATAS_TYPE_REGISTERING = "registering"
10
+ STATAS_TYPE_ONLINE = "online"
11
+ STATAS_TYPE_DEGRADE = "degrade"
12
+ STATAS_TYPE_FAILED = "failed"
13
+ STATAS_TYPE_DEREGISTERED = "deregistered"
14
+
15
+ STATUS_MSGS = {
16
+ STATAS_TYPE_REGISTERING => :registering,
17
+ STATAS_TYPE_ONLINE => :online,
18
+ STATAS_TYPE_DEGRADE => :degrade,
19
+ STATAS_TYPE_FAILED => :failed,
20
+ STATAS_TYPE_DEREGISTERED => :deregistered
21
+ }
22
+
23
+ inheritable_schema do
24
+ String :node_id, :null=>false
25
+ String :export_path, :null=>false
26
+ String :status, :null=>false, :default=>STATAS_TYPE_REGISTERING
27
+ Fixnum :offerring_disk_space, :null=>false, :unsigned=>true
28
+ String :transport_type, :null=>false
29
+ String :storage_type, :null=>false
30
+ String :ipaddr, :null=>false
31
+ String :snapshot_base_path, :null=>false
32
+ end
33
+
34
+ one_to_many :volumes
35
+ one_to_many :volume_snapshots
36
+
37
+ many_to_one :storage_agents
38
+
39
+ def before_validation
40
+ export_path = self.export_path
41
+ if export_path =~ /^(\/[a-z0-9]+)+$/
42
+ export_path = export_path.split('/')
43
+ export_path.shift
44
+ self.export_path = export_path.join('/')
45
+ end
46
+ end
47
+
48
+ def to_hash_document
49
+ h = self.values.dup
50
+ h[:id] = h[:uuid] = self.canonical_uuid
51
+ h
52
+ end
53
+
54
+ def state_machine
55
+ model = self
56
+ st = Statemachine.build do
57
+ superstate :storage_condition do
58
+ trans :registering, :on_success, :online
59
+ trans :registering, :on_error, :degrade
60
+ trans :online, :on_success, :online
61
+ trans :online, :on_error, :degrade
62
+ trans :degrade, :on_success, :online
63
+ trans :degrade, :on_error, :degrade
64
+
65
+ event :on_fail, :failed
66
+ event :on_deregistered, :deregistered
67
+ end
68
+
69
+ trans :failed, :on_success, :online
70
+ trans :failed, :on_error, :degrade
71
+ trans :failed, :on_deregistered, :deregistered
72
+
73
+ on_entry_of :registering, proc {
74
+ model.status = STATAS_TYPE_REGISTERING
75
+ }
76
+
77
+ on_entry_of :online, proc {
78
+ model.status = STATAS_TYPE_ONLINE
79
+ }
80
+
81
+ on_entry_of :degrade, proc {
82
+ model.status = STATAS_TYPE_DEGRADE
83
+ }
84
+
85
+ on_entry_of :failed, proc {
86
+ model.status = STATAS_TYPE_FAILED
87
+ }
88
+
89
+ on_entry_of :deregistered, proc {
90
+ model.status = STATAS_TYPE_DEREGISTERED
91
+ }
92
+ end
93
+
94
+ if self[:status]
95
+ if st.has_state(STATUS_MSGS[self[:status]].to_sym)
96
+ st.state = STATUS_MSGS[self[:status]].to_sym
97
+ else
98
+ raise "Unknown state: #{self[:status]}"
99
+ end
100
+ else
101
+ st.reset
102
+ end
103
+ st
104
+ end
105
+
106
+ def self.create_pool(params)
107
+ self.create(:account_id => params[:account_id],
108
+ :node_id => params[:node_id],
109
+ :offerring_disk_space => params[:offerring_disk_space],
110
+ :transport_type => params[:transport_type],
111
+ :storage_type => params[:storage_type],
112
+ :export_path => params[:export_path],
113
+ :ipaddr => params[:ipaddr],
114
+ :snapshot_base_path => params[:snapshot_base_path])
115
+ end
116
+
117
+ def self.get_lists(uuid)
118
+ self.dataset.where(:account_id => uuid).all.map{|row|
119
+ row.values
120
+ }
121
+ end
122
+
123
+ # def find_private_pool(account_id, uuid)
124
+ # sp = self.dataset.where(:account_id=>account_id).where(:uuid=>uuid)
125
+ # end
126
+
127
+ def create_volume(account_id, size, snapshot_id=nil)
128
+ v = Volume.create(:account_id => account_id,
129
+ :storage_pool_id => self.id,
130
+ :snapshot_id => snapshot_id,
131
+ :size =>size)
132
+ end
133
+ end
134
+ end