wakame-vdc-agents 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/hva +854 -449
- data/bin/nsa +56 -26
- data/bin/sta +11 -4
- data/config/hva.conf.example +9 -0
- data/config/nsa.conf.example +2 -2
- 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
@@ -45,6 +45,10 @@ module Dcmgr
|
|
45
45
|
define_error(:OutOfHostCapacity, 400)
|
46
46
|
define_error(:UnknownSshKeyPair, 404)
|
47
47
|
define_error(:UndefinedStoragePoolID, 400)
|
48
|
+
define_error(:DetachVolumeFailure, 400)
|
49
|
+
define_error(:AttachVolumeFailure, 400)
|
50
|
+
define_error(:InvalidInstanceState, 400)
|
51
|
+
define_error(:DuplicateHostname, 400)
|
48
52
|
|
49
53
|
# netfilter_group
|
50
54
|
define_error(:UndefinedNetfilterGroup, 400)
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'eventmachine'
|
4
|
+
require 'shellwords'
|
5
|
+
raise "Shellword is old version." unless Shellwords.respond_to?(:shellescape)
|
6
|
+
require 'open4'
|
7
|
+
|
8
|
+
module Dcmgr
|
9
|
+
module Helpers
|
10
|
+
module CliHelper
|
11
|
+
class TimeoutError < RuntimeError; end
|
12
|
+
|
13
|
+
def tryagain(opts={:timeout=>60, :retry=>3}, &blk)
|
14
|
+
timedout = false
|
15
|
+
curthread = Thread.current
|
16
|
+
|
17
|
+
timersig = EventMachine.add_timer(opts[:timeout]) {
|
18
|
+
timedout = true
|
19
|
+
if curthread
|
20
|
+
curthread.raise(TimeoutError.new("timeout"))
|
21
|
+
curthread.pass
|
22
|
+
end
|
23
|
+
}
|
24
|
+
|
25
|
+
count = opts[:retry]
|
26
|
+
begin
|
27
|
+
begin
|
28
|
+
break if blk.call
|
29
|
+
end while !timedout && ((count -= 1) >= 0)
|
30
|
+
rescue TimeoutError => e
|
31
|
+
raise e
|
32
|
+
rescue RuntimeError => e
|
33
|
+
if respond_to?(:logger)
|
34
|
+
logger.debug("Caught Error. To be retrying....: #{e}")
|
35
|
+
end
|
36
|
+
retry if (count -= 1) >= 0
|
37
|
+
ensure
|
38
|
+
curthread = nil
|
39
|
+
EventMachine.cancel_timer(timersig) rescue nil
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class CommandError < StandardError
|
44
|
+
attr_reader :stderr, :stdout
|
45
|
+
def initialize(msg, stdout, stderr)
|
46
|
+
super(msg)
|
47
|
+
@stdout = stdout
|
48
|
+
@stderr = stderr
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def sh(cmd, args=[], opts={})
|
53
|
+
opts = opts.merge({:expect_exitcode=>0})
|
54
|
+
cmd = sprintf(cmd, *args.map {|a| Shellwords.shellescape(a.to_s) })
|
55
|
+
|
56
|
+
outbuf = errbuf = ''
|
57
|
+
blk = proc {|pid, stdin, stdout, stderr|
|
58
|
+
stdin.close
|
59
|
+
outbuf = stdout.read
|
60
|
+
errbuf = stderr.read
|
61
|
+
}
|
62
|
+
stat = Open4::popen4(cmd, &blk)
|
63
|
+
if self.respond_to?(:logger)
|
64
|
+
logger.debug("Exec command (pid=#{stat.pid}): #{cmd}")
|
65
|
+
msg = "Command output:"
|
66
|
+
msg << "\nSTDOUT:\n#{outbuf.strip}" if outbuf && outbuf.strip.size > 0
|
67
|
+
msg << "\nSTDERR:\n#{errbuf.strip}" if errbuf && errbuf.strip.size > 0
|
68
|
+
logger.debug(msg)
|
69
|
+
end
|
70
|
+
if stat.exitstatus != opts[:expect_exitcode]
|
71
|
+
raise CommandError.new("Unexpected exit code=#{stat.exitstatus} (expected=#{opts[:expect_exitcode]})", \
|
72
|
+
outbuf, errbuf)
|
73
|
+
end
|
74
|
+
true
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
end
|
data/lib/dcmgr/models/account.rb
CHANGED
@@ -3,10 +3,6 @@
|
|
3
3
|
module Dcmgr::Models
|
4
4
|
class Account < BaseNew
|
5
5
|
taggable 'a'
|
6
|
-
with_timestamps
|
7
|
-
plugin :single_table_inheritance, :uuid, :model_map=>{}
|
8
|
-
plugin :subclasses
|
9
|
-
|
10
6
|
# pk has to be overwritten by the STI subclasses.
|
11
7
|
unrestrict_primary_key
|
12
8
|
|
@@ -17,8 +13,14 @@ module Dcmgr::Models
|
|
17
13
|
String :description, :size=>100
|
18
14
|
Fixnum :enabled, :default=>ENABLED, :null=>false
|
19
15
|
end
|
16
|
+
with_timestamps
|
20
17
|
|
21
|
-
one_to_many :tags
|
18
|
+
one_to_many :tags, :dataset=>lambda { Tag.filter(:account_id=>self.canonical_uuid); }
|
19
|
+
|
20
|
+
# sti plugin has to be loaded at lower position.
|
21
|
+
plugin :subclasses
|
22
|
+
plugin :single_table_inheritance, :uuid, :model_map=>{}
|
23
|
+
|
22
24
|
|
23
25
|
def disable?
|
24
26
|
self.enabled == DISABLED
|
@@ -28,13 +30,6 @@ module Dcmgr::Models
|
|
28
30
|
self.enabled == ENABLED
|
29
31
|
end
|
30
32
|
|
31
|
-
def to_hash_document
|
32
|
-
h = self.values.dup
|
33
|
-
h[:id] = h[:uuid] = self.canonical_uuid
|
34
|
-
h
|
35
|
-
end
|
36
|
-
|
37
|
-
|
38
33
|
# STI class variable setter, getter methods.
|
39
34
|
class << self
|
40
35
|
def default_values
|
@@ -98,6 +93,18 @@ module Dcmgr::Models
|
|
98
93
|
self.enabled = Account::ENABLED
|
99
94
|
end
|
100
95
|
end
|
96
|
+
|
97
|
+
SystemAccount.define_account(:SharedPoolAccount) do
|
98
|
+
pk 101
|
99
|
+
uuid 'shpoolxx'
|
100
|
+
description 'system account for shared resources'
|
101
|
+
|
102
|
+
# SahredPoolAccount is always enabled.
|
103
|
+
def before_save
|
104
|
+
super
|
105
|
+
self.enabled = Account::ENABLED
|
106
|
+
end
|
107
|
+
end
|
101
108
|
|
102
109
|
end
|
103
110
|
end
|
@@ -50,6 +50,7 @@ module Dcmgr::Models
|
|
50
50
|
column(:uuid, String, :size=>8, :null=>false, :fixed=>true, :unique=>true)
|
51
51
|
end
|
52
52
|
}
|
53
|
+
model.many_to_many :tags, :dataset=>lambda { Tag.join(TagMapping.table_name, :tag_id=>:id, :uuid=>self.canonical_uuid); }
|
53
54
|
end
|
54
55
|
|
55
56
|
module InstanceMethods
|
@@ -65,6 +66,12 @@ module Dcmgr::Models
|
|
65
66
|
self[:uuid] ||= Array.new(8) do UUID_TABLE[rand(UUID_TABLE.size)]; end.join
|
66
67
|
end
|
67
68
|
|
69
|
+
# model hook
|
70
|
+
def after_destroy
|
71
|
+
super
|
72
|
+
TagMapping.filter(:uuid=>self.canonical_uuid).delete
|
73
|
+
end
|
74
|
+
|
68
75
|
# Returns canonicalized uuid which has the form of
|
69
76
|
# "{uuid_prefix}-{uuid}".
|
70
77
|
def canonical_uuid
|
@@ -74,36 +81,56 @@ module Dcmgr::Models
|
|
74
81
|
|
75
82
|
# Put the tag on the object.
|
76
83
|
#
|
77
|
-
#
|
78
|
-
# @params [
|
79
|
-
|
80
|
-
|
84
|
+
# @params [Models::Tag,String,Symbol] arg1
|
85
|
+
# @params [String,NilClass] arg2
|
86
|
+
# @params [String,NilClass] arg3
|
87
|
+
#
|
88
|
+
# @example
|
89
|
+
# lable_tag('tag-xxxxx')
|
90
|
+
# t = Tag['tag-xxxx']
|
91
|
+
# label_tag(t)
|
92
|
+
# label_tag(:NetworkPool, 'newname1', 'account_id')
|
93
|
+
def label_tag(arg1, arg2=nil, arg3=nil)
|
94
|
+
tag = case arg1
|
81
95
|
when String
|
82
|
-
Tag[
|
96
|
+
Tag[arg1]
|
97
|
+
when Symbol
|
98
|
+
acctid = arg3 || self.respond_to?(:account_id) ? self.account_id : raise("Unknown Account ID")
|
99
|
+
Dcmgr::Tags.const_get(arg1).find_or_create(:account_id=>acctid, :name=>arg2)
|
83
100
|
when Tag
|
84
|
-
|
101
|
+
arg1
|
85
102
|
else
|
86
|
-
raise ArgumentError, "Invalid type: #{
|
103
|
+
raise ArgumentError, "Invalid type: #{arg1.class}"
|
87
104
|
end
|
88
|
-
|
89
|
-
tag.label(self.
|
105
|
+
raise "Root Tag class can not be used" unless tag.class < Tag
|
106
|
+
tag.label(self.canonical_uuid)
|
90
107
|
end
|
91
108
|
|
92
109
|
# Remove the labeled tag from the object
|
93
110
|
#
|
94
|
-
#
|
95
|
-
# @params [
|
96
|
-
|
97
|
-
|
111
|
+
# @params [Models::Tag,String,Symbol] arg1
|
112
|
+
# @params [String,NilClass] arg2
|
113
|
+
# @params [String,NilClass] arg3
|
114
|
+
#
|
115
|
+
# @example
|
116
|
+
# unlable_tag('tag-xxxxx')
|
117
|
+
# t = Tag['tag-xxxx']
|
118
|
+
# unlabel_tag(t)
|
119
|
+
# unlabel_tag(:NetworkPool, 'newname1', 'account_id')
|
120
|
+
def unlabel_tag(arg1, arg2=nil, arg3=nil)
|
121
|
+
tag = case arg1
|
98
122
|
when String
|
99
|
-
Tag[
|
123
|
+
Tag[arg1]
|
124
|
+
when Symbol
|
125
|
+
acctid = arg3 || self.respond_to?(:account_id) ? self.account_id : raise("Unknown Account ID")
|
126
|
+
Dcmgr::Tags.const_get(arg1).find(:account_id=>acctid, :name=>arg2)
|
100
127
|
when Tag
|
101
|
-
|
128
|
+
arg1
|
102
129
|
else
|
103
|
-
raise ArgumentError, "Invalid type: #{
|
130
|
+
raise ArgumentError, "Invalid type: #{arg1.class}"
|
104
131
|
end
|
105
132
|
|
106
|
-
tag.unlabel(self.
|
133
|
+
tag.unlabel(self.canonical_uuid)
|
107
134
|
end
|
108
135
|
|
109
136
|
def to_hash()
|
@@ -256,7 +283,116 @@ module Dcmgr::Models
|
|
256
283
|
end
|
257
284
|
|
258
285
|
end
|
259
|
-
|
286
|
+
|
287
|
+
# This plugin is to archive the changes on each column of the model
|
288
|
+
# to a history table.
|
289
|
+
#
|
290
|
+
# plugin ArchiveChangedColumn, :your_history_table
|
291
|
+
# or
|
292
|
+
# plugin ArchiveChangedColumn
|
293
|
+
# history_dataset = DB[:history_table]
|
294
|
+
#
|
295
|
+
# The history table should have the schema below:
|
296
|
+
# schema do
|
297
|
+
# Fixnum :id, :null=>false, :primary_key=>true
|
298
|
+
# String :uuid, :size=>50, :null=>false
|
299
|
+
# String :attr, :null=>false
|
300
|
+
# String :vchar_value, :null=>true
|
301
|
+
# String :blob_value, :null=>true, :text=>true
|
302
|
+
# Time :created_at, :null=>false
|
303
|
+
# index [:uuid, :created_at]
|
304
|
+
# index [:uuid, :attr]
|
305
|
+
# end
|
306
|
+
module ArchiveChangedColumn
|
307
|
+
def self.configure(model, history_table=nil)
|
308
|
+
model.history_dataset = case history_table
|
309
|
+
when NilClass
|
310
|
+
nil
|
311
|
+
when String,Symbol
|
312
|
+
model.db.from(history_table)
|
313
|
+
when Class
|
314
|
+
raise "Unknown type" unless history_table < Sequel::Model
|
315
|
+
history_table.dataset
|
316
|
+
when Sequel::Dataset
|
317
|
+
history_table
|
318
|
+
else
|
319
|
+
raise "Unknown type"
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
module ClassMethods
|
324
|
+
def history_dataset=(ds)
|
325
|
+
@history_ds = ds
|
326
|
+
end
|
327
|
+
|
328
|
+
def history_dataset
|
329
|
+
@history_ds
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
module InstanceMethods
|
334
|
+
def history_snapshot(at)
|
335
|
+
raise TypeError unless at.is_a?(Time)
|
336
|
+
|
337
|
+
if self.created_at > at || (!self.terminated_at.nil? && self.terminated_at < at)
|
338
|
+
raise "#{at} is not in the range of the object's life span."
|
339
|
+
end
|
340
|
+
|
341
|
+
ss = self.dup
|
342
|
+
# SELECT * FROM (SELECT * FROM `instance_histories` WHERE
|
343
|
+
# (`uuid` = 'i-ezsrs132') AND created_at <= '2010-11-30 23:08:05'
|
344
|
+
# ORDER BY created_at DESC) AS a GROUP BY a.attr;
|
345
|
+
ds = self.class.history_dataset.filter('uuid=? AND created_at <= ?', self.canonical_uuid, at).order(:created_at.desc)
|
346
|
+
ds = ds.from_self.group_by(:attr)
|
347
|
+
ds.all.each { |h|
|
348
|
+
if !h[:blob_value].nil?
|
349
|
+
ss.send("#{h[:attr]}=", typecast_value(h[:attr], h[:blob_value]))
|
350
|
+
else
|
351
|
+
ss.send("#{h[:attr]}=", typecast_value(h[:attr], h[:vchar_value]))
|
352
|
+
end
|
353
|
+
}
|
354
|
+
# take care for serialized columns by serialization plugin.
|
355
|
+
ss.deserialized_values.clear if ss.respond_to?(:deserialized_values)
|
356
|
+
|
357
|
+
ss
|
358
|
+
end
|
359
|
+
|
360
|
+
def before_create
|
361
|
+
return false if super == false
|
362
|
+
store_changes(self.columns)
|
363
|
+
true
|
364
|
+
end
|
365
|
+
|
366
|
+
def before_update
|
367
|
+
return false if super == false
|
368
|
+
store_changes(self.changed_columns)
|
369
|
+
true
|
370
|
+
end
|
371
|
+
|
372
|
+
private
|
373
|
+
def store_changes(cols_stored)
|
374
|
+
return if cols_stored.nil? || cols_stored.empty?
|
375
|
+
common_rec = {
|
376
|
+
:uuid=>self.canonical_uuid,
|
377
|
+
:created_at => Time.now,
|
378
|
+
}
|
379
|
+
|
380
|
+
cols_stored.each { |c|
|
381
|
+
hist_rec = common_rec.dup
|
382
|
+
hist_rec[:attr] = c.to_s
|
383
|
+
|
384
|
+
coldef = self.class.db_schema[c]
|
385
|
+
case coldef[:type]
|
386
|
+
when :text,:blob
|
387
|
+
hist_rec[:blob_value]= (new? ? (self[c] || coldef[:default]) : self[c])
|
388
|
+
else
|
389
|
+
hist_rec[:vchar_value]=(new? ? (self[c] || coldef[:default]) : self[c])
|
390
|
+
end
|
391
|
+
self.class.history_dataset.insert(hist_rec)
|
392
|
+
}
|
393
|
+
end
|
394
|
+
end
|
395
|
+
end
|
260
396
|
|
261
397
|
class BaseNew < Sequel::Model
|
262
398
|
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
module Dcmgr::Models
|
4
|
+
# History record table for ArchiveChangedColumn plugin
|
5
|
+
class History < BaseNew
|
6
|
+
set_dataset(:histories)
|
7
|
+
|
8
|
+
inheritable_schema do
|
9
|
+
String :uuid, :size=>50, :null=>false
|
10
|
+
String :attr, :null=>false
|
11
|
+
String :vchar_value, :null=>true
|
12
|
+
String :blob_value, :null=>true, :text=>true
|
13
|
+
Time :created_at, :null=>false
|
14
|
+
index [:uuid, :created_at]
|
15
|
+
index [:uuid, :attr]
|
16
|
+
end
|
17
|
+
|
18
|
+
plugin :timestamps
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -19,16 +19,15 @@ module Dcmgr::Models
|
|
19
19
|
|
20
20
|
String :arch, :size=>10, :null=>false # :x86, :x86_64
|
21
21
|
String :hypervisor, :size=>30, :null=>false
|
22
|
-
Fixnum :network_id, :null=>false
|
23
22
|
|
24
23
|
Fixnum :offering_cpu_cores, :null=>false, :unsigned=>true
|
25
24
|
Fixnum :offering_memory_size, :null=>false, :unsigned=>true
|
26
|
-
|
25
|
+
|
26
|
+
index :node_id
|
27
27
|
end
|
28
28
|
|
29
29
|
one_to_many :instances
|
30
30
|
many_to_one :node, :class=>Isono::Models::NodeState, :key=>:node_id, :primary_key=>:node_id
|
31
|
-
many_to_one :network
|
32
31
|
|
33
32
|
def after_initialize
|
34
33
|
super
|
@@ -66,10 +65,12 @@ module Dcmgr::Models
|
|
66
65
|
# @param [Models::Account] account
|
67
66
|
# @param [Models::Image] image
|
68
67
|
# @param [Models::InstanceSpec] spec
|
68
|
+
# @param [Models::Network] network
|
69
69
|
# @return [Models::Instance] created new Instance object.
|
70
|
-
def create_instance(account, image, spec, &blk)
|
70
|
+
def create_instance(account, image, spec, network, &blk)
|
71
71
|
raise ArgumentError unless image.is_a?(Image)
|
72
72
|
raise ArgumentError unless spec.is_a?(InstanceSpec)
|
73
|
+
raise ArgumentError unless network.is_a?(Network)
|
73
74
|
i = Instance.new &blk
|
74
75
|
i.account_id = account.canonical_uuid
|
75
76
|
i.image = image
|
@@ -77,9 +78,8 @@ module Dcmgr::Models
|
|
77
78
|
i.host_pool = self
|
78
79
|
i.save
|
79
80
|
|
80
|
-
|
81
|
-
vnic
|
82
|
-
IpLease.lease(vnic)
|
81
|
+
vnic = i.add_nic(network)
|
82
|
+
IpLease.lease(vnic, network)
|
83
83
|
i
|
84
84
|
end
|
85
85
|
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
module Dcmgr::Models
|
4
|
+
# hostname table for each instance to ensure uniqueness.
|
5
|
+
class HostnameLease < BaseNew
|
6
|
+
|
7
|
+
inheritable_schema do
|
8
|
+
String :account_id, :null=>false, :size=>50
|
9
|
+
String :hostname, :null=>false, :size=>32
|
10
|
+
|
11
|
+
index [:account_id, :hostname], {:unique=>true}
|
12
|
+
end
|
13
|
+
with_timestamps
|
14
|
+
end
|
15
|
+
end
|
@@ -16,17 +16,16 @@ module Dcmgr::Models
|
|
16
16
|
Fixnum :instance_spec_id, :null=>false
|
17
17
|
String :state, :size=>20, :null=>false, :default=>:init.to_s
|
18
18
|
String :status, :size=>20, :null=>false, :default=>:init.to_s
|
19
|
-
String :hostname, :null=>false
|
19
|
+
String :hostname, :null=>false, :size=>32
|
20
20
|
String :ssh_key_pair_id
|
21
|
+
Fixnum :ha_enabled, :null=>false, :default=>0
|
21
22
|
|
22
23
|
Text :user_data, :null=>false, :default=>''
|
23
24
|
Text :runtime_config, :null=>false, :default=>''
|
24
25
|
|
25
|
-
Time
|
26
|
+
Time :terminated_at
|
26
27
|
index :state
|
27
28
|
index :terminated_at
|
28
|
-
# can not use same hostname within an account.
|
29
|
-
index [:account_id, :hostname], {:unique=>true}
|
30
29
|
end
|
31
30
|
with_timestamps
|
32
31
|
|
@@ -41,29 +40,116 @@ module Dcmgr::Models
|
|
41
40
|
many_to_many :netfilter_groups, :join_table=>:instance_netfilter_groups
|
42
41
|
many_to_one :ssh_key_pair
|
43
42
|
|
43
|
+
plugin ArchiveChangedColumn, :histories
|
44
|
+
|
44
45
|
subset(:lives, {:terminated_at => nil})
|
45
46
|
|
46
47
|
# serialization plugin must be defined at the bottom of all class
|
47
48
|
# method calls.
|
48
49
|
# Possible column data:
|
49
50
|
# kvm:
|
50
|
-
# {:vnc_port=>11}
|
51
|
+
# {:vnc_port=>11, :telnet_port=>1111}
|
51
52
|
plugin :serialization
|
52
53
|
serialize_attributes :yaml, :runtime_config
|
53
54
|
|
55
|
+
module ValidationMethods
|
56
|
+
def self.hostname_uniqueness(account_id, hostname)
|
57
|
+
HostnameLease.filter(:account_id=>account_id, :hostname=>hostname).empty?
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
54
61
|
def validate
|
55
62
|
super
|
56
63
|
|
57
|
-
|
64
|
+
unless self.hostname =~ /\A[0-9a-z][0-9a-z\-]{0,31}\Z/
|
65
|
+
errors.add(:hostname, "Invalid hostname syntax")
|
66
|
+
end
|
67
|
+
|
68
|
+
# uniqueness check for hostname
|
69
|
+
if changed_columns.include?(:hostname)
|
70
|
+
proc_test = lambda {
|
71
|
+
unless ValidationMethods.hostname_uniqueness(self.account_id, self.hostname)
|
72
|
+
errors.add(:hostname, "Duplicated hostname: #{self.hostname}")
|
73
|
+
end
|
74
|
+
}
|
75
|
+
|
76
|
+
if new?
|
77
|
+
proc_test.call
|
78
|
+
else
|
79
|
+
orig = self.dup.refresh
|
80
|
+
# do nothing if orig.hostname == self.hostname
|
81
|
+
if orig.hostname != self.hostname
|
82
|
+
proc_test.call
|
83
|
+
end
|
84
|
+
end
|
85
|
+
@update_hostname = true
|
86
|
+
end
|
87
|
+
|
88
|
+
# check runtime_config column
|
89
|
+
case self.hypervisor
|
90
|
+
when HostPool::HYPERVISOR_KVM
|
91
|
+
r1 = self.runtime_config
|
92
|
+
self.host_pool.instances.each { |i|
|
93
|
+
next true if i.id == self.id
|
94
|
+
r2 = i.runtime_config
|
95
|
+
unless r1[:vnc_port] != r2[:vnc_port] && r1[:telnet_port] != r2[:telnet_port]
|
96
|
+
errors.add(:runtime_config, "#{self.canonical_uuid}.runtime_config conflicted with #{i.canonical_uuid}")
|
97
|
+
break
|
98
|
+
end
|
99
|
+
}
|
100
|
+
end
|
58
101
|
end
|
59
102
|
|
60
103
|
def before_validation
|
104
|
+
self[:user_data] ||= ''
|
105
|
+
self[:hostname] ||= self.uuid
|
106
|
+
self[:hostname] = self[:hostname].downcase
|
61
107
|
super
|
108
|
+
end
|
62
109
|
|
63
|
-
|
64
|
-
|
110
|
+
def before_save
|
111
|
+
if @update_hostname
|
112
|
+
if new?
|
113
|
+
HostnameLease.create(:account_id=>self.account_id,
|
114
|
+
:hostname=>self.hostname)
|
115
|
+
else
|
116
|
+
orig = self.dup.refresh
|
117
|
+
# do nothing if orig.hostname == self.hostname
|
118
|
+
if orig.hostname != self.hostname
|
119
|
+
|
120
|
+
orig_name = HostnameLease.filter(:account_id=>self.account_id,
|
121
|
+
:hostname=>orig.hostname).first
|
122
|
+
orig_name.hostname = self.hostname
|
123
|
+
orig_name.save
|
124
|
+
end
|
125
|
+
end
|
126
|
+
@update_hostname = false
|
127
|
+
end
|
128
|
+
|
129
|
+
super
|
65
130
|
end
|
66
131
|
|
132
|
+
def before_destroy
|
133
|
+
HostnameLease.filter(:account_id=>self.account_id, :hostname=>self.hostname).destroy
|
134
|
+
self.instance_nic.each { |o| o.destroy }
|
135
|
+
self.instance_netfilter_groups.each{|o| o.destroy }
|
136
|
+
self.volume.each { |v|
|
137
|
+
v.instance_id = nil
|
138
|
+
v.state = :available
|
139
|
+
v.save
|
140
|
+
}
|
141
|
+
super
|
142
|
+
end
|
143
|
+
|
144
|
+
# override Sequel::Model#_delete not to delete rows but to set
|
145
|
+
# delete flags.
|
146
|
+
def _delete
|
147
|
+
self.terminated_at ||= Time.now
|
148
|
+
self.state = :terminated if self.state != :terminated
|
149
|
+
self.status = :offline if self.status != :offline
|
150
|
+
self.save
|
151
|
+
end
|
152
|
+
|
67
153
|
# dump column data as hash with details of associated models.
|
68
154
|
# this is for internal use.
|
69
155
|
def to_hash
|
@@ -74,11 +160,12 @@ module Dcmgr::Models
|
|
74
160
|
:host_pool=>host_pool.to_hash,
|
75
161
|
:instance_nics=>instance_nic.map {|n| n.to_hash },
|
76
162
|
:instance_spec=>instance_spec.to_hash,
|
163
|
+
:ips => instance_nic.map { |n| n.ip.ipv4 if n.ip },
|
77
164
|
})
|
78
165
|
h[:volume]={}
|
79
166
|
if self.volume
|
80
167
|
self.volume.each { |v|
|
81
|
-
h[:volume][v.canonical_uuid] = v.
|
168
|
+
h[:volume][v.canonical_uuid] = v.to_hash
|
82
169
|
}
|
83
170
|
end
|
84
171
|
h
|
@@ -92,8 +179,8 @@ module Dcmgr::Models
|
|
92
179
|
# :cpu_cores
|
93
180
|
# :memory_size
|
94
181
|
# :image_id
|
95
|
-
# :network => {'
|
96
|
-
# :volume => {'uuid'=>{:guest_device_name=>,}
|
182
|
+
# :network => [{:network_name=>'nw-xxxxxxx', :ipaddr=>'111.111.111.111'}]
|
183
|
+
# :volume => [{'uuid'=>{:guest_device_name=>,}]
|
97
184
|
# :ssh_key_pair => 'xxxxx',
|
98
185
|
# :netfilter_group => ['rule1', 'rule2']
|
99
186
|
# :created_at
|
@@ -122,7 +209,7 @@ module Dcmgr::Models
|
|
122
209
|
instance_nic.each { |n|
|
123
210
|
if n.ip
|
124
211
|
h[:network] << {
|
125
|
-
:network_name => n.
|
212
|
+
:network_name => n.network.canonical_uuid,
|
126
213
|
:ipaddr => n.ip.ipv4
|
127
214
|
}
|
128
215
|
end
|
@@ -169,13 +256,11 @@ module Dcmgr::Models
|
|
169
256
|
self.instance_spec.config
|
170
257
|
end
|
171
258
|
|
172
|
-
def add_nic(
|
173
|
-
vifname ||= "vif-#{self[:uuid]}"
|
259
|
+
def add_nic(network, vendor_id=nil)
|
174
260
|
# TODO: get default vendor ID based on the hypervisor.
|
175
261
|
vendor_id ||= '00:ff:f1'
|
176
|
-
nic = InstanceNic.new(
|
177
|
-
|
178
|
-
})
|
262
|
+
nic = InstanceNic.new(:mac_addr=>vendor_id)
|
263
|
+
nic.network = network
|
179
264
|
nic.instance = self
|
180
265
|
nic.save
|
181
266
|
end
|
@@ -202,15 +287,15 @@ module Dcmgr::Models
|
|
202
287
|
self.instance_nic.map { |nic| nic.ip }
|
203
288
|
end
|
204
289
|
|
205
|
-
def netfilter_group_instances
|
206
|
-
instances = self.netfilter_groups.map { |g| g.instances }
|
207
|
-
|
208
|
-
instances.flatten!.uniq! if instances.size > 0
|
209
|
-
instances
|
210
|
-
end
|
290
|
+
# def netfilter_group_instances
|
291
|
+
# instances = self.netfilter_groups.map { |g| g.instances }
|
292
|
+
#
|
293
|
+
# instances.flatten!.uniq! if instances.size > 0
|
294
|
+
# instances
|
295
|
+
# end
|
211
296
|
|
212
297
|
def fqdn_hostname
|
213
|
-
sprintf("%s.%s.%s", self.hostname, self.account.uuid, self.
|
298
|
+
sprintf("%s.%s.%s", self.hostname, self.account.uuid, self.nic.first.network.domain_name)
|
214
299
|
end
|
215
300
|
|
216
301
|
# Retrieve all networks belong to this instance
|
@@ -221,7 +306,7 @@ module Dcmgr::Models
|
|
221
306
|
}.map { |nic|
|
222
307
|
nic.ip.network
|
223
308
|
}.group_by { |net|
|
224
|
-
net.
|
309
|
+
net.canonical_uuid
|
225
310
|
}.values.map { |i|
|
226
311
|
i.first
|
227
312
|
}
|
@@ -251,5 +336,9 @@ module Dcmgr::Models
|
|
251
336
|
VolumeSnapshot.lock!
|
252
337
|
IpLease.lock!
|
253
338
|
end
|
339
|
+
|
340
|
+
def live?
|
341
|
+
self.terminated_at.nil?
|
342
|
+
end
|
254
343
|
end
|
255
344
|
end
|