Class: Host::Managed

Defined Under Namespace

Classes: Jail

Constant Summary

Constants included from ReportCommon

ReportCommon::BIT_NUM, ReportCommon::MAX, ReportCommon::METRIC

Instance Attribute Summary collapse

Attributes included from HostTemplateHelpers

#url_options

Class Method Summary collapse

Instance Method Summary collapse

Methods included from HostTemplateHelpers

#foreman_url, #install_path, #jumpstart_path, #media_path, #miniroot, #multiboot

Methods included from Orchestration::SSHProvision

#delSSHProvision, included, #validate_ssh_provisioning

Methods included from Orchestration::Puppetca

included

Methods included from Orchestration::TFTP

included

Methods included from Orchestration::Compute

included

Methods included from Orchestration::DNS

included

Methods included from Orchestration::DHCP

included

Methods included from Orchestration

included

Methods included from Foreman::Renderer

#foreman_url, #render_safe, #snippet, #snippets, #unattended_render, #unattended_render_to_temp_file

Methods included from HostCommon

included

Methods included from Hostext::Search

included

Methods included from ReportCommon

#changes?, #error?, included, #pending?, #status

Methods included from Authorization

#enforce_create_permissions, #enforce_destroy_permissions, #enforce_edit_permissions, included, #permission_failed?

Methods inherited from Base

attributes_protected_by_default, #facts_hash, #importFacts, #is_name_downcased?, #merge_facts, #set_non_empty_values, #to_param

Methods included from Foreman::STI

included, #save_with_type

Instance Attribute Details

#cached_host_paramsObject (readonly)

Returns the value of attribute cached_host_params


52
53
54
# File 'app/models/host/managed.rb', line 52

def cached_host_params
  @cached_host_params
end

Class Method Details

.count_distribution(assocication) ⇒ Object

counts each association of a given host e.g. how many hosts belongs to each os returns sorted hash


443
444
445
446
447
448
449
450
451
452
453
# File 'app/models/host/managed.rb', line 443

def self.count_distribution assocication
  output = []
  count(:group => assocication).each do |k,v|
    begin
      output << {:label => k.to_label, :data => v }  unless v == 0
    rescue
      logger.info "skipped #{k} as it has has no label"
    end
  end
  output
end

.count_habtm(association) ⇒ Object

counts each association of a given host for HABTM relationships TODO: Merge these two into one method e.g. how many hosts belongs to each os returns sorted hash


459
460
461
462
463
# File 'app/models/host/managed.rb', line 459

def self.count_habtm association
  counter = Host::Managed.joins(association.tableize.to_sym).group("#{association.tableize.to_sym}.id").count
  #Puppetclass.find(counter.keys.compact)...
  association.camelize.constantize.find(counter.keys.compact).map {|i| {:label=>i.to_label, :data =>counter[i.id]}}
end

.importHostAndFacts(yaml) ⇒ Object


343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
# File 'app/models/host/managed.rb', line 343

def self.importHostAndFacts yaml
  facts = YAML::load yaml
  case facts
    when Puppet::Node::Facts
      certname = facts.name
      name     = facts.values["fqdn"].downcase
      values   = facts.values
    when Hash
      certname = facts["clientcert"] || facts["certname"]
      name     = facts["fqdn"].downcase
      values   = facts
      return raise(::Foreman::Exception.new(N_("invalid facts hash"))) unless name and values
    else
      return raise(::Foreman::Exception.new(N_("Invalid Facts, much be a Puppet::Node::Facts or a Hash")))
  end

  if name == certname or certname.nil?
    h = Host.find_by_name name
  else
    h = Host.find_by_certname certname
    h ||= Host.find_by_name name
  end
  h ||= Host.new :name => name

  h.save(:validate => false) if h.new_record?
  h.importFacts(name, values)
end

.model_nameObject


168
169
170
# File 'app/models/host/managed.rb', line 168

def self.model_name
  ActiveModel::Name.new(Host)
end

Instance Method Details

#<=>(other) ⇒ Object


155
156
157
# File 'app/models/host/managed.rb', line 155

def <=>(other)
  self.name <=> other.name
end

#all_puppetclassesObject


264
265
266
# File 'app/models/host/managed.rb', line 264

