File: windows_spec.rb

package info (click to toggle)
puppet 5.5.22-2
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 21,316 kB
  • sloc: ruby: 254,925; sh: 1,608; xml: 219; makefile: 153; sql: 103
file content (162 lines) | stat: -rw-r--r-- 8,038 bytes parent folder | download | duplicates (3)
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
require 'spec_helper'
require 'puppet_spec/compiler'
require 'puppet_spec/files'

# For some reason the provider test will not filter out on windows when using the
# :if => Puppet.features.microsoft_windows? method of filtering the tests.
if Puppet.features.microsoft_windows?
  require 'puppet/util/windows'
  describe Puppet::Type.type(:file).provider(:windows), '(integration)' do
    include PuppetSpec::Compiler
    include PuppetSpec::Files

    def create_temp_file(owner_sid, group_sid, initial_mode)
      tmp_file = tmpfile('filewindowsprovider')
      File.delete(tmp_file) if File.exist?(tmp_file)
      File.open(tmp_file, 'w') { |file| file.write("rspec test") }

      # There are other tests to ensure that these methods do indeed
      # set the owner and group.  Therefore it's ok to depend on them
      # here
      Puppet::Util::Windows::Security.set_owner(owner_sid, tmp_file) unless owner_sid.nil?
      Puppet::Util::Windows::Security.set_group(group_sid, tmp_file) unless group_sid.nil?
      # Pretend we are managing the owner and group to FORCE this mode, even if it's "bad"
      Puppet::Util::Windows::Security.set_mode(initial_mode.to_i(8), tmp_file, true, true, true) unless initial_mode.nil?

      tmp_file
    end

    def strip_sticky(value)
      # For the purposes of these tests we don't care about the extra-ace bit in modes
      # This function removes it
      value & ~Puppet::Util::Windows::Security::S_IEXTRA
    end

    sids = {
      :system => Puppet::Util::Windows::SID::LocalSystem,
      :administrators => Puppet::Util::Windows::SID::BuiltinAdministrators,
      :users => Puppet::Util::Windows::SID::BuiltinUsers,
      :power_users => Puppet::Util::Windows::SID::PowerUsers,
      :none => Puppet::Util::Windows::SID::Nobody,
      :everyone => Puppet::Util::Windows::SID::Everyone
    }

    # Testcase Hash options
    # create_* : These options are used when creating the initial test file
    # create_owner (Required!)
    # create_group (Required!)
    # create_mode
    #
    # manifest_* : These options are used to craft the manifest which is applied to the test file after createion
    # manifest_owner,
    # manifest_group,
    # manifest_mode (Required!)
    #
    # actual_* : These options are used to check the _actual_ values as opposed to the munged values from puppet
    # actual_mode (Uses manifest_mode for checks if not set)

    RSpec.shared_examples "a mungable file resource" do |testcase|

      before(:each) do
        @tmp_file = create_temp_file(sids[testcase[:create_owner]], sids[testcase[:create_group]], testcase[:create_mode])
        raise "Could not create temporary file" if @tmp_file.nil?
      end

      after(:each) do
        File.delete(@tmp_file) if File.exist?(@tmp_file)
      end

      context_name = "With initial owner '#{testcase[:create_owner]}' and initial group '#{testcase[:create_owner]}'"
      context_name += " and initial mode of '#{testcase[:create_mode]}'" unless testcase[:create_mode].nil?
      context_name += " and a mode of '#{testcase[:manifest_mode]}' in the manifest"
      context_name += " and an owner of '#{testcase[:manifest_owner]}' in the manifest" unless testcase[:manifest_owner].nil?
      context_name += " and a group of '#{testcase[:manifest_group]}' in the manifest" unless testcase[:manifest_group].nil?

      context context_name do
        is_idempotent = testcase[:is_idempotent].nil? || testcase[:is_idempotent]

        let(:manifest) do
          value = <<-MANIFEST
            file { 'rspec_example':
              ensure => present,
              path   => '#{@tmp_file}',
              mode   => '#{testcase[:manifest_mode]}',
          MANIFEST
          value += "  owner  => '#{testcase[:manifest_owner]}',\n" unless testcase[:manifest_owner].nil?
          value += "  group  => '#{testcase[:manifest_group]}',\n" unless testcase[:manifest_group].nil?
          value + "}"
        end

        it "should apply with no errors and have expected ACL" do
          apply_with_error_check(manifest)
          new_mode = strip_sticky(Puppet::Util::Windows::Security.get_mode(@tmp_file))
          expect(new_mode.to_s(8)).to eq (testcase[:actual_mode].nil? ? testcase[:manifest_mode] : testcase[:actual_mode])
        end

        it "should be idempotent", :if => is_idempotent do
          result = apply_with_error_check(manifest)
          result = apply_with_error_check(manifest)
          # Idempotent. Should be no changed resources
          expect(result.changed?.count).to eq 0
        end

        it "should NOT be idempotent", :unless => is_idempotent do
          result = apply_with_error_check(manifest)
          result = apply_with_error_check(manifest)
          result = apply_with_error_check(manifest)
          result = apply_with_error_check(manifest)
          # Not idempotent. Expect changed resources
          expect(result.changed?.count).to be > 0
        end
      end
    end

    # These scenarios round-trip permissions and are idempotent
    [
      { :create_owner => :system,         :create_group => :administrators, :manifest_mode => '760' },
      { :create_owner => :administrators, :create_group => :administrators, :manifest_mode => '660' },
      { :create_owner => :system,         :create_group => :system,         :manifest_mode => '770' },
    ].each do |testcase|
      # What happens if the owner and group are not managed
      it_behaves_like "a mungable file resource", testcase
      # What happens if the owner is managed
      it_behaves_like "a mungable file resource", testcase.merge({ :manifest_owner => testcase[:create_owner]})
      # What happens if the group is managed
      it_behaves_like "a mungable file resource", testcase.merge({ :manifest_group => testcase[:create_group]})
      # What happens if both the owner and group are managed
      it_behaves_like "a mungable file resource", testcase.merge({
        :manifest_owner => testcase[:create_owner],
        :manifest_group => testcase[:create_group]
      })
    end

    # SYSTEM is special in that when specifying less than mode 7, the owner and/or group MUST be managed
    # otherwise it's munged to 7 behind the scenes and is not idempotent
    both_system_testcase = { :create_owner => :system, :create_group => :system, :manifest_mode => '660', :actual_mode => '770', :is_idempotent => false }
    # What happens if the owner and group are not managed
    it_behaves_like "a mungable file resource", both_system_testcase.merge({ :is_idempotent => true })
    # What happens if the owner is managed
    it_behaves_like "a mungable file resource", both_system_testcase.merge({ :manifest_owner => both_system_testcase[:create_owner]})
    # What happens if the group is managed
    it_behaves_like "a mungable file resource", both_system_testcase.merge({ :manifest_group => both_system_testcase[:create_group]})

    # However when we manage SYSTEM explicitly, then the modes lower than 7 stick and the file provider
    # assumes it's insync (i.e. idempotent)
    it_behaves_like "a mungable file resource", both_system_testcase.merge({
      :manifest_owner => both_system_testcase[:create_owner],
      :manifest_group => both_system_testcase[:create_group],
      :actual_mode    => both_system_testcase[:manifest_mode],
      :is_idempotent  => true
    })

    # What happens if we _create_ a file that SYSTEM is a part of, and is Full Control, but the manifest says it should not be Full Control
    # Behind the scenes the mode should be changed to 7 and be idempotent
    [
      { :create_owner => :system,         :create_group => :system,         :manifest_mode => '660' },
      { :create_owner => :administrators, :create_group => :system,         :manifest_mode => '760' },
      { :create_owner => :system,         :create_group => :administrators, :manifest_mode => '670' },
    ].each do |testcase|
      it_behaves_like "a mungable file resource", testcase.merge({ :create_mode => '770', :actual_mode => '770'})
    end
  end
end