summaryrefslogtreecommitdiffstats
path: root/lib/puppet/node/environment.rb
blob: 97dcc89e64db039a78c1d1ccf97bc8acfa521be0 (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
require 'puppet/util/cacher'

# Just define it, so this class has fewer load dependencies.
class Puppet::Node
end

# Model the environment that a node can operate in.  This class just
# provides a simple wrapper for the functionality around environments.
class Puppet::Node::Environment
    module Helper
        def environment
            Puppet::Node::Environment.new(@environment)
        end

        def environment=(env)
            if env.is_a?(String) or env.is_a?(Symbol)
                @environment = env
            else
                @environment = env.name
            end
        end
    end

    include Puppet::Util::Cacher

    @seen = {}

    # Return an existing environment instance, or create a new one.
    def self.new(name = nil)
        return name if name.is_a?(self)
        name ||= Puppet.settings.value(:environment)

        raise ArgumentError, "Environment name must be specified" unless name

        symbol = name.to_sym

        return @seen[symbol] if @seen[symbol]

        obj = self.allocate
        obj.send :initialize, symbol
        @seen[symbol] = obj
    end

    def self.current
        Thread.current[:environment] || root
    end

    def self.current=(env)
        Thread.current[:environment] = new(env)
    end

    def self.root
        @root
    end

    # This is only used for testing.
    def self.clear
        @seen.clear
    end

    attr_reader :name

    # Return an environment-specific setting.
    def [](param)
        Puppet.settings.value(param, self.name)
    end

    def initialize(name)
        @name = name
    end

    def known_resource_types
        if @known_resource_types.nil? or @known_resource_types.stale?
            @known_resource_types = Puppet::Resource::TypeCollection.new(self)
            @known_resource_types.perform_initial_import
        end
        @known_resource_types
    end

    def module(name)
        mod = Puppet::Module.new(name, self)
        return nil unless mod.exist?
        return mod
    end

    # Cache the modulepath, so that we aren't searching through
    # all known directories all the time.
    cached_attr(:modulepath, :ttl => Puppet[:filetimeout]) do
        dirs = self[:modulepath].split(File::PATH_SEPARATOR)
        dirs = ENV["PUPPETLIB"].split(File::PATH_SEPARATOR) + dirs if ENV["PUPPETLIB"]
        validate_dirs(dirs)
    end

    # Return all modules from this environment.
    # Cache the list, because it can be expensive to create.
    cached_attr(:modules, :ttl => Puppet[:filetimeout]) do
        module_names = modulepath.collect { |path| Dir.entries(path) }.flatten.uniq
        module_names.collect do |path|
            begin
                Puppet::Module.new(path, self)
            rescue Puppet::Module::Error => e
                nil
            end
        end.compact
    end

    # Cache the manifestdir, so that we aren't searching through
    # all known directories all the time.
    cached_attr(:manifestdir, :ttl => Puppet[:filetimeout]) do
        validate_dirs(self[:manifestdir].split(File::PATH_SEPARATOR))
    end

    def to_s
        name.to_s
    end

    def validate_dirs(dirs)
        dirs.collect do |dir|
            if dir !~ /^#{File::SEPARATOR}/
                File.join(Dir.getwd, dir)
            else
                dir
            end
        end.find_all do |p|
            p =~ /^#{File::SEPARATOR}/ && FileTest.directory?(p)
        end
    end

    @root = new(:'*root*')
end