aboutsummaryrefslogtreecommitdiff
path: root/modules/base_installation
diff options
context:
space:
mode:
authorIsmaël Bouya <ismael.bouya@normalesup.org>2018-07-01 15:35:43 +0200
committerIsmaël Bouya <ismael.bouya@normalesup.org>2018-07-08 13:29:25 +0200
commitd8f933bd00a5cc416da00cd26c9d13f7a1c02486 (patch)
tree6f8773b69418463485d1196389a6c264f3cf3a6e /modules/base_installation
parent25c99a635507abfe6af4a1f0a9fc5a103d1880c0 (diff)
downloadPuppet-d8f933bd00a5cc416da00cd26c9d13f7a1c02486.tar.gz
Puppet-d8f933bd00a5cc416da00cd26c9d13f7a1c02486.tar.zst
Puppet-d8f933bd00a5cc416da00cd26c9d13f7a1c02486.zip
Add monitoring
Diffstat (limited to 'modules/base_installation')
-rw-r--r--modules/base_installation/lib/puppet/provider/package/pacman.rb283
-rw-r--r--modules/base_installation/lib/puppet/provider/package/pip2.rb17
-rw-r--r--modules/base_installation/manifests/package_managers.pp6
3 files changed, 306 insertions, 0 deletions
diff --git a/modules/base_installation/lib/puppet/provider/package/pacman.rb b/modules/base_installation/lib/puppet/provider/package/pacman.rb
new file mode 100644
index 0000000..0a5e5d0
--- /dev/null
+++ b/modules/base_installation/lib/puppet/provider/package/pacman.rb
@@ -0,0 +1,283 @@
1require 'puppet/provider/package'
2require 'set'
3require 'uri'
4
5Puppet::Type.type(:package).provide :pacman, :parent => Puppet::Provider::Package do
6 desc "Support for the Package Manager Utility (pacman) used in Archlinux.
7
8 This provider supports the `install_options` attribute, which allows command-line flags to be passed to pacman.
9 These options should be specified as a string (e.g. '--flag'), a hash (e.g. {'--flag' => 'value'}),
10 or an array where each element is either a string or a hash."
11
12 # If aura is installed, we can make use of it
13 def self.aura?
14 @aura ||= Puppet::FileSystem.exist?('/usr/bin/aura')
15 end
16
17 commands :pacman => "/usr/bin/pacman"
18 # Aura is a common AUR helper which, if installed, we can use to query the AUR
19 commands :aura => "/usr/bin/aura" if aura?
20
21 confine :operatingsystem => [:archlinux, :manjarolinux]
22 defaultfor :operatingsystem => [:archlinux, :manjarolinux]
23 has_feature :install_options
24 has_feature :uninstall_options
25 has_feature :upgradeable
26 has_feature :virtual_packages
27
28 # Checks if a given name is a group
29 def self.group?(name)
30 begin
31 !pacman("-Sg", name).empty?
32 rescue Puppet::ExecutionFailure
33 # pacman returns an expected non-zero exit code when the name is not a group
34 false
35 end
36 end
37
38 # Install a package using 'pacman', or 'aura' if available.
39 # Installs quietly, without confirmation or progress bar, updates package
40 # list from servers defined in pacman.conf.
41 def install
42 if @resource[:source]
43 install_from_file
44 else
45 install_from_repo
46 end
47
48 unless self.query
49 fail(_("Could not find package '%{name}'") % { name: @resource[:name] })
50 end
51 end
52
53 # Fetch the list of packages and package groups that are currently installed on the system.
54 # Only package groups that are fully installed are included. If a group adds packages over time, it will not
55 # be considered as fully installed any more, and we would install the new packages on the next run.
56 # If a group removes packages over time, nothing will happen. This is intended.
57 def self.instances
58 instances = []
59
60 # Get the installed packages
61 installed_packages = get_installed_packages
62 installed_packages.sort_by { |k, _| k }.each do |package, version|
63 instances << new(to_resource_hash(package, version))
64 end
65
66 # Get the installed groups
67 get_installed_groups(installed_packages).each do |group, version|
68 instances << new(to_resource_hash(group, version))
69 end
70
71 instances
72 end
73
74 # returns a hash package => version of installed packages
75 def self.get_installed_packages
76 begin
77 packages = {}
78 execpipe([command(:pacman), "-Q"]) do |pipe|
79 # pacman -Q output is 'packagename version-rel'
80 regex = %r{^(\S+)\s(\S+)}
81 pipe.each_line do |line|
82 if match = regex.match(line)
83 packages[match.captures[0]] = match.captures[1]
84 else
85 warning(_("Failed to match line '%{line}'") % { line: line })
86 end
87 end
88 end
89 packages
90 rescue Puppet::ExecutionFailure
91 fail(_("Error getting installed packages"))
92 end
93 end
94
95 # returns a hash of group => version of installed groups
96 def self.get_installed_groups(installed_packages, filter = nil)
97 groups = {}
98 begin
99 # Build a hash of group name => list of packages
100 command = [command(:pacman), "-Sgg"]
101 command << filter if filter
102 execpipe(command) do |pipe|
103 pipe.each_line do |line|
104 name, package = line.split
105 packages = (groups[name] ||= [])
106 packages << package
107 end
108 end
109
110 # Remove any group that doesn't have all its packages installed
111 groups.delete_if do |_, packages|
112 !packages.all? { |package| installed_packages[package] }
113 end
114
115 # Replace the list of packages with a version string consisting of packages that make up the group
116 groups.each do |name, packages|
117 groups[name] = packages.sort.map {|package| "#{package} #{installed_packages[package]}"}.join ', '
118 end
119 rescue Puppet::ExecutionFailure
120 # pacman returns an expected non-zero exit code when the filter name is not a group
121 raise unless filter
122 end
123 groups
124 end
125
126 # Because Archlinux is a rolling release based distro, installing a package
127 # should always result in the newest release.
128 def update
129 # Install in pacman can be used for update, too
130 self.install
131 end
132
133 # We rescue the main check from Pacman with a check on the AUR using aura, if installed
134 def latest
135 # Synchronize the database
136 pacman "-Sy"
137
138 resource_name = @resource[:name]
139
140 # If target is a group, construct the group version
141 return pacman("-Sp", "--print-format", "%n %v", resource_name).lines.map{ |line| line.chomp }.sort.join(', ') if self.class.group?(resource_name)
142
143 # Start by querying with pacman first
144 # If that fails, retry using aura against the AUR
145 pacman_check = true
146 begin
147 if pacman_check
148 output = pacman "-Sp", "--print-format", "%v", resource_name
149 return output.chomp
150 else
151 output = aura "-Ai", resource_name
152 output.split("\n").each do |line|
153 return line.split[2].chomp if line.split[0] =~ /Version/
154 end
155 end
156 rescue Puppet::ExecutionFailure
157 if pacman_check and self.class.aura?
158 pacman_check = false # now try the AUR
159 retry
160 else
161 raise
162 end
163 end
164 end
165
166 # Queries information for a package or package group
167 def query
168 installed_packages = self.class.get_installed_packages
169 resource_name = @resource[:name]
170
171 # Check for the resource being a group
172 version = self.class.get_installed_groups(installed_packages, resource_name)[resource_name]
173
174 if version
175 unless @resource.allow_virtual?
176 warning(_("%{resource_name} is a group, but allow_virtual is false.") % { resource_name: resource_name })
177 return nil
178 end
179 else
180 version = installed_packages[resource_name]
181 end
182
183 # Return nil if no package or group found
184 return nil unless version
185
186 self.class.to_resource_hash(resource_name, version)
187 end
188
189 def self.to_resource_hash(name, version)
190 {
191 :name => name,
192 :ensure => version,
193 :provider => self.name
194 }
195 end
196
197 # Removes a package from the system.
198 def uninstall
199 resource_name = @resource[:name]
200
201 is_group = self.class.group?(resource_name)
202
203 fail(_("Refusing to uninstall package group %{resource_name}, because allow_virtual is false.") % { resource_name: resource_name }) if is_group && !@resource.allow_virtual?
204
205 cmd = %w{--noconfirm --noprogressbar}
206 cmd += uninstall_options if @resource[:uninstall_options]
207 cmd << "-R"
208 cmd << '-s' if is_group
209 cmd << resource_name
210
211 if self.class.aura?
212 aura(*cmd)
213 else
214 pacman(*cmd)
215 end
216 end
217
218 private
219
220 def install_with_aura?
221 resource_name = @resource[:name]
222 if !self.class.aura?
223 return false
224 end
225
226 begin
227 pacman "-Sp", resource_name
228 return false
229 rescue Puppet::ExecutionFailure
230 return true
231 end
232 end
233
234 def install_options
235 join_options(@resource[:install_options])
236 end
237
238 def uninstall_options
239 join_options(@resource[:uninstall_options])
240 end
241
242 def install_from_file
243 source = @resource[:source]
244 begin
245 source_uri = URI.parse source
246 rescue => detail
247 self.fail Puppet::Error, _("Invalid source '%{source}': %{detail}") % { source: source, detail: detail }, detail
248 end
249
250 source = case source_uri.scheme
251 when nil then source
252 when /https?/i then source
253 when /ftp/i then source
254 when /file/i then source_uri.path
255 when /puppet/i
256 fail _("puppet:// URL is not supported by pacman")
257 else
258 fail _("Source %{source} is not supported by pacman") % { source: source }
259 end
260 pacman "--noconfirm", "--noprogressbar", "-Sy"
261 pacman "--noconfirm", "--noprogressbar", "-U", source
262 end
263
264 def install_from_repo
265 resource_name = @resource[:name]
266
267 # Refuse to install if not allowing virtual packages and the resource is a group
268 fail(_("Refusing to install package group %{resource_name}, because allow_virtual is false.") % { resource_name: resource_name }) if self.class.group?(resource_name) && !@resource.allow_virtual?
269
270 cmd = %w{--noconfirm --needed}
271 cmd += install_options if @resource[:install_options]
272
273 if install_with_aura?
274 cmd << "-Aq" << resource_name
275 aura(*cmd)
276 else
277 cmd << "--noprogressbar"
278 cmd << "-Sy" << resource_name
279 pacman(*cmd)
280 end
281 end
282
283end
diff --git a/modules/base_installation/lib/puppet/provider/package/pip2.rb b/modules/base_installation/lib/puppet/provider/package/pip2.rb
new file mode 100644
index 0000000..27cc0c4
--- /dev/null
+++ b/modules/base_installation/lib/puppet/provider/package/pip2.rb
@@ -0,0 +1,17 @@
1require 'puppet/provider/package/pip'
2
3Puppet::Type.type(:package).provide :pip2,
4 :parent => :pip do
5
6 desc "Python packages via `pip2`.
7
8 This provider supports the `install_options` attribute, which allows command-line flags to be passed to pip2.
9 These options should be specified as a string (e.g. '--flag'), a hash (e.g. {'--flag' => 'value'}),
10 or an array where each element is either a string or a hash."
11
12 has_feature :installable, :uninstallable, :upgradeable, :versionable, :install_options
13
14 def self.cmd
15 ["pip2"]
16 end
17end
diff --git a/modules/base_installation/manifests/package_managers.pp b/modules/base_installation/manifests/package_managers.pp
index c5c8485..a03085d 100644
--- a/modules/base_installation/manifests/package_managers.pp
+++ b/modules/base_installation/manifests/package_managers.pp
@@ -18,6 +18,12 @@ class base_installation::package_managers inherits base_installation {
18 include => '/etc/pacman.d/mirrorlist' 18 include => '/etc/pacman.d/mirrorlist'
19 } 19 }
20 20
21 pacman::repo { 'immae':
22 order => 0,
23 server => 'https://git.immae.eu/releases/packages/',
24 siglevel => 'Optional'
25 }
26
21 class { 'aur': } 27 class { 'aur': }
22 28
23 contain "pacman" 29 contain "pacman"