wakame-vdc-dcmgr 10.11.0 → 10.12.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +2 -2
- data/bin/collector +1 -0
- data/config/dcmgr.conf.example +5 -0
- data/lib/dcmgr.rb +15 -2
- data/lib/dcmgr/endpoints/core_api.rb +281 -119
- data/lib/dcmgr/endpoints/errors.rb +4 -0
- data/lib/dcmgr/helpers/cli_helper.rb +79 -0
- data/lib/dcmgr/models/account.rb +19 -12
- data/lib/dcmgr/models/base_new.rb +154 -18
- data/lib/dcmgr/models/history.rb +21 -0
- data/lib/dcmgr/models/host_pool.rb +7 -7
- data/lib/dcmgr/models/hostname_lease.rb +15 -0
- data/lib/dcmgr/models/instance.rb +114 -25
- data/lib/dcmgr/models/instance_nic.rb +24 -19
- data/lib/dcmgr/models/instance_spec.rb +21 -1
- data/lib/dcmgr/models/ip_lease.rb +27 -14
- data/lib/dcmgr/models/mac_lease.rb +22 -0
- data/lib/dcmgr/models/netfilter_group.rb +3 -2
- data/lib/dcmgr/models/network.rb +47 -10
- data/lib/dcmgr/models/storage_pool.rb +2 -6
- data/lib/dcmgr/models/tag.rb +104 -66
- data/lib/dcmgr/models/tag_mapping.rb +1 -13
- data/lib/dcmgr/models/vlan_lease.rb +17 -0
- data/lib/dcmgr/models/volume.rb +26 -9
- data/lib/dcmgr/models/volume_snapshot.rb +21 -8
- data/lib/dcmgr/node_modules/hva_collector.rb +88 -38
- data/lib/dcmgr/node_modules/instance_ha.rb +65 -0
- data/lib/dcmgr/node_modules/sta_collector.rb +1 -1
- data/lib/dcmgr/tags.rb +54 -0
- metadata +10 -3
@@ -2,22 +2,10 @@
|
|
2
2
|
|
3
3
|
module Dcmgr::Models
|
4
4
|
class TagMapping < BaseNew
|
5
|
-
TYPE_ACCOUNT = 0
|
6
|
-
TYPE_TAG = 1
|
7
|
-
TYPE_USER = 2
|
8
|
-
TYPE_INSTANCE = 3
|
9
|
-
TYPE_INSTANCE_IMAGE = 4
|
10
|
-
TYPE_HV_CONTROLLER = 5
|
11
|
-
TYPE_HV_AGENT = 6
|
12
|
-
TYPE_PHYSICAL_HOST = 7
|
13
|
-
TYPE_PHYSICAL_HOST_LOCATION = 8
|
14
|
-
TYPE_IMAGE_STORAGE_HOST = 9
|
15
|
-
TYPE_IMAGE_STORAGE = 10
|
16
|
-
|
17
5
|
inheritable_schema do
|
18
6
|
Fixnum :tag_id, :null=>false
|
7
|
+
String :uuid, :null=>false, :size=>20
|
19
8
|
index :tag_id
|
20
|
-
String :uuid, :null=>false, :fixed=>true, :size=>20
|
21
9
|
index :uuid
|
22
10
|
end
|
23
11
|
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
module Dcmgr::Models
|
4
|
+
# VLAN lease information
|
5
|
+
class VlanLease < AccountResource
|
6
|
+
taggable 'vlan'
|
7
|
+
|
8
|
+
inheritable_schema do
|
9
|
+
Fixnum :tag_id, :null=>false
|
10
|
+
|
11
|
+
index :tag_id, {:unique=>true}
|
12
|
+
end
|
13
|
+
with_timestamps
|
14
|
+
|
15
|
+
one_to_many :networks
|
16
|
+
end
|
17
|
+
end
|
data/lib/dcmgr/models/volume.rb
CHANGED
@@ -27,6 +27,7 @@ module Dcmgr::Models
|
|
27
27
|
String :state, :null=>false, :default=>STATE_TYPE_REGISTERING
|
28
28
|
Fixnum :size, :null=>false
|
29
29
|
Fixnum :instance_id
|
30
|
+
Fixnum :boot_dev, :null=>false, :default=>0
|
30
31
|
String :snapshot_id
|
31
32
|
String :host_device_name
|
32
33
|
String :guest_device_name
|
@@ -41,6 +42,11 @@ module Dcmgr::Models
|
|
41
42
|
end
|
42
43
|
with_timestamps
|
43
44
|
|
45
|
+
many_to_one :storage_pool
|
46
|
+
many_to_one :instance
|
47
|
+
|
48
|
+
plugin ArchiveChangedColumn, :histories
|
49
|
+
|
44
50
|
# serialization plugin must be defined at the bottom of all class
|
45
51
|
# method calls.
|
46
52
|
# Possible column data:
|
@@ -48,9 +54,6 @@ module Dcmgr::Models
|
|
48
54
|
# {:iqn=>'iqn.1986-03.com.sun:02:a1024afa-775b-65cf-b5b0-aa17f3476bfc', :lun=>0}
|
49
55
|
plugin :serialization, :yaml, :transport_information
|
50
56
|
|
51
|
-
many_to_one :storage_pool
|
52
|
-
many_to_one :instance
|
53
|
-
|
54
57
|
class DiskError < RuntimeError; end
|
55
58
|
class RequestError < RuntimeError; end
|
56
59
|
|
@@ -93,7 +96,7 @@ module Dcmgr::Models
|
|
93
96
|
vl = vl.grep(data[:target].to_sym, "%#{filter}%")
|
94
97
|
end
|
95
98
|
vl.all.map{|row|
|
96
|
-
row.
|
99
|
+
row.to_api_document
|
97
100
|
}
|
98
101
|
end
|
99
102
|
|
@@ -108,18 +111,32 @@ module Dcmgr::Models
|
|
108
111
|
end
|
109
112
|
|
110
113
|
def merge_pool_data
|
111
|
-
v = self.
|
112
|
-
v.merge(:storage_pool=>storage_pool.
|
114
|
+
v = self.to_hash
|
115
|
+
v.merge(:storage_pool=>storage_pool.to_hash)
|
113
116
|
end
|
114
117
|
|
115
|
-
def
|
116
|
-
h =
|
117
|
-
h[:id] = h[:uuid] = h[:export_path] = self.canonical_uuid
|
118
|
+
def to_hash
|
119
|
+
h = super
|
118
120
|
# yaml -> hash translation
|
119
121
|
h[:transport_information]=self.transport_information
|
120
122
|
h
|
121
123
|
end
|
122
124
|
|
125
|
+
# Hash data for API response.
|
126
|
+
def to_api_document
|
127
|
+
h = {
|
128
|
+
:id => self.canonical_uuid,
|
129
|
+
:uuid => self.canonical_uuid,
|
130
|
+
:size => self.size,
|
131
|
+
:snapshot_id => self.snapshot_id,
|
132
|
+
:created_at => self.created_at,
|
133
|
+
:attached_at => self.attached_at,
|
134
|
+
:state => self.state,
|
135
|
+
:instance_id => (self.instance && self.instance.canonical_uuid),
|
136
|
+
:deleted_at => self.deleted_at,
|
137
|
+
}
|
138
|
+
end
|
139
|
+
|
123
140
|
def create_snapshot(account_id)
|
124
141
|
vs = VolumeSnapshot.create(:account_id=>account_id,
|
125
142
|
:storage_pool_id=>self.storage_pool_id,
|
@@ -22,11 +22,20 @@ module Dcmgr::Models
|
|
22
22
|
with_timestamps
|
23
23
|
|
24
24
|
many_to_one :storage_pool
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
25
|
+
plugin ArchiveChangedColumn, :histories
|
26
|
+
|
27
|
+
class RequestError < RuntimeError; end
|
28
|
+
|
29
|
+
# Hash data for API response.
|
30
|
+
def to_api_document
|
31
|
+
h = {
|
32
|
+
:id => self.canonical_uuid,
|
33
|
+
:uuid => self.canonical_uuid,
|
34
|
+
:state => self.state,
|
35
|
+
:size => self.size,
|
36
|
+
:origin_volume_id => self.origin_volume_id,
|
37
|
+
:created_at => self.created_at,
|
38
|
+
}
|
30
39
|
end
|
31
40
|
|
32
41
|
# create volume inherite from this snapshot for the account.
|
@@ -39,9 +48,13 @@ module Dcmgr::Models
|
|
39
48
|
Volume[origin_volume_id]
|
40
49
|
end
|
41
50
|
|
42
|
-
def delete_snapshot
|
43
|
-
self.
|
44
|
-
|
51
|
+
def self.delete_snapshot(account_id, uuid)
|
52
|
+
vs = self.dataset.where(:account_id => account_id).where(:uuid => uuid.split('-').last).first
|
53
|
+
if vs.state.to_sym != :available
|
54
|
+
raise RequestError, "invalid delete request"
|
55
|
+
end
|
56
|
+
vs.state = :deleting
|
57
|
+
vs.save_changes
|
45
58
|
end
|
46
59
|
end
|
47
60
|
end
|
@@ -34,7 +34,15 @@ module Dcmgr
|
|
34
34
|
def update_instance(instance_id, data)
|
35
35
|
Models::Instance.lock!
|
36
36
|
inst = Models::Instance[instance_id]
|
37
|
-
inst.
|
37
|
+
raise "UnknownInstanceID" if inst.nil?
|
38
|
+
if data[:state] == :terminated
|
39
|
+
inst.terminated_at = data[:terminated_at]
|
40
|
+
# Instance#destroy do not really delete row.
|
41
|
+
# just for chain react destroy hooks in the associated models.
|
42
|
+
inst.destroy
|
43
|
+
else
|
44
|
+
inst.set(data).save
|
45
|
+
end
|
38
46
|
# do not respond model object.
|
39
47
|
nil
|
40
48
|
end
|
@@ -52,14 +60,31 @@ module Dcmgr
|
|
52
60
|
inst = Models::Instance[instance_id]
|
53
61
|
raise "UnknownInstanceID" if inst.nil?
|
54
62
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
63
|
+
ipv4s = inst.netfilter_groups.map { |netfilter_group|
|
64
|
+
next if netfilter_group.nil?
|
65
|
+
netfilter_group.instance_netfilter_groups.map { |instance_netfilter_group|
|
66
|
+
next if instance_netfilter_group.nil?
|
67
|
+
instance_netfilter_group.instance_dataset.lives.all.map { |instance|
|
68
|
+
next if instance.nil?
|
69
|
+
instance.ips.map { |ip|
|
70
|
+
next if ip.nil?
|
71
|
+
ip.ipv4
|
72
|
+
}
|
73
|
+
}
|
74
|
+
}
|
75
|
+
}.flatten.uniq.compact
|
76
|
+
ipv4s
|
77
|
+
end
|
60
78
|
|
61
|
-
|
62
|
-
|
79
|
+
# def get_instances_of_account_netfilter_group(account_id, netfilter_group_id)
|
80
|
+
def get_instances_of_account_netfilter_group(account_id, netfilter_group_name)
|
81
|
+
Models::NetfilterGroup.lock!
|
82
|
+
ng_map = Models::NetfilterGroup.find(:account_id => account_id, :name => netfilter_group_name)
|
83
|
+
raise "UnknownNetfilterGroupID" if ng_map.nil?
|
84
|
+
inst_maps = ng_map.instance_netfilter_groups.map { |instance_netfilter_group|
|
85
|
+
instance_netfilter_group.instance_dataset.lives.all.map { |inst| inst.to_hash }
|
86
|
+
}.flatten.uniq.compact
|
87
|
+
inst_maps
|
63
88
|
end
|
64
89
|
|
65
90
|
def get_network(network_id)
|
@@ -79,33 +104,55 @@ module Dcmgr
|
|
79
104
|
|
80
105
|
def get_dhcp_conf(network_name)
|
81
106
|
Models::Network.lock!
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
next if ip.instance_nic.nil? || ip.instance_nic.instance.nil?
|
98
|
-
|
99
|
-
h[:mac2addr] << {
|
100
|
-
:mac_addr => ip.instance_nic.pretty_mac_addr,
|
101
|
-
:ipaddr => ip.ipv4
|
107
|
+
|
108
|
+
build_network_segment = proc { |network|
|
109
|
+
gwaddr = network.ipaddress
|
110
|
+
h = {
|
111
|
+
:uuid => network.canonical_uuid,
|
112
|
+
:ipv4_first => gwaddr.network.first.to_s,
|
113
|
+
:ipv4_last => gwaddr.network.last.to_s,
|
114
|
+
:ipv4_gw=>network.ipv4_gw,
|
115
|
+
:netmask => gwaddr.network.prefix.to_ip,
|
116
|
+
:prefix => network.prefix,
|
117
|
+
:dns_server=> network.dns_server,
|
118
|
+
:domain_name => network.domain_name,
|
119
|
+
:metadata_server => network.metadata_server,
|
120
|
+
:mac2addr => [],
|
121
|
+
:addr2host=> [],
|
102
122
|
}
|
103
|
-
|
104
|
-
|
105
|
-
|
123
|
+
|
124
|
+
network.ip_lease_dataset.filter(:type=>Models::IpLease::TYPE_AUTO).each { |ip|
|
125
|
+
# ignore IPs unbound to vnic.
|
126
|
+
next if ip.instance_nic.nil? || ip.instance_nic.instance.nil?
|
127
|
+
|
128
|
+
h[:mac2addr] << {
|
129
|
+
:mac_addr => ip.instance_nic.pretty_mac_addr,
|
130
|
+
:ipaddr => ip.ipv4
|
131
|
+
}
|
132
|
+
h[:addr2host] << {
|
133
|
+
:hostname => ip.instance_nic.instance.fqdn_hostname,
|
134
|
+
:ipaddr => ip.ipv4
|
135
|
+
}
|
106
136
|
}
|
137
|
+
|
138
|
+
h
|
107
139
|
}
|
108
140
|
|
141
|
+
network_set = nil
|
142
|
+
Tags::NetworkPool
|
143
|
+
Models::Network
|
144
|
+
case network = Models::Taggable.find(network_name)
|
145
|
+
when Models::Network
|
146
|
+
network_set = [network]
|
147
|
+
when Tags::NetworkPool
|
148
|
+
network_set = network.mapped_uuids.map {|m| Models::Network[m.uuid] }
|
149
|
+
else
|
150
|
+
raise "Unknown network name: #{network_name}"
|
151
|
+
end
|
152
|
+
h = {}
|
153
|
+
network_set.each {|n|
|
154
|
+
h[n.canonical_uuid] = build_network_segment.call(n)
|
155
|
+
}
|
109
156
|
h
|
110
157
|
end
|
111
158
|
|
@@ -113,19 +160,22 @@ module Dcmgr
|
|
113
160
|
Models::NetfilterGroup.lock!
|
114
161
|
g = Models::NetfilterGroup[netfilter_group_id]
|
115
162
|
raise "UnknownNetfilterGroupID" if g.nil?
|
116
|
-
inst_maps = g.
|
117
|
-
|
163
|
+
inst_maps = g.instance_netfilter_groups.map { |instance_netfilter_group|
|
164
|
+
instance_netfilter_group.instance_dataset.lives.all.map { |inst| inst.to_hash }
|
165
|
+
}.flatten.uniq.compact
|
166
|
+
inst_maps
|
118
167
|
end
|
119
168
|
|
120
169
|
def get_alive_instances(node_id)
|
121
170
|
Models::HostPool.lock!
|
122
171
|
hp = Models::HostPool.find(:node_id => node_id)
|
123
172
|
raise "UnknownNodeID", node_id if hp.nil?
|
124
|
-
|
125
|
-
inst_on_hp =
|
126
|
-
inst
|
127
|
-
|
128
|
-
|
173
|
+
hps = Models::HostPool.where(:account_id => hp.account_id).all
|
174
|
+
inst_on_hp = hps.map { |hp|
|
175
|
+
inst_on_hp = hp.instances_dataset.lives.all.map { |inst|
|
176
|
+
inst.to_hash
|
177
|
+
}
|
178
|
+
}.flatten.uniq.compact
|
129
179
|
inst_on_hp
|
130
180
|
end
|
131
181
|
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'isono'
|
3
|
+
|
4
|
+
module Dcmgr
|
5
|
+
module NodeModules
|
6
|
+
class InstanceHA < Isono::NodeModules::Base
|
7
|
+
include Dcmgr::Logger
|
8
|
+
|
9
|
+
initialize_hook do
|
10
|
+
@thread_pool = Isono::ThreadPool.new
|
11
|
+
event = Isono::NodeModules::EventChannel.new(node)
|
12
|
+
event.subscribe('hva/fault_instance', '#') { |args|
|
13
|
+
@thread_pool.pass {
|
14
|
+
inst_id = args[0]
|
15
|
+
inst = Models::Instance[inst_id]
|
16
|
+
# check if the instance has HA enable.
|
17
|
+
next if inst.ha_enabled == 0
|
18
|
+
myinstance.restart_instance(inst)
|
19
|
+
}
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
terminate_hook do
|
24
|
+
@thread_pool.shutdown
|
25
|
+
end
|
26
|
+
|
27
|
+
def restart_instance(inst)
|
28
|
+
# terminate and cleanup
|
29
|
+
begin
|
30
|
+
jobrpc.run("kvm-handle.#{inst.host_pool.node_id}", 'cleanup', inst.canonical_uuid)
|
31
|
+
rescue => e
|
32
|
+
# termination may fail
|
33
|
+
end
|
34
|
+
|
35
|
+
# TODO: pick a new host node
|
36
|
+
Isono::NodeModules::DataStore.barrier {
|
37
|
+
inst.state = :failingover
|
38
|
+
inst.save
|
39
|
+
}
|
40
|
+
|
41
|
+
# start a new backup instance
|
42
|
+
case inst.image.boot_dev_type
|
43
|
+
when Models::Image::BOOT_DEV_SAN
|
44
|
+
boot_vol = inst.volume.find {|v| v.boot_dev == 1 }
|
45
|
+
res = jobrpc.submit("kvm-handle.#{inst.host_pool.node_id}", 'run_vol_store', inst.canonical_uuid, boot_vol.canonical_uuid)
|
46
|
+
when Models::Image::BOOT_DEV_LOCAL
|
47
|
+
res = jobrpc.submit("kvm-handle.#{inst.host_pool.node_id}", 'run_local_store', inst.canonical_uuid)
|
48
|
+
else
|
49
|
+
raise "Unknown boot type"
|
50
|
+
end
|
51
|
+
logger.info("#{inst.canonical_uuid} has been restarted")
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
def event
|
56
|
+
@event ||= Isono::NodeModules::EventChannel.new(node)
|
57
|
+
end
|
58
|
+
|
59
|
+
def jobrpc
|
60
|
+
@jobrpc ||= Isono::NodeModules::JobChannel.new(node)
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
data/lib/dcmgr/tags.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
module Dcmgr::Tags
|
4
|
+
include Dcmgr
|
5
|
+
KEY_MAP={10=>:NetworkPool, 11=>:HostPool, 12=>:StoragePool}.freeze
|
6
|
+
MODEL_MAP=KEY_MAP.invert.freeze
|
7
|
+
|
8
|
+
def self.type_id(class_or_sym)
|
9
|
+
k = case class_or_sym
|
10
|
+
when String, Symbol
|
11
|
+
class_or_sym.to_sym
|
12
|
+
when Class
|
13
|
+
class_or_sym.to_s.split('::').last.to_sym
|
14
|
+
end
|
15
|
+
|
16
|
+
MODEL_MAP[k] || raise("Unknown key to get type_id: #{class_or_sym}")
|
17
|
+
end
|
18
|
+
|
19
|
+
class NetworkPool < Models::Tag
|
20
|
+
def accept_mapping?(to)
|
21
|
+
to.is_a?(Dcmgr::Models::Network)
|
22
|
+
end
|
23
|
+
|
24
|
+
def pick()
|
25
|
+
lst = mapped_uuids.map { |t|
|
26
|
+
Dcmgr::Models::Network[t.uuid]
|
27
|
+
}.sort_by{ |n|
|
28
|
+
n.available_ip_nums
|
29
|
+
}.reverse.first
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class HostPool < Models::Tag
|
34
|
+
def accept_mapping?(to)
|
35
|
+
to.is_a?(Dcmgr::Models::HostNode)
|
36
|
+
end
|
37
|
+
|
38
|
+
def pick(spec)
|
39
|
+
mapped_uuids.map { |t|
|
40
|
+
Dcmgr::Models::HostPool[t.uuid]
|
41
|
+
}.find_all { |h|
|
42
|
+
h.check_capacity(spec)
|
43
|
+
}.sort_by { |h|
|
44
|
+
h.instances.count
|
45
|
+
}.reverse.first
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class StoragePool < Models::Tag
|
50
|
+
def accept_mapping?(to)
|
51
|
+
to.is_a?(Dcmgr::Models::StorageNode)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|