def all_puppetclasses
  hostgroup.nil? ? puppetclasses : (hostgroup.classes + puppetclasses).uniq
end

#attributes_to_import_from_factsObject


371
372
373
374
375
# File 'app/models/host/managed.rb', line 371

def attributes_to_import_from_facts
  attrs = []
  attrs = [:mac, :ip] unless managed? and Setting[:ignore_puppet_facts_for_provisioning]
  super + [:domain, :architecture, :operatingsystem, :model, :certname] + attrs
end

#bmc_available?Boolean


681
682
683
684
685
# File 'app/models/host/managed.rb', line 681

def bmc_available?
  ipmi = bmc_nic
  return false if ipmi.nil?
  ipmi.password.present? && ipmi.username.present? && ipmi.provider == 'IPMI'
end

#bmc_nicObject


598
599
600
# File 'app/models/host/managed.rb', line 598

def bmc_nic
  interfaces.bmc.first
end

#bmc_proxyObject


677
678
679
# File 'app/models/host/managed.rb', line 677

def bmc_proxy
  @bmc_proxy ||= bmc_nic.proxy
end

#build_hooksObject


31
32
33
34
35
36
37
38
39
40
41
42
# File 'app/models/host/managed.rb', line 31

def build_hooks
  return unless respond_to?(:old) && old && (build? != old.build?)
  if build?
    run_callbacks :build do
      logger.debug { "custom hook after_build on #{name} will be executed if defined." }
    end
  else
    run_callbacks :provision do
      logger.debug { "custom hook before_provision on #{name} will be executed if defined." }
    end
  end
end

#built(installed = true) ⇒ Object

Called from the host build post install process to indicate that the base build has completed Build is cleared and the boot link and autosign entries are removed A site specific build script is called at this stage that can do site specific tasks


204
205
206
207
208
209
210
211
212
213
# File 'app/models/host/managed.rb', line 204

def built(installed = true)

  # delete all expired tokens
  self.build        = false
  self.installed_at = Time.now.utc if installed
  self.save
rescue => e
  logger.warn "Failed to set Build on #{self}: #{e}"
  false
end

#can_be_built?Boolean


471
472
473
# File 'app/models/host/managed.rb', line 471

def can_be_built?
  managed? and SETTINGS[:unattended] and capabilities.include?(:build) ? build == false : false
end

#capabilitiesObject


567
568
569
# File 'app/models/host/managed.rb', line 567

def capabilities
  compute_resource ? compute_resource.capabilities : [:build]
end

#certnameObject

if certname does not exist, use hostname instead


555
556
557
# File 'app/models/host/managed.rb', line 555

def certname
  read_attribute(:certname) || name
end

#classes_from_storeconfigsObject


465
466
467
468
469
# File 'app/models/host/managed.rb', line 465

def classes_from_storeconfigs
  klasses = resources.select(:title).where(:restype => "Class").where("title <> ? AND title <> ?", "main", "Settings").order(:title)
  klasses.map!(&:title).delete(:main)
  klasses
end

#clear_host_parameters_cache!Object


318
319
320
# File 'app/models/host/managed.rb', line 318

def clear_host_parameters_cache!
  @cached_host_params = nil
end

#clearFactsObject


186
187
188
# File 'app/models/host/managed.rb', line 186

def clearFacts
  FactValue.delete_all("host_id = #{id}")
end

#clearReportsObject


181
182
183
184
# File 'app/models/host/managed.rb', line 181

def clearReports
  # Remove any reports that may be held against this host
  Report.delete_all("host_id = #{id}")
end

#cloneObject


584
585
586
587
588
589
590
591
592
593
594
595
596
# File 'app/models/host/managed.rb', line 584

def clone
  new = super
  new.puppetclasses = puppetclasses
  # Clone any parameters as well
  host_parameters.each{|param| new.host_parameters << HostParameter.new(:name => param.name, :value => param.value, :nested => true)}
  interfaces.each {|int| new.interfaces << int.clone }
  # clear up the system specific attributes
  [:name, :mac, :ip, :uuid, :certname, :last_report].each do |attr|
    new.send "#{attr}=", nil
  end
  new.puppet_status = 0
  new
end

#configTemplate(opts = {}) ⇒ Object

returns a configuration template (such as kickstart) to a given host


