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
@@ -3,18 +3,19 @@
|
|
3
3
|
module Dcmgr::Models
|
4
4
|
# Network interface for running instance.
|
5
5
|
class InstanceNic < BaseNew
|
6
|
-
taggable '
|
6
|
+
taggable 'vif'
|
7
7
|
|
8
8
|
inheritable_schema do
|
9
9
|
Fixnum :instance_id, :null=>false
|
10
|
-
|
10
|
+
Fixnum :network_id, :null=>false
|
11
11
|
String :mac_addr, :null=>false, :size=>12
|
12
12
|
|
13
|
-
index :mac_addr
|
13
|
+
index :mac_addr
|
14
14
|
end
|
15
15
|
with_timestamps
|
16
16
|
|
17
17
|
many_to_one :instance
|
18
|
+
many_to_one :network
|
18
19
|
one_to_one :ip, :class=>IpLease
|
19
20
|
|
20
21
|
def to_hash
|
@@ -24,28 +25,32 @@ module Dcmgr::Models
|
|
24
25
|
end
|
25
26
|
|
26
27
|
def before_validation
|
27
|
-
|
28
|
-
m = normalize_mac_addr(self[:mac_addr])
|
29
|
-
if m
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
28
|
+
newlease=nil
|
29
|
+
m = self[:mac_addr] = normalize_mac_addr(self[:mac_addr])
|
30
|
+
if m
|
31
|
+
if m.size == 6
|
32
|
+
newlease = MacLease.lease(m)
|
33
|
+
else
|
34
|
+
MacLease.create(:mac_addr=>m)
|
35
|
+
end
|
36
|
+
else
|
37
|
+
newlease = MacLease.lease()
|
37
38
|
end
|
38
|
-
|
39
|
+
self[:mac_addr] = newlease.mac_addr if newlease
|
40
|
+
|
41
|
+
super
|
39
42
|
end
|
40
43
|
|
41
|
-
def
|
44
|
+
def before_destroy
|
45
|
+
MacLease.find(:mac_addr=>self.mac_addr).destroy
|
46
|
+
ip && ip.destroy
|
42
47
|
super
|
48
|
+
end
|
43
49
|
|
44
|
-
|
45
|
-
|
46
|
-
end
|
50
|
+
def validate
|
51
|
+
super
|
47
52
|
|
48
|
-
unless self.mac_addr =~ /^[0-9a-f]{12}$/
|
53
|
+
unless self.mac_addr.size == 12 && self.mac_addr =~ /^[0-9a-f]{12}$/
|
49
54
|
errors.add(:mac_addr, "Invalid mac address syntax: #{self.mac_addr}")
|
50
55
|
end
|
51
56
|
end
|
@@ -14,8 +14,28 @@ module Dcmgr::Models
|
|
14
14
|
end
|
15
15
|
with_timestamps
|
16
16
|
|
17
|
+
# serialization plugin must be defined at the bottom of all class
|
18
|
+
# method calls.
|
19
|
+
# Possible column data:
|
20
|
+
# hypervisor=kvm:
|
21
|
+
# {:block_driver=>'virtio', :nic_driver=>'virtio'}
|
22
|
+
plugin :serialization
|
23
|
+
serialize_attributes :yaml, :config
|
24
|
+
|
25
|
+
def before_validate
|
26
|
+
default_config =
|
27
|
+
case self.hypervisor
|
28
|
+
when HostPool::HYPERVISOR_KVM
|
29
|
+
{:block_driver=>'virtio', :nic_driver=>'virtio'}
|
30
|
+
end
|
31
|
+
|
32
|
+
self.config = default_config.merge(self.config || {})
|
33
|
+
super
|
34
|
+
end
|
35
|
+
|
17
36
|
def to_hash
|
18
|
-
super.merge({:config=>config
|
37
|
+
super.merge({:config=>self.config, # yaml -> Hash
|
38
|
+
})
|
19
39
|
end
|
20
40
|
end
|
21
41
|
end
|
@@ -5,35 +5,48 @@ require 'ipaddress'
|
|
5
5
|
module Dcmgr::Models
|
6
6
|
# IP address lease information
|
7
7
|
class IpLease < BaseNew
|
8
|
-
|
8
|
+
TYPE_AUTO=0
|
9
|
+
TYPE_RESERVED=1
|
10
|
+
TYPE_MANUAL=2
|
11
|
+
|
9
12
|
inheritable_schema do
|
10
|
-
Fixnum :instance_nic_id
|
13
|
+
Fixnum :instance_nic_id
|
11
14
|
Fixnum :network_id, :null=>false
|
12
15
|
String :ipv4, :size=>50
|
16
|
+
Fixnum :type, :null=>false, :default=>TYPE_AUTO
|
17
|
+
Text :description
|
13
18
|
|
14
|
-
index :ipv4, {:unique=>true}
|
19
|
+
index [:network_id, :ipv4], {:unique=>true}
|
15
20
|
end
|
16
21
|
with_timestamps
|
17
22
|
|
18
23
|
many_to_one :instance_nic
|
19
24
|
many_to_one :network
|
20
25
|
|
21
|
-
def
|
26
|
+
def validate
|
27
|
+
# validate ipv4 syntax
|
28
|
+
begin
|
29
|
+
addr = IPAddress::IPv4.new("#{self.ipv4}")
|
30
|
+
# validate if ipv4 is in the range of network_id.
|
31
|
+
unless network.ipaddress.network.include?(addr)
|
32
|
+
errors.add(:ipv4, "IP address #{addr} is out of range: #{network.canonical_uuid})")
|
33
|
+
end
|
34
|
+
rescue => e
|
35
|
+
errors.add(:ipv4, "Invalid IP address syntax: #{self.ipv4} (#{e})")
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.lease(instance_nic, network)
|
22
40
|
raise TypeError unless instance_nic.is_a?(InstanceNic)
|
23
|
-
|
24
|
-
|
25
|
-
gwaddr =
|
41
|
+
raise TypeError unless network.is_a?(Network)
|
42
|
+
|
43
|
+
gwaddr = network.ipaddress
|
26
44
|
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
45
|
reserved = reserved.map {|i| i.to_u32 }
|
33
46
|
# use SELECT FOR UPDATE to lock rows within same network.
|
34
|
-
addrs = (gwaddr.first.to_u32 .. gwaddr.last.to_u32).to_a -
|
47
|
+
addrs = (gwaddr.network.first.to_u32 .. gwaddr.network.last.to_u32).to_a -
|
35
48
|
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?
|
49
|
+
raise "Out of free IP address in this network segment: #{gwaddr.network.to_s}/#{gwaddr.prefix}" if addrs.empty?
|
37
50
|
|
38
51
|
leaseaddr = IPAddress::IPv4.parse_u32(addrs[rand(addrs.size).to_i])
|
39
52
|
create(:ipv4=>leaseaddr.to_s, :network_id=>network.id, :instance_nic_id=>instance_nic.id)
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
module Dcmgr::Models
|
4
|
+
# MAC address lease information
|
5
|
+
class MacLease < BaseNew
|
6
|
+
|
7
|
+
inheritable_schema do
|
8
|
+
String :mac_addr, :size=>12, :fixed=>true, :null=>false
|
9
|
+
|
10
|
+
index :mac_addr, {:unique=>true}
|
11
|
+
end
|
12
|
+
with_timestamps
|
13
|
+
|
14
|
+
# dynamically assign new MAC address.
|
15
|
+
def self.lease(vendor_id='00ff01')
|
16
|
+
begin
|
17
|
+
m = vendor_id + ("%02x%02x%02x" % [rand(0xff),rand(0xff),rand(0xff)])
|
18
|
+
end while self.find(:mac_addr=> m)
|
19
|
+
create(:mac_addr=>m)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -49,10 +49,11 @@ module Dcmgr::Models
|
|
49
49
|
NetfilterRule.filter(:netfilter_group_id => self.id).destroy
|
50
50
|
end
|
51
51
|
|
52
|
-
def
|
52
|
+
def before_destroy
|
53
53
|
self.flush_rule
|
54
|
-
|
54
|
+
super
|
55
55
|
end
|
56
|
+
alias :destroy_group :destroy
|
56
57
|
|
57
58
|
def rebuild_rule
|
58
59
|
self.flush_rule
|
data/lib/dcmgr/models/network.rb
CHANGED
@@ -1,32 +1,69 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
|
3
|
+
require 'ipaddress'
|
4
|
+
|
3
5
|
module Dcmgr::Models
|
4
|
-
#
|
5
|
-
class Network <
|
6
|
+
# IP network definitions.
|
7
|
+
class Network < AccountResource
|
8
|
+
taggable 'nw'
|
6
9
|
|
7
10
|
inheritable_schema do
|
8
|
-
String :name, :null=>false
|
9
11
|
String :ipv4_gw, :null=>false
|
10
12
|
Fixnum :prefix, :null=>false, :default=>24, :unsigned=>true
|
11
|
-
String :domain_name
|
12
|
-
String :dns_server
|
13
|
-
String :dhcp_server
|
13
|
+
String :domain_name
|
14
|
+
String :dns_server
|
15
|
+
String :dhcp_server
|
14
16
|
String :metadata_server
|
17
|
+
Fixnum :vlan_lease_id, :null=>false
|
15
18
|
Text :description
|
16
|
-
index :name, {:unique=>true}
|
17
19
|
end
|
18
20
|
with_timestamps
|
19
21
|
|
20
|
-
many_to_one :host_pool
|
21
22
|
one_to_many :ip_lease
|
23
|
+
many_to_one :vlan_lease
|
22
24
|
|
23
25
|
def validate
|
24
26
|
super
|
27
|
+
|
28
|
+
# validate ipv4 syntax
|
29
|
+
begin
|
30
|
+
IPAddress::IPv4.new("#{self.ipv4_gw}")
|
31
|
+
rescue => e
|
32
|
+
errors.add(:ipv4_gw, "Invalid IP address syntax: #{self.ipv4_gw}")
|
33
|
+
end
|
34
|
+
|
35
|
+
unless (1..31).include?(self.prefix.to_i)
|
36
|
+
errors.add(:prefix, "prefix must be 1-31: #{self.prefix}")
|
37
|
+
end
|
25
38
|
end
|
26
39
|
|
27
40
|
def to_hash
|
28
|
-
|
41
|
+
h = super
|
42
|
+
h.delete(:vlan_lease_id)
|
43
|
+
h.merge({
|
44
|
+
:description=>description.to_s,
|
45
|
+
:vlan_id => vlan_lease.tag_id,
|
46
|
+
})
|
47
|
+
end
|
48
|
+
|
49
|
+
def ipaddress
|
50
|
+
IPAddress::IPv4.new("#{self.ipv4_gw}/#{self.prefix}")
|
51
|
+
end
|
52
|
+
|
53
|
+
# check if the given IP addess is in the range of this network.
|
54
|
+
# @param [String] ipaddr IP address
|
55
|
+
def include?(ipaddr)
|
56
|
+
ipaddr = ipaddr.is_a?(IPAddress::IPv4) ? ipaddr : IPAddress::IPv4.new(ipaddr)
|
57
|
+
self.ipaddress.network.include?(ipaddr)
|
58
|
+
end
|
59
|
+
|
60
|
+
# register reserved IP address in this network
|
61
|
+
def add_reserved(ipaddr)
|
62
|
+
add_ip_lease(:ipv4=>ipaddr, :type=>IpLease::TYPE_RESERVED)
|
63
|
+
end
|
64
|
+
|
65
|
+
def available_ip_nums
|
66
|
+
self.ipaddress.hosts.size - self.ip_lease_dataset.count
|
29
67
|
end
|
30
|
-
|
31
68
|
end
|
32
69
|
end
|
@@ -29,6 +29,8 @@ module Dcmgr::Models
|
|
29
29
|
String :storage_type, :null=>false
|
30
30
|
String :ipaddr, :null=>false
|
31
31
|
String :snapshot_base_path, :null=>false
|
32
|
+
|
33
|
+
index :node_id
|
32
34
|
end
|
33
35
|
|
34
36
|
one_to_many :volumes
|
@@ -45,12 +47,6 @@ module Dcmgr::Models
|
|
45
47
|
end
|
46
48
|
end
|
47
49
|
|
48
|
-
def to_hash_document
|
49
|
-
h = self.values.dup
|
50
|
-
h[:id] = h[:uuid] = self.canonical_uuid
|
51
|
-
h
|
52
|
-
end
|
53
|
-
|
54
50
|
def state_machine
|
55
51
|
model = self
|
56
52
|
st = Statemachine.build do
|
data/lib/dcmgr/models/tag.rb
CHANGED
@@ -1,27 +1,59 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
|
3
3
|
module Dcmgr::Models
|
4
|
-
|
4
|
+
# Tag is a label which groups arbitrary resource(s) having canonical
|
5
|
+
# uuid. A tag object consists of three items: Account ID, Type, Name
|
6
|
+
#
|
7
|
+
# Account ID is top level scope that represents the owner of the
|
8
|
+
# tag. Each tag instance is created in the scope of the account.
|
9
|
+
#
|
10
|
+
# Type field is second level scope to filter the object out to be
|
11
|
+
# labeled. If the tag is only for grouping resource A, it will fail
|
12
|
+
# at labling the tag other than resource A.
|
13
|
+
#
|
14
|
+
# Name represents the instance ID of the tag. This is a string that
|
15
|
+
# must be unique in the scope of Account ID and Type.
|
16
|
+
# Below is Type & Name matrix in single account:
|
17
|
+
# TypeA, name1
|
18
|
+
# TypeA, name1 # can not create
|
19
|
+
# TypeB, name2 # ok
|
20
|
+
# TypeB, name1 # nop
|
21
|
+
#
|
22
|
+
# The resource can be labeled is called "Taggable" resource. The
|
23
|
+
# model framework is provided to declare simply.
|
24
|
+
#
|
25
|
+
# class A < Dcmgr::Models::Base
|
26
|
+
# taggable 'xxx'
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
# @example Retrieve tag
|
30
|
+
# t = Tag.declare(account_id, :NetworkPool, 'xxxxx')
|
31
|
+
# t.mapped_uuids # => ['nw-11111', 'nw-22222' ,'nw-33333']
|
32
|
+
#
|
33
|
+
# @example Lable a tag from tag
|
34
|
+
# t = Tag.declare(account_id, :NetworkPool, 'nwgroup1')
|
35
|
+
# t.lable('nw-xxxxx')
|
36
|
+
# t.lable('nw-yyyyy')
|
37
|
+
#
|
38
|
+
# @example Label a tag from resource
|
39
|
+
# t = Tag.declare(account_id, :NetworkPool, 'nwgroup1')
|
40
|
+
# nw = Network['nw-44444']
|
41
|
+
# nw.label_tag(t)
|
42
|
+
# nw.label_tag('tag-xxxxx')
|
43
|
+
class Tag < AccountResource
|
5
44
|
taggable('tag')
|
6
|
-
|
7
|
-
plugin :single_table_inheritance, :type_id, :model_map=>{}
|
8
|
-
plugin :subclasses
|
9
|
-
|
45
|
+
|
10
46
|
inheritable_schema do
|
11
|
-
Fixnum :account_id, :null=>false
|
12
|
-
index :account_id
|
13
|
-
Fixnum :owner_id
|
14
|
-
String :name, :fixed=>true, :size=>200, :null=>false
|
15
47
|
Fixnum :type_id, :null=>false
|
48
|
+
String :name, :null=>false
|
16
49
|
String :attributes
|
17
|
-
end
|
18
50
|
|
19
|
-
|
20
|
-
|
51
|
+
index [:account_id, :type_id, :name], {:unique=>true}
|
52
|
+
end
|
53
|
+
with_timestamps
|
21
54
|
|
22
55
|
many_to_one :account
|
23
56
|
|
24
|
-
#one_to_many :tag_mappings, :dataset=>proc{ TagMapping.dataset.filter(:tag_id=>self.id) } do
|
25
57
|
one_to_many :mapped_uuids, :class=>TagMapping do |ds|
|
26
58
|
ds.instance_eval {
|
27
59
|
def exists?(canonical_uuid)
|
@@ -31,12 +63,18 @@ module Dcmgr::Models
|
|
31
63
|
ds
|
32
64
|
end
|
33
65
|
|
66
|
+
# sti plugin has to be loaded at lower position.
|
67
|
+
plugin :subclasses
|
68
|
+
plugin :single_table_inheritance, :type_id,
|
69
|
+
:key_map=>proc {|v| Dcmgr::Tags::MODEL_MAP[v.to_s.split('Dcmgr::Tags::').last.to_sym] },
|
70
|
+
:model_map=>proc {|v| Dcmgr::Tags.const_get(Dcmgr::Tags::KEY_MAP[v]) }
|
71
|
+
|
34
72
|
class UnacceptableTagType < StandardError
|
35
73
|
def initialize(msg, tag, taggable)
|
36
74
|
super(msg)
|
37
75
|
|
38
|
-
raise ArgumentError, "Expected #{Tag
|
39
|
-
raise ArgumentError, "Expected #{Taggable
|
76
|
+
raise ArgumentError, "Expected child of #{Tag} but #{tag.class}" unless tag.is_a?(Tag)
|
77
|
+
raise ArgumentError, "Expected kind of #{Taggable} but #{taggable.class}" unless taggable.kind_of?(Taggable)
|
40
78
|
@tag = tag
|
41
79
|
@taggable = taggable
|
42
80
|
end
|
@@ -48,67 +86,59 @@ module Dcmgr::Models
|
|
48
86
|
def labeled?(canonical_uuid)
|
49
87
|
# TODO: check if the uuid exists
|
50
88
|
|
51
|
-
!TagMapping.filter(:
|
89
|
+
!TagMapping.filter(:tag_id=>self.pk, :uuid=>canonical_uuid).empty?
|
52
90
|
end
|
53
|
-
|
54
|
-
|
55
|
-
|
91
|
+
|
92
|
+
# Associate the tag to the taggable object.
|
93
|
+
#
|
94
|
+
# @params [Models::Taggable,String] taggable_or_uuid
|
95
|
+
def label(taggable_or_uuid)
|
96
|
+
tgt = case taggable_or_uuid
|
97
|
+
when String
|
98
|
+
Taggable.find(taggable_or_uuid)
|
99
|
+
when Models::Taggable
|
100
|
+
taggable_or_uuid
|
101
|
+
else
|
102
|
+
raise TypeError
|
103
|
+
end
|
56
104
|
|
57
|
-
raise(UnacceptableTagType, self, tgt)
|
58
|
-
raise(TagAlreadyLabeled) if labeled?(canonical_uuid)
|
59
|
-
TagMapping.create(:uuid=>canonical_uuid, :tag_id=>self.pk)
|
105
|
+
raise(UnacceptableTagType.new("", self, tgt)) unless accept_mapping?(tgt)
|
106
|
+
raise(TagAlreadyLabeled) if labeled?(tgt.canonical_uuid)
|
107
|
+
TagMapping.create(:uuid=>tgt.canonical_uuid, :tag_id=>self.pk)
|
60
108
|
self
|
61
109
|
end
|
62
110
|
|
63
|
-
def
|
64
|
-
|
65
|
-
|
111
|
+
def lable_ifnot(t)
|
112
|
+
begin
|
113
|
+
lable(t)
|
114
|
+
rescue TagAlreadyLabeled
|
115
|
+
end
|
66
116
|
self
|
67
117
|
end
|
68
|
-
|
69
|
-
#many_to_many :tags, :join_table=>:tag_mappings, :left_key=>:target_id, :conditions=>{:target_type=>TagMapping::TYPE_TAG}
|
70
|
-
|
71
|
-
#many_to_one :owner, :class=>:User
|
72
|
-
|
73
|
-
#one_to_many :tag_attributes, :one_to_one=>true
|
74
118
|
|
119
|
+
# Disassociate the tag from the taggable object.
|
120
|
+
#
|
121
|
+
# @params [Models::Taggable,String] taggable_or_uuid
|
122
|
+
def unlabel(taggable_or_uuid)
|
123
|
+
tgt = case taggable_or_uuid
|
124
|
+
when String
|
125
|
+
Taggable.find(taggable_or_uuid) || raise("Not found Taggable object: #{taggable_or_uuid}")
|
126
|
+
when Models::Taggable
|
127
|
+
taggable_or_uuid
|
128
|
+
else
|
129
|
+
raise TypeError
|
130
|
+
end
|
131
|
+
t = TagMapping.find(:tag_id=>self.pk, :uuid=>tgt.canonical_uuid) || raise(TagAlreadyUnlabeled)
|
132
|
+
t.destroy
|
133
|
+
self
|
134
|
+
end
|
135
|
+
|
75
136
|
def self.find_tag_class(name)
|
76
137
|
self.subclasses.find { |m|
|
77
|
-
m.
|
138
|
+
m == name || m.split('::').last == name
|
78
139
|
}
|
79
140
|
end
|
80
141
|
|
81
|
-
# STI class variable setter, getter methods.
|
82
|
-
class << self
|
83
|
-
|
84
|
-
# Declare the integer number for the tag.
|
85
|
-
#
|
86
|
-
# Also set the value to sti map in class Tag.
|
87
|
-
# class Tag1 < Tag
|
88
|
-
# type_id 123456
|
89
|
-
# end
|
90
|
-
#
|
91
|
-
# puts Tag1.type_id # == 123456
|
92
|
-
def type_id(type_id=nil)
|
93
|
-
if type_id.is_a?(Fixnum)
|
94
|
-
@type_id = type_id
|
95
|
-
Tag.sti_model_map[type_id] = self
|
96
|
-
Tag.sti_key_map[self.to_s] = type_id
|
97
|
-
end
|
98
|
-
@type_id || raise("#{self}.type_id is unset. Please set the unique number for the tag instance.")
|
99
|
-
end
|
100
|
-
|
101
|
-
|
102
|
-
# Set or read description of the Tag class.
|
103
|
-
def description(desc=nil)
|
104
|
-
if desc
|
105
|
-
@description = desc
|
106
|
-
end
|
107
|
-
@description
|
108
|
-
end
|
109
|
-
|
110
|
-
end
|
111
|
-
|
112
142
|
# Check the object class type before associating to the Tag.
|
113
143
|
# Child class must implement this method.
|
114
144
|
# @param taggable_obj any object kind_of?(Model::Taggable)
|
@@ -116,11 +146,19 @@ module Dcmgr::Models
|
|
116
146
|
raise NotImplementedError
|
117
147
|
end
|
118
148
|
|
119
|
-
|
149
|
+
# model hook
|
150
|
+
def before_destroy
|
151
|
+
return false if !mapped_uuids_dataset.empty?
|
152
|
+
super
|
153
|
+
end
|
154
|
+
|
155
|
+
def self.lock!
|
120
156
|
super
|
121
|
-
|
157
|
+
TagMapping.lock!
|
122
158
|
end
|
123
159
|
|
160
|
+
def to_api_document
|
161
|
+
to_hash.merge({:type_id=>self.class.to_s.split('::').last})
|
162
|
+
end
|
124
163
|
end
|
125
164
|
end
|
126
|
-
|