summaryrefslogtreecommitdiffstats
path: root/lib/puppet/node.rb
blob: 16a0e5c3d7b8126e28cf8f33faef50b2f0c07bb8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
require 'puppet/indirector'

# A class for managing nodes, including their facts and environment.
class Puppet::Node
  require 'puppet/node/facts'
  require 'puppet/node/inventory'
  require 'puppet/node/environment'

  # Set up indirection, so that nodes can be looked for in
  # the node sources.
  extend Puppet::Indirector

  # Adds the environment getter and setter, with some instance/string conversion
  include Puppet::Node::Environment::Helper

  # Use the node source as the indirection terminus.
  indirects :node, :terminus_setting => :node_terminus, :doc => "Where to find node information.
    A node is composed of its name, its facts, and its environment."

  attr_accessor :name, :classes, :source, :ipaddress, :parameters
  attr_reader :time
  #
  # Load json before trying to register.
  Puppet.features.pson? and ::PSON.register_document_type('Node',self)

  def self.from_pson(pson)
    raise ArgumentError, "No name provided in pson data" unless name = pson['name']

    node = new(name)
    node.classes = pson['classes']
    node.parameters = pson['parameters']
    node.environment = pson['environment']
    node
  end

  def to_pson(*args)
    result = {
      'document_type' => "Node",
      'data' => {}
    }
    result['data']['name'] = name
    result['data']['classes'] = classes unless classes.empty?
    result['data']['parameters'] = parameters unless parameters.empty?
    result['data']['environment'] = environment.name

    result.to_pson(*args)
  end

  def environment
    return super if @environment

    if env = parameters["environment"]
      self.environment = env
      return super
    end

    # Else, return the default
    Puppet::Node::Environment.new
  end

  def initialize(name, options = {})
    raise ArgumentError, "Node names cannot be nil" unless name
    @name = name

    if classes = options[:classes]
      if classes.is_a?(String)
        @classes = [classes]
      else
        @classes = classes
      end
    else
      @classes = []
    end

    @parameters = options[:parameters] || {}

    if env = options[:environment]
      self.environment = env
    end

    @time = Time.now
  end

  # Merge the node facts with parameters from the node source.
  def fact_merge
      if facts = Puppet::Node::Facts.indirection.find(name)
        merge(facts.values)
      end
  rescue => detail
      error = Puppet::Error.new("Could not retrieve facts for #{name}: #{detail}")
      error.set_backtrace(detail.backtrace)
      raise error
  end

  # Merge any random parameters into our parameter list.
  def merge(params)
    params.each do |name, value|
      @parameters[name] = value unless @parameters.include?(name)
    end

    @parameters["environment"] ||= self.environment.name.to_s if self.environment
  end

  # Calculate the list of names we might use for looking
  # up our node.  This is only used for AST nodes.
  def names
    return [name] if Puppet.settings[:strict_hostname_checking]

    names = []

    names += split_name(name) if name.include?(".")

    # First, get the fqdn
    unless fqdn = parameters["fqdn"]
      if parameters["hostname"] and parameters["domain"]
        fqdn = parameters["hostname"] + "." + parameters["domain"]
      else
        Puppet.warning "Host is missing hostname and/or domain: #{name}"
      end
    end

    # Now that we (might) have the fqdn, add each piece to the name
    # list to search, in order of longest to shortest.
    names += split_name(fqdn) if fqdn

    # And make sure the node name is first, since that's the most
    # likely usage.
    #   The name is usually the Certificate CN, but it can be
    # set to the 'facter' hostname instead.
    if Puppet[:node_name] == 'cert'
      names.unshift name
    else
      names.unshift parameters["hostname"]
    end
    names.uniq
  end

  def split_name(name)
    list = name.split(".")
    tmp = []
    list.each_with_index do |short, i|
      tmp << list[0..i].join(".")
    end
    tmp.reverse
  end
end