236
237
238
239
240
241
242
243
# File 'app/models/host/managed.rb', line 236

def configTemplate opts = {}
  opts[:kind]               ||= "provision"
  opts[:operatingsystem_id] ||= operatingsystem_id
  opts[:hostgroup_id]       ||= hostgroup_id
  opts[:environment_id]     ||= environment_id

  ConfigTemplate.find_template opts
end

#disabled?Boolean


255
256
257
# File 'app/models/host/managed.rb', line 255

def disabled?
  not enabled?
end

#diskLayoutObject

returns the host correct disk layout, custom or common


230
231
232
233
# File 'app/models/host/managed.rb', line 230

def diskLayout
  @host = self
  pxe_render((disk.empty? ? ptable.layout : disk).gsub("\r",""))
end

#enforce_permissions(operation) ⇒ Object


475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
# File 'app/models/host/managed.rb', line 475

def enforce_permissions operation
  if operation == "edit" and new_record?
    return true # We get called again with the operation being set to create
  end
  current = User.current
  if (operation == "edit") or operation == "destroy"
    if current.allowed_to?("#{operation}_hosts".to_sym)
      return true if Host.my_hosts.include? self
    end
  else # create
    if current.allowed_to?(:create_hosts)
      # We are unconstrained
      return true if current.domains.empty? and current.hostgroups.empty?
      # We are constrained and the constraint is matched
      return true if (!current.domains.empty?    and current.domains.include?(domain)) or
      (!current.hostgroups.empty? and current.hostgroups.include?(hostgroup))
    end
  end
  errors.add(:base, _("You do not have permission to %s this host") % operation)
  false
end

#error_countObject

reports methods


247
248
249
# File 'app/models/host/managed.rb', line 247

def error_count
  %w[failed failed_restarts].sum {|f| status f}
end

#expire_tokensObject


196
197
198
199
# File 'app/models/host/managed.rb', line 196

def expire_tokens
  # this clean up other hosts as well, but reduce the need for another task to cleanup tokens.
  Token.delete_all(["expires < ? or host_id = ?", Time.now.utc.to_s(:db), id])
end

#handle_caObject

Cleans Certificate and enable Autosign Called after a host is given their provisioning template Returns : Boolean status of the operation


223
224
225
226
227
# File 'app/models/host/managed.rb', line 223

def handle_ca
  return true unless Setting[:manage_puppetca]
  return true unless puppetca?
  respond_to?(:initialize_puppetca,true) && initialize_puppetca && delCertificate && setAutosign
end

#host_inherited_params(include_source = false) ⇒ Object


322
323
324
325
326
327
328
329
330
331
332
333
# File 'app/models/host/managed.rb', line 322

def host_inherited_params include_source = false
  hp = {}
  # read common parameters
  CommonParameter.all.each {|p| hp.update Hash[p.name => include_source ? {:value => p.value, :source => :common} : p.value] }
  # read domain parameters
  domain.domain_parameters.each {|p| hp.update Hash[p.name => include_source ? {:value => p.value, :source => :domain} : p.value] } unless domain.nil?
  # read OS parameters
  operatingsystem.os_parameters.each {|p| hp.update Hash[p.name => include_source ? {:value => p.value, :source => :os} : p.value] } unless operatingsystem.nil?
  # read group parameters only if a host belongs to a group
  hp.update hostgroup.parameters(include_source) unless hostgroup.nil?
  hp
end

#host_paramsObject


335
336
337
338
339
340
341
# File 'app/models/host/managed.rb', line 335

def host_params
  return cached_host_params unless cached_host_params.blank?
  hp = host_inherited_params
  # and now read host parameters, override if required
  host_parameters.each {|p| hp.update Hash[p.name => p.value] }
  @cached_host_params = hp
end

#host_statusObject


622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
# File 'app/models/host/managed.rb', line 622

def host_status
  if build
    N_("Pending Installation")
  elsif respond_to?(:enabled) && !enabled
    N_("Alerts disabled")
  elsif respond_to?(:last_report) && last_report.nil?
    N_("No reports")
  elsif no_report
    N_("Out of sync")
  elsif error?
    N_("Error")
  elsif changes?
    N_("Active")
  elsif pending?
    N_("Pending")
  else
    N_("No changes")
  end
