summaryrefslogtreecommitdiffstats
path: root/lib/puppet/util.rb
blob: 650eb484a005d6e1d3ca3270b623aa8ced28900a (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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# A module to collect utility functions.

module Puppet
module Util
    # Execute a block as a given user or group
    def self.asuser(user = nil, group = nil)
        require 'etc'

        uid = nil
        gid = nil
        olduid = nil
        oldgid = nil

        begin
            # the groupid, if we got passed a group
            # The gid has to be changed first, because, well, otherwise we won't
            # be able to
            if group
                if group.is_a?(Integer)
                    gid = group
                else
                    unless obj = Puppet.type(:group)[group]
                        obj = Puppet.type(:group).create(
                            :name => group,
                            :check => [:gid]
                        )
                    end
                    obj.retrieve
                    gid = obj.is(:gid)
                    unless gid.is_a?(Integer)
                        raise Puppet::Error, "Could not find group %s" % group
                    end
                end

                if Process.gid != gid
                    oldgid = Process.gid
                    begin
                        Process.egid = gid
                    rescue => detail
                        raise Puppet::Error, "Could not change GID: %s" % detail
                    end
                end
            end

            if user
                # Retrieve the user id
                if user.is_a?(Integer)
                    uid = user
                else
                    unless obj = Puppet.type(:user)[user]
                        obj = Puppet.type(:user).create(
                            :name => user,
                            :check => [:uid, :gid]
                        )
                    end
                    obj.retrieve
                    uid = obj.is(:uid)
                    unless uid.is_a?(Integer)
                        raise Puppet::Error, "Could not find user %s" % user
                    end
                end

                # Now change the uid
                if Process.uid != uid
                    olduid = Process.uid
                    begin
                        Process.euid = uid
                    rescue => detail
                        raise Puppet::Error, "Could not change UID: %s" % detail
                    end
                end
            end

            retval = yield
        ensure
            if olduid
                Process.euid = olduid
            end

            if oldgid
                Process.egid = oldgid
            end
        end

        return retval
    end

    # Create a lock file while something is happening
    def self.lock(*opts)
        lock = opts[0] + ".lock"
        while File.exists?(lock)
            #Puppet.debug "%s is locked" % opts[0]
            sleep 0.1
        end
        File.open(lock, "w") { |f| f.print " "; f.flush }
        begin
            File.open(*opts) { |file| yield file }
        rescue
            raise
        ensure
            # I don't really understand how the lock file could disappear,
            # but just in case...
            if FileTest.exists?(lock)
                File.delete(lock)
            end
        end
    end

    # Create instance methods for each of the log levels.  This allows
    # the messages to be a little richer.  Most classes will be calling this
    # method.
    def self.logmethods(klass, useself = true)
        Puppet::Log.eachlevel { |level|
            klass.send(:define_method, level, proc { |args|
                if args.is_a?(Array)
                    args = args.join(" ")
                end
                if useself
                    Puppet::Log.create(
                        :level => level,
                        :source => self,
                        :message => args
                    )
                else
                    Puppet::Log.create(
                        :level => level,
                        :message => args
                    )
                end
            })
        }
    end

    # XXX this should all be done using puppet objects, not using
    # normal mkdir
    def self.recmkdir(dir,mode = 0755)
        if FileTest.exist?(dir)
            return false
        else
            tmp = dir.sub(/^\//,'')
            path = [File::SEPARATOR]
            tmp.split(File::SEPARATOR).each { |dir|
                path.push dir
                if ! FileTest.exist?(File.join(path))
                    Dir.mkdir(File.join(path), mode)
                elsif FileTest.directory?(File.join(path))
                    next
                else FileTest.exist?(File.join(path))
                    raise "Cannot create %s: basedir %s is a file" %
                        [dir, File.join(path)]
                end
            }
            return true
        end
    end

    def self.symbolize(value)
        case value
        when String: value = value.intern
        when Symbol: # nothing
        else
            raise ArgumentError, "'%s' must be a string or symbol" % value
        end
    end
end
end

# $Id$