Class: Dcmgr::Models::Instance

Inherits:
AccountResource show all
Defined in:
lib/dcmgr/models/instance.rb

Overview

Model class which represents Virtual Machine or Isolated Instace running on HostPool.

Defined Under Namespace

Modules: ValidationMethods

Constant Summary collapse

RECENT_TERMED_PERIOD =
(60 * 15)

Constants inherited from BaseNew

BaseNew::LOCK_TABLES_KEY

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from AccountResource

#account

Methods inherited from BaseNew

Proxy, dataset, default_row_lock_mode=, install_data, install_data_hooks, unlock!, #with_timestamps?

Class Method Details

.lock!Object



369
370
371
372
373
374
375
376
377
378
379
# File 'lib/dcmgr/models/instance.rb', line 369

def self.lock!
  super()
  Image.lock!
  InstanceSpec.lock!
  InstanceNic.lock!
  Volume.lock!
  VolumeSnapshot.lock!
  IpLease.lock!
  HostnameLease.lock!
  Network.lock!
end

Instance Method Details

#_deleteObject

override Sequel::Model#_delete not to delete rows but to set delete flags.



168
169
170
171
172
173
# File 'lib/dcmgr/models/instance.rb', line 168

def _delete
  self.terminated_at ||= Time.now
  self.state = :terminated if self.state != :terminated
  self.status = :offline if self.status != :offline
  self.save
end

#add_nic(network, vendor_id = nil) ⇒ Object



297
298
299
300
301
302
303
304
305
# File 'lib/dcmgr/models/instance.rb', line 297

def add_nic(network, vendor_id=nil)
  # TODO: get default vendor ID based on the hypervisor.
  vendor_id ||= '00:ff:f1'
  nic = InstanceNic.new(:mac_addr=>vendor_id)
  nic.network = network
  nic.nat_network = network.nat_network
  nic.instance = self
  nic.save
end

#archObject

Returns the architecture type of the image



289
290
291
# File 'lib/dcmgr/models/instance.rb', line 289

def arch
  self.image.arch
end

#before_destroyObject



154
155
156
157
158
159
160
161
162
163
164
# File 'lib/dcmgr/models/instance.rb', line 154

def before_destroy
  HostnameLease.filter(:account_id=>self., :hostname=>self.hostname).destroy
  self.instance_nic.each { |o| o.destroy }
  self.remove_all_netfilter_groups
  self.volume.each { |v|
    v.instance_id = nil
    v.state = :available
    v.save
  }
  super
end

#before_saveObject



126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# File 'lib/dcmgr/models/instance.rb', line 126

def before_save
  if @update_hostname
    if new?
      HostnameLease.create(:account_id=>self.,
                           :hostname=>self.hostname)
    else
      orig = self.dup.refresh
      # do nothing if orig.hostname == self.hostname
      if orig.hostname != self.hostname
        
        orig_name = HostnameLease.filter(:account_id=>self.,
                                         :hostname=>orig.hostname).first
        orig_name.hostname = self.hostname
        orig_name.save
      end
    end
    @update_hostname = false
  end

  # sum() returns nil if there is no instance rows.
  lives_weight = self.class.filter(:account_id=>self.).lives.sum(:quota_weight) || 0.0
  unless lives_weight <= self..quota.instance_total_weight
    raise "Out of quota limit: #{self.}'s current weight capacity: #{lives_weight} (<= #{self..quota.instance_total_weight})"
  end

  super
end

#before_validationObject



119
120
121
122
123
124
# File 'lib/dcmgr/models/instance.rb', line 119

def before_validation
  self[:user_data] ||= ''
  self[:hostname] ||= self.uuid
  self[:hostname] = self[:hostname].downcase
  super
end

#configObject



293
294
295
# File 'lib/dcmgr/models/instance.rb', line 293

def config
  self.instance_spec.config
end

#fqdn_hostnameObject

def netfilter_group_instances

  instances = self.netfilter_groups.map { |g| g.instances }

  instances.flatten!.uniq! if instances.size > 0
  instances
end


336
337
338
# File 'lib/dcmgr/models/instance.rb', line 336

