summaryrefslogtreecommitdiffstats
path: root/lib/puppet/file_serving/metadata.rb
blob: 87d3f138e796c841f90d7cc8902f966b84c489a3 (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
#
#  Created by Luke Kanies on 2007-10-16.
#  Copyright (c) 2007. All rights reserved.

require 'puppet'
require 'puppet/indirector'
require 'puppet/file_serving'
require 'puppet/file_serving/base'
require 'puppet/util/checksums'
require 'puppet/file_serving/indirection_hooks'

# A class that handles retrieving file metadata.
class Puppet::FileServing::Metadata < Puppet::FileServing::Base

    include Puppet::Util::Checksums

    extend Puppet::Indirector
    indirects :file_metadata, :extend => Puppet::FileServing::IndirectionHooks

    attr_reader :path, :owner, :group, :mode, :checksum_type, :checksum, :ftype, :destination

    PARAM_ORDER = [:mode, :ftype, :owner, :group]

    def attributes_with_tabs
        raise(ArgumentError, "Cannot manage files of type #{ftype}") unless ['file','directory','link'].include? ftype
        desc = []
        PARAM_ORDER.each { |check|
            check = :ftype if check == :type
            desc << send(check)
        }

        desc << checksum
        desc << @destination rescue nil if ftype == 'link'

        desc.join("\t")
    end

    def checksum_type=(type)
        raise(ArgumentError, "Unsupported checksum type #{type}") unless respond_to?("#{type}_file")

        @checksum_type = type
    end

    # Retrieve the attributes for this file, relative to a base directory.
    # Note that File.stat raises Errno::ENOENT if the file is absent and this
    # method does not catch that exception.
    def collect
        real_path = full_path()
        stat = stat()
        @owner = stat.uid
        @group = stat.gid
        @ftype = stat.ftype


        # We have to mask the mode, yay.
        @mode = stat.mode & 007777

        case stat.ftype
        when "file"
            @checksum = ("{#{@checksum_type}}") + send("#{@checksum_type}_file", real_path).to_s
        when "directory" # Always just timestamp the directory.
            @checksum_type = "ctime"
            @checksum = ("{#{@checksum_type}}") + send("#{@checksum_type}_file", path).to_s
        when "link"
            @destination = File.readlink(real_path)
            @checksum = ("{#{@checksum_type}}") + send("#{@checksum_type}_file", real_path).to_s rescue nil
        else
            raise ArgumentError, "Cannot manage files of type #{stat.ftype}"
        end
    end

    def initialize(path,data={})
        @owner       = data.delete('owner')
        @group       = data.delete('group')
        @mode        = data.delete('mode')
        if checksum = data.delete('checksum')
            @checksum_type = checksum['type']
            @checksum      = checksum['value']
        end
        @checksum_type ||= "md5"
        @ftype       = data.delete('type')
        @destination = data.delete('destination')
        super(path,data)
    end

    PSON.register_document_type('FileMetadata',self)
    def to_pson_data_hash
        {
            'document_type' => 'FileMetadata',

                'data'       => super['data'].update(
                    {
                    'owner'        => owner,
                    'group'        => group,
                    'mode'         => mode,
                    'checksum'     => {
                        'type'   => checksum_type,
                        'value'  => checksum
                },
                'type'         => ftype,
                'destination'  => destination,

                }),
            'metadata' => {
                'api_version' => 1
                }
        }
    end

    def to_pson(*args)
        to_pson_data_hash.to_pson(*args)
    end

    def self.from_pson(data)
        new(data.delete('path'), data)
    end

end