end

#import_missing_idsObject


672
673
674
675
# File 'app/models/host/managed.rb', line 672

def import_missing_ids
  tax_location.import_missing_ids     if location
  tax_organization.import_missing_ids if organization
end

#importNode(nodeinfo) ⇒ Object

this method accepts a puppets external node yaml output and generate a node in our setup it is assumed that you already have the node (e.g. imported by one of the rack tasks)


405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
# File 'app/models/host/managed.rb', line 405

def importNode nodeinfo
  myklasses= []
  # puppet classes
  nodeinfo["classes"].each do |klass|
    if (pc = Puppetclass.find_by_name(klass))
      myklasses << pc
    else
      error = _("Failed to import %{klass} for %{name}: doesn't exists in our database - ignoring") % { :klass => klass, :name => name }
      logger.warn error
      $stdout.puts error
    end
    self.puppetclasses = myklasses
  end

  # parameters are a bit more tricky, as some classifiers provide the facts as parameters as well
  # not sure what is puppet priority about it, but we ignore it if has a fact with the same name.
  # additionally, we don't import any non strings values, as puppet don't know what to do with those as well.

  myparams = self.info["parameters"]
  nodeinfo["parameters"].each_pair do |param,value|
    next if fact_names.exists? :name => param
    next unless value.is_a?(String)

    # we already have this parameter
    next if myparams.has_key?(param) and myparams[param] == value

    unless (hp = self.host_parameters.create(:name => param, :value => value))
      logger.warn "Failed to import #{param}/#{value} for #{name}: #{hp.errors.full_messages.join(", ")}"
      $stdout.puts $!
    end
  end

  self.save
end

#infoObject

provide information about each node, mainly used for puppet external nodes TODO: remove hard coded default parameters into some selectable values in the database.


270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
# File 'app/models/host/managed.rb', line 270

def info
  # Static parameters
  param = {}
  # maybe these should be moved to the common parameters, leaving them in for now
  param["puppetmaster"] = puppetmaster
  param["domainname"]   = domain.fullname unless domain.nil? or domain.fullname.nil?
  param["hostgroup"]    = hostgroup.to_label unless hostgroup.nil?
  if SETTINGS[:locations_enabled]
    param["location"] = location.name unless location.blank?
  end
  if SETTINGS[:organizations_enabled]
    param["organization"] = organization.name unless organization.blank?
  end
  if SETTINGS[:unattended]
    param["root_pw"]      = root_pass
    param["puppet_ca"]    = puppet_ca_server if puppetca?
  end
  param["comment"]      = comment unless comment.blank?
  param["foreman_env"]  = environment.to_s unless environment.nil? or environment.name.nil?
  if SETTINGS[:login] and owner
    param["owner_name"]  = owner.name
    param["owner_email"] = owner.is_a?(User) ? owner.mail : owner.users.map(&:mail)
  end

  if Setting[:ignore_puppet_facts_for_provisioning]
    param["ip"]  = ip
    param["mac"] = mac
  end
  param.update self.params

  classes = if Setting[:Parametrized_Classes_in_ENC] && Setting[:Enable_Smart_Variables_in_ENC]
              lookup_keys_class_params
            else
              self.puppetclasses_names
            end

  info_hash = {}
  info_hash['classes'] = classes
  info_hash['parameters'] = param
  info_hash['environment'] = param["foreman_env"] if Setting["enc_environment"]

  info_hash
end

#ipmi_boot(booting_device) ⇒ Object


699
700
701
# File 'app/models/host/managed.rb', line 699

def ipmi_boot(booting_device)
  bmc_proxy.boot({:function => 'bootdevice', :device => booting_device})
end

#is_owned_byObject

method to return the correct owner list for host edit owner select dropbox


164
165
166
# File 'app/models/host/managed.rb', line 164

def is_owned_by
  owner.id_and_type if owner
end

#is_owned_by=(selection) ⇒ Object