def fqdn_hostname
  sprintf("%s.%s.%s", self.hostname, self..uuid, self.nic.first.network.domain_name)
end

#hypervisorObject

Returns the hypervisor type for the instance.



284
285
286
# File 'lib/dcmgr/models/instance.rb', line 284

def hypervisor
  self.host_pool.hypervisor
end

#ipsObject



325
326
327
# File 'lib/dcmgr/models/instance.rb', line 325

def ips
  self.instance_nic.map { |nic| nic.ip }
end

#join_netfilter_group(netfilter_group_uuids) ⇒ Object

Join this instance to the list of netfilter group using group’s uuid.

Parameters:

  • netfilter_group_uuids (String, Array)


309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
# File 'lib/dcmgr/models/instance.rb', line 309

def join_netfilter_group(netfilter_group_uuids)
  netfilter_group_uuids = [netfilter_group_uuids] if netfilter_group_uuids.is_a?(String)
  joined_group_uuids = self.netfilter_groups.map { |netfilter_group|
    netfilter_group.canonical_uuid
  }
  target_group_uuids = netfilter_group_uuids.uniq - joined_group_uuids.uniq
  target_group_uuids.uniq!

  target_group_uuids.map { |target_group_uuid|
    if ng = NetfilterGroup[target_group_uuid]
      InstanceNetfilterGroup.create(:instance_id => self.id,
                                    :netfilter_group_id => ng.id)
    end
  }
end

#join_nfgroup_by_name(account_id, nfgroup_names) ⇒ Object

Join this instance to the list of netfilter group using group name.

Parameters:

  • account_id (String)

    uuid of current account.

  • nfgroup_names (String, Array)


357
358
359
360
361
362
363
364
365
366
367
# File 'lib/dcmgr/models/instance.rb', line 357

def join_nfgroup_by_name(, nfgroup_names)
  nfgroup_names = [nfgroup_names] if nfgroup_names.is_a?(String)

  uuids = nfgroup_names.map { |n|
    ng = NetfilterGroup.for_update.filter(:account_id=>,
                                          :name=>n).first
    ng.nil? ? nil : ng.canonical_uuid
  }
  # clean up nils
  join_netfilter_group(uuids.compact.uniq)
end

#live?Boolean

Returns:

  • (Boolean)


381
382
383
# File 'lib/dcmgr/models/instance.rb', line 381

def live?
  self.terminated_at.nil?
end

#networksArray[Models::Network]

Retrieve all networks belong to this instance

Returns:



342
343
344
345
346
347
348
349
350
351
352
# File 'lib/dcmgr/models/instance.rb', line 342

def networks
  instance_nic.select { |nic|
    !nic.ip.nil?
  }.map { |nic|
    nic.ip.network
  }.group_by { |net|
    net.canonical_uuid
  }.values.map { |i|
    i.first
  }
end

#set_ssh_key_pair(ssh_key_pair) ⇒ Object

Raises:

  • (ArgumentError)


385
386
387
388
389
390
# File 'lib/dcmgr/models/instance.rb', line 385

def set_ssh_key_pair(ssh_key_pair)
  raise ArgumentError unless ssh_key_pair.is_a?(SshKeyPair)
  self.ssh_key_data = ssh_key_pair.to_hash
  # TODO: remove ssh_key_pair_id column
  self.ssh_key_pair_id = ssh_key_pair.canonical_uuid
end

#to_api_documentObject

returns hash data for API response on GET instances/

