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.
@@ -3,18 +3,19 @@
3
3
  module Dcmgr::Models
4
4
  # Network interface for running instance.
5
5
  class InstanceNic < BaseNew
6
- taggable 'nic'
6
+ taggable 'vif'
7
7
 
8
8
  inheritable_schema do
9
9
  Fixnum :instance_id, :null=>false
10
- String :vif, :null=>false, :size=>50
10
+ Fixnum :network_id, :null=>false
11
11
  String :mac_addr, :null=>false, :size=>12
12
12
 
13
- index :mac_addr, {:unique=>true}
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
- 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
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
- true
39
+ self[:mac_addr] = newlease.mac_addr if newlease
40
+
41
+ super
39
42
  end
40
43
 
41
- def validate
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
- unless self.mac_addr.size == 12
45
- errors.add(:mac_addr, "Invalid mac address length: #{self.mac_addr}")
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.to_s})
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, :null=>false
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 self.lease(instance_nic)
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
- # 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}")
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 destroy_group
52
+ def before_destroy
53
53
  self.flush_rule
54
- self.destroy
54
+ super
55
55
  end
56
+ alias :destroy_group :destroy
56
57
 
57
58
  def rebuild_rule
58
59
  self.flush_rule
@@ -1,32 +1,69 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
+ require 'ipaddress'
4
+
3
5
  module Dcmgr::Models
4
- # Network definitions in the DC.
5
- class Network < BaseNew
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, :null=>false
12
- String :dns_server, :null=>false
13
- String :dhcp_server, :null=>false
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
- values.dup.merge({:description=>description.to_s})
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
@@ -1,27 +1,59 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
3
  module Dcmgr::Models
4
- class Tag < BaseNew
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
- with_timestamps
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
- TYPE_NORMAL = 0
20
- TYPE_AUTH = 1
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.class}: #{tag.class}" unless tag.is_a?(Tag)
39
- raise ArgumentError, "Expected #{Taggable.class}: #{tag.class}" unless taggable.is_a?(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(:uuid=>canonical_uuid, :tag_id=>self.pk).empty?
89
+ !TagMapping.filter(:tag_id=>self.pk, :uuid=>canonical_uuid).empty?
52
90
  end
53
-
54
- def label(canonical_uuid)
55
- tgt = Taggable.find(canonical_uuid)
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) if accept_mapping?(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 unlabel(canonical_uuid)
64
- t = TagMapping.find(:uuid=>canonical_uuid, :tag_id=>self.pk) || raise(TagAlreadyUnlabeled)
65
- t.delete
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.to_s.sub(/^#{self.class}::/, '') == name
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
- def after_initialize
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
- self[:type_id] = self.class.type_id
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
-