virtual attributes which sets the owner based on the user selection supports a simple user, or a usergroup selection parameter is expected to be an ActiveRecord id_and_type method (see Foreman's AR extentions).


175
176
177
178
179
# File 'app/models/host/managed.rb', line 175

def is_owned_by=(selection)
  oid = User.find(selection.to_i) if selection =~ (/-Users$/)
  oid = Usergroup.find(selection.to_i) if selection =~ (/-Usergroups$/)
  self.owner = oid
end

#jumpstart?Boolean


497
498
499
# File 'app/models/host/managed.rb', line 497

def jumpstart?
  operatingsystem.family == "Solaris" and architecture.name =~/Sparc/i rescue false
end

#matching?Boolean


664
665
666
# File 'app/models/host/managed.rb', line 664

def matching?
  missing_ids.empty?
end

#missing_idsObject


668
669
670
# File 'app/models/host/managed.rb', line 668

def missing_ids
  Array.wrap(tax_location.try(:missing_ids)) + Array.wrap(tax_organization.try(:missing_ids))
end

#no_reportObject


251
252
253
# File 'app/models/host/managed.rb', line 251

def no_report
  last_report.nil? or last_report < Time.now - (Setting[:puppet_interval] + 3).minutes and enabled?
end

#overwrite=(value) ⇒ Object

We have to coerce the value back to boolean. It is not done for us by the framework.


546
547
548
# File 'app/models/host/managed.rb', line 546

def overwrite=(value)
  @overwrite = value == "true"
end

#overwrite?Boolean


541
542
543
# File 'app/models/host/managed.rb', line 541

def overwrite?
  @overwrite ||= false
end

#paramsObject


314
315
316
# File 'app/models/host/managed.rb', line 314

def params
  host_params.update(lookup_keys_params)
end

#pm_fqdnObject

retuns fqdn of host puppetmaster


216
217
218
# File 'app/models/host/managed.rb', line 216

def pm_fqdn
  puppetmaster == "puppet" ? "puppet.#{domain.name}" : "#{puppetmaster}"
end

#populateFieldsFromFacts(facts = self.facts_hash) ⇒ Object


377
378
379
380
381
382
383
384
385
386
387
# File 'app/models/host/managed.rb', line 377

def populateFieldsFromFacts facts = self.facts_hash
  importer = super
  normalize_addresses
  if Setting[:update_environment_from_facts]
    set_non_empty_values importer, [:environment]
  else
    self.environment ||= importer.environment unless importer.environment.blank?
  end

  self.save(:validate => false)
end

#powerObject


687
688
689
690
691
692
693
694
695
696
# File 'app/models/host/managed.rb', line 687

def power
  opts = {:host => self}
  if compute_resource_id && uuid
    VirtPowerManager.new(opts)
  elsif bmc_available?
    BMCPowerManager.new(opts)
  else
    raise ::Foreman::Exception.new(N_("Unknown power management support - can't continue"))
  end
end

#progress_report_idObject


559
560
561
# File 'app/models/host/managed.rb', line 559

def progress_report_id
  @progress_report_id ||= Foreman.uuid
end

#progress_report_id=(value) ⇒ Object


563
564
565
# File 'app/models/host/managed.rb', line 563

def progress_report_id=(value)
  @progress_report_id = value
end

#providerObject


571
572
573
574
575
576
577
# File 'app/models/host/managed.rb', line 571

def provider
  if compute_resource_id
    compute_resource.provider_friendly_name
  else
    "BareMetal"
  end
end

#puppetclasses_namesObject

returns the list of puppetclasses a host is in.


260
261
262
# File 'app/models/host/managed.rb', line 260

def puppetclasses_names
  all_puppetclasses.collect {|c| c.name}
end

#puppetrun!Object


529
530
531
532
533
534
535
536
537
538
539
# File 'app/models/host/managed.rb', line 529

def puppetrun!
  unless puppet_proxy.present?
    errors.add(:base, _("no puppet proxy defined - cant continue"))
    logger.warn "unable to execute puppet run, no puppet proxies defined"
    return false
  end
  ProxyAPI::Puppet.new({:url => puppet_proxy.url}).run fqdn
rescue => e
  errors.add(:base, _("failed to execute puppetrun: %s") % e)
  false
end

#require_ip_validation?Boolean


550
551
552
# File 'app/models/host/managed.rb', line 550

def require_ip_validation?
  managed? and !compute? or (compute? and !compute_resource.provided_attributes.keys.include?(:ip))
end

#root_passObject

no need to store anything in the db if the password is our default


580
581
582
# File 'app/models/host/managed.rb', line 580

def root_pass
  read_attribute(:root_pass) || hostgroup.try(:root_pass) || Setting[:root_pass]
end

#rundeckObject

returns a rundeck output


515
516
517
518
519
520
521
522
523
524
525
526
527
# File 'app/models/host/managed.rb', line 515

def rundeck
  rdecktags = puppetclasses_names.map{|k| "class=#{k}"}
  unless self.params["rundeckfacts"].empty?
    rdecktags += self.params["rundeckfacts"].gsub(/\s+/, '').split(',').map { |rdf| "#{rdf}=" + (facts_hash[rdf] || "undefined") }
  end
  { name => { "description" => comment, "hostname" => name, "nodename" => name,
    "osArch" => arch.name, "osFamily" => os.family, "osName" => os.name,
    "osVersion" => os.release, "tags" => rdecktags, "username" => self.params["rundeckuser"] || "root" }
  }
rescue => e
  logger.warn "Failed to fetch rundeck info for #{to_s}: #{e}"
  {}
end

#set_hostgroup_defaultsObject


501
502
503
504
505
506
507
508
# File 'app/models/host/managed.rb', line 501

def set_hostgroup_defaults
  return unless hostgroup
  assign_hostgroup_attributes(%w{environment domain puppet_proxy puppet_ca_proxy})
  if SETTINGS[:unattended] and (new_record? or managed?)
    assign_hostgroup_attributes(%w{operatingsystem architecture})
    assign_hostgroup_attributes(%w{medium ptable subnet}) if capabilities.include?(:build)
  end
end

#set_ip_addressObject


510
511
512
# File 'app/models/host/managed.rb', line 510

def set_ip_address
  self.ip ||= subnet.unused_ip if subnet and SETTINGS[:unattended] and (new_record? or managed?)
end

#set_tokenObject


190
191
192
193
194
# File 'app/models/host/managed.rb', line 190

def set_token
  return unless Setting[:token_duration] != 0
  self.create_token(:value => Foreman.uuid,
                    :expires => Time.now.utc + Setting[:token_duration].minutes)
end

#setBuildObject

Called by build link in the list Build is set The boot link and autosign entry are created Any existing puppet certificates are deleted Any facts are discarded


394
395
396
397
398
399
400
401
# File 'app/models/host/managed.rb', line 394

def setBuild
  clearFacts
  clearReports

  self.build = true
  self.save
  errors.empty?
end

#shortnameObject


159
160
161
# File 'app/models/host/managed.rb', line 159

def shortname
  domain.nil? ? name : name.chomp("." + domain.name)
end

#smart_proxiesObject


642
643
644
# File 'app/models/host/managed.rb', line 642

def smart_proxies
  SmartProxy.where(:id => smart_proxy_ids)
end

#smart_proxy_idsObject


646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
# File 'app/models/host/managed.rb', line 646

def smart_proxy_ids
  ids = []
  [subnet, hostgroup.try(:subnet)].compact.each do |s|
    ids << s.dhcp_id
    ids << s.tftp_id
    ids << s.dns_id
  end

  [domain, hostgroup.try(:domain)].compact.each do |d|
    ids << d.dns_id
  end

  [puppet_proxy_id, puppet_ca_proxy_id, hostgroup.try(:puppet_proxy_id), hostgroup.try(:puppet_ca_proxy_id)].compact.each do |p|
    ids << p
  end
  ids.uniq.compact
end

#sp_ipObject


602
603
604
# File 'app/models/host/managed.rb', line 602

def sp_ip
  bmc_nic.try(:ip)
end

#sp_macObject


606
607
608
# File 'app/models/host/managed.rb', line 606

def sp_mac
  bmc_nic.try(:mac)
end

#sp_nameObject


618
619
620
# File 'app/models/host/managed.rb', line 618

def sp_name
  bmc_nic.try(:name)
end

#sp_subnetObject


614
615
616
# File 'app/models/host/managed.rb', line 614

def sp_subnet
  bmc_nic.try(:subnet)
end

#sp_subnet_idObject


610
611
612
# File 'app/models/host/managed.rb', line 610

def sp_subnet_id
  bmc_nic.try(:subnet_id)
end