summaryrefslogtreecommitdiff
path: root/lib/chef/resource/chocolatey_source.rb
blob: 5c52ec5b649bdca62a1d2a777d5d19510c1c71f3 (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
#
# Copyright:: 2018-2020, Chef Software Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

class Chef
  class Resource
    class ChocolateySource < Chef::Resource
      unified_mode true
      provides :chocolatey_source

      description "Use the chocolatey_source resource to add, remove, enable, or disable Chocolatey sources."
      introduced "14.3"
      examples <<~DOC
        Add a Chocolatey source
        ```ruby
        chocolatey_source 'MySource' do
          source 'http://example.com/something'
          action :add
        end
        ```

        Remove a Chocolatey source
        ```ruby
        chocolatey_source 'MySource' do
          action :remove
        end
        ```
      DOC

      property :source_name, String, name_property: true,
               description: "An optional property to set the source name if it differs from the resource block's name."

      property :source, String,
        description: "The source URL."

      property :bypass_proxy, [TrueClass, FalseClass], default: false,
               description: "Whether or not to bypass the system's proxy settings to access the source."

      property :admin_only, [TrueClass, FalseClass], default: false,
               description: "Whether or not to set the source to be accessible to only admins.",
               introduced: "15.1"

      property :allow_self_service, [TrueClass, FalseClass], default: false,
               description: "Whether or not to set the source to be used for self service.",
               introduced: "15.1"

      property :priority, Integer, default: 0,
               description: "The priority level of the source."

      property :disabled, [TrueClass, FalseClass], default: false, desired_state: false, skip_docs: true

      load_current_value do
        element = fetch_source_element(source_name)
        current_value_does_not_exist! if element.nil?

        source_name element["id"]
        source element["value"]
        bypass_proxy element["bypassProxy"] == "true"
        admin_only element["adminOnly"] == "true"
        allow_self_service element["selfService"] == "true"
        priority element["priority"].to_i
        disabled element["disabled"] == "true"
      end

      # @param [String] id the source name
      # @return [REXML::Attributes] finds the source element with the
      def fetch_source_element(id)
        require "rexml/document" unless defined?(REXML::Document)

        config_file = "#{ENV["ALLUSERSPROFILE"]}\\chocolatey\\config\\chocolatey.config"
        raise "Could not find the Chocolatey config at #{config_file}!" unless ::File.exist?(config_file)

        config_contents = REXML::Document.new(::File.read(config_file))
        data = REXML::XPath.first(config_contents, "//sources/source[@id=\"#{id}\"]")
        data ? data.attributes : nil # REXML just returns nil if it can't find anything so avoid an undefined method error
      end

      action :add do
        description "Adds a Chocolatey source."

        raise "#{new_resource}: When adding a Chocolatey source you must pass the 'source' property!" unless new_resource.source

        converge_if_changed do
          shell_out!(choco_cmd("add"))
        end
      end

      action :remove do
        description "Removes a Chocolatey source."

        if current_resource
          converge_by("remove Chocolatey source '#{new_resource.source_name}'") do
            shell_out!(choco_cmd("remove"))
          end
        end
      end

      action :disable do
        description "Disables a Chocolatey source."

        if current_resource.disabled != true
          converge_by("disable Chocolatey source '#{new_resource.source_name}'") do
            shell_out!(choco_cmd("disable"))
          end
        end
      end

      action :enable do
        description "Enables a Chocolatey source."

        if current_resource.disabled == true
          converge_by("enable Chocolatey source '#{new_resource.source_name}'") do
            shell_out!(choco_cmd("enable"))
          end
        end
      end

      action_class do
        # @param [String] action the name of the action to perform
        # @return [String] the choco source command string
        def choco_cmd(action)
          cmd = "#{ENV["ALLUSERSPROFILE"]}\\chocolatey\\bin\\choco source #{action} -n \"#{new_resource.source_name}\""
          if action == "add"
            cmd << " -s #{new_resource.source} --priority=#{new_resource.priority}"
            cmd << " --bypassproxy" if new_resource.bypass_proxy
            cmd << " --allowselfservice" if new_resource.allow_self_service
            cmd << " --adminonly" if new_resource.admin_only
          end
          cmd
        end
      end
    end
  end
end