{ :id=>

:cpu_cores
:memory_size
:image_id
:network => [{:network_name=>'nw-xxxxxxx', :ipaddr=>'111.111.111.111'}]
:volume => [{'uuid'=>{:guest_device_name=>,}]
:ssh_key_pair => 'xxxxx',
:netfilter_group => ['rule1', 'rule2']
:created_at
:state
:status
:vif => {'vif-xxxxx'=>{:ipv4=>{:address=>'8.8.8.8', :nat_address=>'9.9.9.9.9'}}}

}



214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
# File 'lib/dcmgr/models/instance.rb', line 214

def to_api_document
  h = {
    :id => canonical_uuid,
    :cpu_cores   => cpu_cores,
    :memory_size => memory_size,
    :image_id    => image.canonical_uuid,
    :created_at  => self.created_at,
    :state => self.state,
    :status => self.status,
    :ssh_key_pair => nil,
    :network => [],
    :volume => [],
    :netfilter_group => [],
    :vif => [],
  }
  if self.ssh_key_data
    h[:ssh_key_pair] = self.ssh_key_data[:name]
  end

  if instance_nic
    instance_nic.each { |n|
      direct_lease_ds = n.direct_ip_lease_dataset
      next if direct_lease_ds.first.nil?
      outside_lease_ds = n.nat_ip_lease_dataset
      
      h[:network] << {
        :network_name => n.network.canonical_uuid,
        :ipaddr => direct_lease_ds.all.map {|lease| lease.ipv4 }.compact,
        :nat_ipaddr => outside_lease_ds.all.map {|lease| lease.ipv4 }.compact
      }
    }
  end

  if instance_nic
    instance_nic.each { |vif|
      ent = {
        :vif_id=>vif.canonical_uuid,
      }
      direct_lease = vif.direct_ip_lease.first
      if direct_lease.nil?
      else
        outside_lease = direct_lease.nat_outside_lease
        ent[:ipv4] = {
          :address=> direct_lease.ipv4,
          :nat_address => outside_lease.nil? ? nil : outside_lease.ipv4,
        }
      end
      h[:vif] << ent
    }
  end
  
  if self.volume
    self.volume.each { |v|
      h[:volume] << {
        :vol_id => v.canonical_uuid,
        :guest_device_name=>v.guest_device_name,
        :state=>v.state,
      }
    }
  end

  if self.netfilter_groups
    self.netfilter_groups.each { |n|
      h[:netfilter_group] << n.name
    }
  end
  h
end

#to_hashObject

dump column data as hash with details of associated models. this is for internal use.



177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
# File 'lib/dcmgr/models/instance.rb', line 177

def to_hash
  h = super
  h.merge!({:user_data => user_data.to_s, # Sequel::BLOB -> String
                :runtime_config => self.runtime_config, # yaml -> hash
                :image=>image.to_hash,
                :host_pool=>host_pool.to_hash,
                :instance_nics=>instance_nic.map {|n| n.to_hash },
                :ips => instance_nic.map { |n| n.ip.map {|i| unless i.is_natted? then i.ipv4 else nil end} if n.ip }.flatten.compact,
                :nat_ips => instance_nic.map { |n| n.ip.map {|i| if i.is_natted? then i.ipv4 else nil end} if n.ip }.flatten.compact,
          })
  h.merge!({:instance_spec=>instance_spec.to_hash}) unless instance_spec.nil?
  h[:volume]={}
  if self.volume
    self.volume.each { |v|
      h[:volume][v.canonical_uuid] = v.to_hash
    }
  end
  h
end

#validateObject



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/dcmgr/models/instance.rb', line 77

def validate
  super

  unless self.hostname =~ /\A[0-9a-z][0-9a-z\-]{0,31}\Z/
    errors.add(:hostname, "Invalid hostname syntax")
  end

  # uniqueness check for hostname
  if changed_columns.include?(:hostname)
    proc_test = lambda {
      unless ValidationMethods.hostname_uniqueness(self., self.hostname)
        errors.add(:hostname, "Duplicated hostname: #{self.hostname}")
      end
    }
    
    if new?
      proc_test.call
    else
      orig = self.dup.refresh
      # do nothing if orig.hostname == self.hostname
      if orig.hostname != self.hostname
        proc_test.call
      end
    end
    @update_hostname = true
  end
  
  # check runtime_config column
  case self.hypervisor
  when HostPool::HYPERVISOR_KVM
    r1 = self.runtime_config
    self.host_pool.instances.each { |i|
      next true if i.id == self.id
      r2 = i.runtime_config
      unless r1[:vnc_port] != r2[:vnc_port] && r1[:telnet_port] != r2[:telnet_port]
        errors.add(:runtime_config, "#{self.canonical_uuid}.runtime_config conflicted with #{i.canonical_uuid}")
        break
      end
    }
  end
end