wakame-vdc-agents 10.11.0

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.
Files changed (58) hide show
  1. data/LICENSE +202 -0
  2. data/NOTICE +1 -0
  3. data/Rakefile +142 -0
  4. data/bin/hva +972 -0
  5. data/bin/nsa +147 -0
  6. data/bin/sta +182 -0
  7. data/config/hva.conf.example +10 -0
  8. data/config/initializers/isono.rb +43 -0
  9. data/config/initializers/passenger.rb +6 -0
  10. data/config/initializers/sequel.rb +21 -0
  11. data/config/nsa.conf.example +9 -0
  12. data/config/path_resolver.rb +12 -0
  13. data/lib/dcmgr.rb +115 -0
  14. data/lib/dcmgr/endpoints/core_api.rb +1004 -0
  15. data/lib/dcmgr/endpoints/core_api_mock.rb +816 -0
  16. data/lib/dcmgr/endpoints/errors.rb +55 -0
  17. data/lib/dcmgr/endpoints/metadata.rb +129 -0
  18. data/lib/dcmgr/logger.rb +44 -0
  19. data/lib/dcmgr/models/account.rb +104 -0
  20. data/lib/dcmgr/models/account_resource.rb +16 -0
  21. data/lib/dcmgr/models/base.rb +69 -0
  22. data/lib/dcmgr/models/base_new.rb +371 -0
  23. data/lib/dcmgr/models/frontend_system.rb +38 -0
  24. data/lib/dcmgr/models/host_pool.rb +102 -0
  25. data/lib/dcmgr/models/image.rb +46 -0
  26. data/lib/dcmgr/models/instance.rb +255 -0
  27. data/lib/dcmgr/models/instance_netfilter_group.rb +16 -0
  28. data/lib/dcmgr/models/instance_nic.rb +68 -0
  29. data/lib/dcmgr/models/instance_spec.rb +21 -0
  30. data/lib/dcmgr/models/ip_lease.rb +42 -0
  31. data/lib/dcmgr/models/netfilter_group.rb +88 -0
  32. data/lib/dcmgr/models/netfilter_rule.rb +21 -0
  33. data/lib/dcmgr/models/network.rb +32 -0
  34. data/lib/dcmgr/models/physical_host.rb +67 -0
  35. data/lib/dcmgr/models/request_log.rb +25 -0
  36. data/lib/dcmgr/models/ssh_key_pair.rb +55 -0
  37. data/lib/dcmgr/models/storage_pool.rb +134 -0
  38. data/lib/dcmgr/models/tag.rb +126 -0
  39. data/lib/dcmgr/models/tag_mapping.rb +28 -0
  40. data/lib/dcmgr/models/volume.rb +130 -0
  41. data/lib/dcmgr/models/volume_snapshot.rb +47 -0
  42. data/lib/dcmgr/node_modules/hva_collector.rb +134 -0
  43. data/lib/dcmgr/node_modules/sta_collector.rb +72 -0
  44. data/lib/dcmgr/scheduler.rb +12 -0
  45. data/lib/dcmgr/scheduler/find_last.rb +16 -0
  46. data/lib/dcmgr/scheduler/find_random.rb +16 -0
  47. data/lib/dcmgr/stm/instance.rb +25 -0
  48. data/lib/dcmgr/stm/snapshot_context.rb +33 -0
  49. data/lib/dcmgr/stm/volume_context.rb +65 -0
  50. data/lib/dcmgr/web/base.rb +21 -0
  51. data/lib/sinatra/accept_media_types.rb +128 -0
  52. data/lib/sinatra/lazy_auth.rb +56 -0
  53. data/lib/sinatra/rabbit.rb +278 -0
  54. data/lib/sinatra/respond_to.rb +272 -0
  55. data/lib/sinatra/sequel_transaction.rb +27 -0
  56. data/lib/sinatra/static_assets.rb +83 -0
  57. data/lib/sinatra/url_for.rb +44 -0
  58. metadata +270 -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