Project

General

Profile

environment.rb

Stefan Julin, 10/30/2014 03:52 AM

 
1
require 'puppet'
2
require 'puppet_proxy/initializer'
3
require 'puppet_proxy/config_reader'
4
require 'puppet_proxy/puppet_class'
5
require 'puppet_proxy/api_request'
6
require 'proxy/util'
7

    
8
class Proxy::Puppet::Environment
9
  extend Proxy::Log
10

    
11
  class << self
12
    include Proxy::Util
13

    
14
    # return a list of all puppet environments
15
    def all
16
      Proxy::Puppet::Initializer.load
17
      conf = Proxy::Puppet::ConfigReader.new(Proxy::Puppet::Initializer.config).get
18

    
19
      if use_environment_api?(conf)
20
        api_environments.map { |env, path| new(:name => env, :paths => path) }
21
      else
22
        config_environments(conf).map { |env, path| new(:name => env, :paths => path.split(":")) }
23
      end
24
    end
25

    
26
    def find name
27
      all.find { |e| e.name == name }
28
    end
29

    
30
    private
31

    
32
    def use_environment_api?(conf)
33
      force = to_bool(Proxy::Puppet::Plugin.settings.puppet_use_environment_api, nil)
34
      return force unless force.nil?
35
      !!([:main, :master].find { |s| (conf[s] && conf[s][:environmentpath] && !conf[s][:environmentpath].empty?) })
36
    end
37

    
38
    def api_environments
39
      response = Proxy::Puppet::EnvironmentsApi.new.find_environments
40
      raise Proxy::Puppet::DataError.new("No environments list in Puppet API response") unless response['environments']
41
      response['environments'].inject({}) do |envs, item|
42
        envs[item.first] = item.last['settings']['modulepath'] if item.last && item.last['settings'] && item.last['settings']['modulepath']
43
        envs
44
      end
45
    end
46

    
47
    def config_environments(conf)
48
      env = { }
49
      # query for the environments variable
50
      if conf[:main][:environments].nil?
51
        # 0.25 and newer doesn't require the environments variable anymore, scanning for modulepath
52
        conf.keys.each { |p| env[p] = conf[p][:modulepath] unless conf[p][:modulepath].nil? }
53
        # puppetmaster section "might" also returns the modulepath
54
        env.delete :main
55
        env.delete :puppetmasterd if env.size > 1
56
      else
57
        conf[:main][:environments].split(",").each { |e| env[e.to_sym] = conf[e.to_sym][:modulepath] unless conf[e.to_sym][:modulepath].nil? }
58
      end
59
      if env.values.compact.size == 0
60
        # fall back to defaults - we probably don't use environments
61
        env[:production] = conf[:main][:modulepath] || conf[:master][:modulepath] || '/etc/puppet/modules'
62
        logger.warn "No environments found - falling back to defaults (production - #{env[:production]})"
63
      end
64
      if env.size == 1 and env.keys.first == :master and !env.values.first.include?('$environment')
65
        # If we only have an entry in [master] it should really be called production
66
        logger.warn "Re-writing single 'master' environment as 'production'"
67
        env[:production] = env[:master]
68
        env.delete :master
69
      end
70

    
71
      new_env = env.clone
72
      # are we using dynamic puppet environments?
73
      env.each do|environment, modulepath|
74
        next unless modulepath
75

    
76
        # expand $confdir if defined and used in modulepath
77
        if modulepath.include?("$confdir")
78
          if conf[:main][:confdir]
79
            modulepath.gsub!("$confdir", conf[:main][:confdir])
80
          else
81
            # /etc/puppet is the default if $confdir is not defined
82
            modulepath.gsub!("$confdir", "/etc/puppet")
83
          end
84
        end
85

    
86
        # parting modulepath into static and dynamic paths
87
        staticpath = modulepath.split(":")
88
        dynamicpath = modulepath.split(":")
89

    
90
        modulepath.split(":").each do |base_dir|
91
          if base_dir.include?("$environment")
92
            # remove this entry from the static paths
93
            staticpath.delete base_dir
94
          else
95
            # remove this entry from the dynamic paths
96
            dynamicpath.delete base_dir
97
          end
98
        end
99

    
100
        # remove or add static environment
101
        if staticpath.empty?
102
          new_env.delete environment
103
        else
104
          new_env[environment] = staticpath.join(':')
105
        end
106

    
107
        # create dynamic environments and modulepaths (array of hash)
108
        unless dynamicpath.empty?
109
          temp_environment = []
110

    
111
          dynamicpath.each do |base_dir|
112
            # Dynamic environments - get every directory under the modulepath
113
            Dir.glob("#{base_dir.gsub(/\$environment(.*)/,"/")}/*").grep(/\/[A-Za-z0-9_]+$/) do |dir|
114
              e = dir.split("/").last
115
              temp_environment.push({e => base_dir.gsub("$environment", e)})
116
            end
117
          end
118

    
119
          # group array of hashes, join values (modulepaths) and create dynamic environment => modulepath
120
          dynamic_environment = temp_environment.group_by(&:keys).map{|k, v| {k.first => v.flatten.map(&:values).join(':')}}
121

    
122
          dynamic_environment.each do |h|
123
            h.each do |k,v|
124
              new_env[k.to_sym] = v
125
            end
126
          end
127
        end
128
      end
129

    
130
      new_env.reject { |k, v| k.nil? or v.nil? }
131
    end
132
  end
133

    
134
  attr_reader :name, :paths
135

    
136
  def initialize args
137
    @name = args[:name].to_s || raise("Must provide a name")
138
    @paths= args[:paths]     || raise("Must provide a path")
139
  end
140

    
141
  def to_s
142
    name
143
  end
144

    
145
  def classes
146
    conf = ::Proxy::Puppet::ConfigReader.new(::Proxy::Puppet::Initializer.config).get
147
    eparser = (conf[:main] && conf[:main][:parser] == 'future') || (conf[:master] && conf[:master][:parser] == 'future')
148

    
149
    paths.map {|path| ::Proxy::Puppet::PuppetClass.scan_directory path, name, eparser}.flatten
150
  end
151
end