Installing multiples packages with chef - package

When I try to install multiples packages with a wildcard naming I got the following error:
* yum_package[mysql-server] action install (up to date)
* yum_package[mysql*] action install
* No candidate version available for mysql*
============================================================================ ====
Error executing action `install` on resource 'yum_package[mysql*]'
============================================================================ ====
Recipe code is:
package 'mysql-server' do
action :install
end
package 'mysql*' do
action :install
end

You have to use the exact package name. The chef package resource does no magic to find matching packages.
The name of the resource (the part just after package) is used as the package name and given to the underlying system (yum on RH like systems, apt on debian like systems)
If you have multiples packages to install and a common configuration you can loop over them in your recipe instead:
['mysql-server','mysql-common','mysql-client'].each do |p|
package p do
action :install
end
end
The array creation could be simplified with some ruby syntax as the words builder %w:
%w(mysql-server mysql-common mysql-client).each [...]
Since chef 12.1 the package resource accept an array of packages directly like this:
package %w(mysql-server mysql-common mysql-client)

This can be resolved using chef cases. Please see below
add the following to your attributes file:
packages = []
case node[:platform_family]
when 'rhel' #based on your OS
packages = [
"package1",
"package2",
"package3",
"package4",
"package5",
"package6",
"package7" ## Last line without comma
]
end
default[:cookbookname][:packages] = packages
Then, add the following to your recipe file (recipes/default.rb):
node[:cookbookname][:packages].each do |pkg|
package pkg do
action :install
retries 3
retry_delay 5
end
end

Related

Trying to create custom installation package through chocolatey

I am new to scripting. I was trying to create a chocolatey package that would automatically do a custom(not typical) install. For example with MariaDB installations, I would like to specify which parts of the server to install and the username and password for the database.
I was trying to practice on Libreoffice where the package chooses Custom install and intalls only libre Writer. But the following script does the default installations what am I missing here? thanks.
chocolateinstall.ps1
e$ErrorActionPreference = 'Stop'; # stop on all errors
$toolsDir = "$(Split-Path -parent $MyInvocation.MyCommand.Definition)"
$fileLocation = ".\LibreOffice_7.2.7_Win_x64.msi"
$pp= Get-PackageParameters
if (!$pp['SetupType']){$pp['SetupType']='Custom'}
if (!$pp['InstallOption']){$pp['InstallOption']='LibreWriter'}
$packageArgs = #{
packageName = $env:ChocolateyPackageName
unzipLocation = $toolsDir
fileType = 'msi'
file = $fileLocation
softwareName = 'libre*'
checksum = '...'
checksumType = 'sha256'
silentArgs = "/qn /norestart /l*v `"$($env:TEMP)\$($packageName).$($env:chocolateyPackageVersion).MsiInstall.log`"" # ALLUSERS=1 DISABLEDESKTOPSHORTCUT=1 ADDDESKTOPICON=0 ADDSTARTMENU=0
validExitCodes= #(0, 3010, 1641)
}
Install-ChocolateyPackage #packageArgs
This is a pretty huge question, to one extent, and quite easy in another!
Short answer:
Your example above doesn't pass any of the package arguments you're crafting (e.g. $pp['InstallOption']) to the actual installer. They're being stored in the variable ($pp) and never used.
The values you want to use should be passed in to Install-ChocolateyPackage using the silentArgs parameter.
However, I don't think the arguments you have there are going to work, even if you pass them in (though I may be mistaken).
Longer answer:
MSIs don't just accept random arguments.
Accepted arguments vary hugely by installer, and by software, and there's no guarantee you can do what you want silently from the commandline.
You can use something like Orca to find out what arguments an MSI may support, or search for documentation (or other folk having done the work before), or create an MST file to apply.
You could also use the Chocolatey for Business Package Builder, which scans the file and tries to identify useful arguments you can pass - though this requires a paid Business license for Chocolatey.

Cannot install tmap

When I try to install tmap:
install.packages("tmap")
I have the following mistake:
also installing the dependencies ‘tmaptools’, ‘sf’
There are binary versions available but the source versions are later:
binary source needs_compilation
sf 0.9-0 0.9-2 TRUE
tmap 2.3-2 3.0 FALSE
Binaries will be installed
trying URL 'https://cran.rstudio.com/bin/windows/contrib/3.6/tmaptools_3.0.zip'
Content type 'application/zip' length 178880 bytes (174 KB)
downloaded 174 KB
trying URL 'https://cran.rstudio.com/bin/windows/contrib/3.6/sf_0.9-0.zip'
Content type 'application/zip' length 39675549 bytes (37.8 MB)
downloaded 37.8 MB
package ‘tmaptools’ successfully unpacked and MD5 sums checked
package ‘sf’ successfully unpacked and MD5 sums checked
The downloaded binary packages are in
C:\Users\Marine\AppData\Local\Temp\RtmpSQF9EP\downloaded_packages
installing the source package ‘tmap’
trying URL 'https://cran.rstudio.com/src/contrib/tmap_3.0.tar.gz'
Content type 'application/x-gzip' length 2936348 bytes (2.8 MB)
downloaded 2.8 MB
* installing *source* package 'tmap' ...
** package 'tmap' correctement décompressé et sommes MD5 vérifiées
** using staged installation
** R
** data
** inst
** byte-compile and prepare package for lazy loading
Error in loadNamespace(i, c(lib.loc, .libPaths()), versionCheck = vI[[i]]) :
namespace 'sf' 0.9-0 is being loaded, but = 0.9.1 is required
Calls: <Anonymous ... withCallingHandlers - loadNamespace - namespaceImport - loadNamespace
Exécution arrêtée
ERROR: lazy loading failed for package 'tmap'
* removing 'C:/Program Files/R/R-3.6.3/library/tmap'
Warning in install.packages :
installation of package ‘tmap’ had non-zero exit status
So I guess this is a problem with the sf version, but when I try to install sf independently, it is the version 0.9-0. that I install, and I cannot install 0.9.1 or more as required.
Any tip to overcome this issue?
Thanks!
PS: I use R version 3.6.3

XLConnect, rJava and package building

I am writing a function that i want to include in a user-defined package (MYPACKAGE). The function is a follows:
readSchedule <- function(FILE){
WB = loadWorkbook(FILE)
WS= readWorksheet(WB, sheet = 'Sheet1',header = TRUE)
return(WS)
}
where FILE is the name of the Excel file i want to read. When writing this function, I want it to import XLConnect, since that is the package it uses. I placed header code defining the function:
#param FILE Excel file
#return Excel data
#export
#import XLConnect
I have also added import(XLConnect) to the NAMESPACE and the DESCRIPTION file of MYPACKAGE. The package builds fine (or at least at first cut it appears to build OK) but when i run "Check Package" it fails and gives me the following error:
* installing *source* package 'MYPACKAGE' ...
** R
** preparing package for lazy loading
** help
*** installing help indices
** building package indices
** testing if installed package can be loaded
*** arch - i386
Error : .onLoad failed in loadNamespace() for 'rJava', details:
call: fun(libname, pkgname)
error: No CurrentVersion entry in Software/JavaSoft registry! Try re-installing Java and make sure R and Java have matching architectures.
Error: loading failed
Execution halted
*** arch - x64
ERROR: loading failed for 'i386'
I have the correct version of Java and can load rJava just fine. i've tried importing rJava (similar to XLConnect) but i get the same error. Below is my sessionInfo:
R version 3.1.2 (2014-10-31)
Platform: x86_64-w64-mingw32/x64 (64-bit)
locale:
[1] LC_COLLATE=English_United States.1252 LC_CTYPE=English_United States.1252 LC_MONETARY=English_United States.1252
[4] LC_NUMERIC=C LC_TIME=English_United States.1252
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] MYPACKAGE
loaded via a namespace (and not attached):
[1] chron_2.3-45 data.table_1.9.4 digest_0.6.8 lubridate_1.3.3 memoise_0.2.1 plyr_1.8.1
[7] Rcpp_0.11.1 reshape2_1.4 rJava_0.9-6 stringr_0.6.2 tools_3.1.2 XLConnect_0.2-7
It looks like you are building your package on a Windows 64-bit machine with a 64-bit version of Java installed. When checking your package using R CMD check, R by default also attempts to check your package on other sub-architectures (i386, 32-bit) which in your case would in addition require a 32-bit installation of Java.
If you want to check your package also for i386 you may just additionally install Java 32-bit. The other option is to pass the option --no-multiarch to your R CMD check call, e.g. R CMD check --no-multiarch MYPACKAGE.

rpm and Yum don't believe a package is installed after Chef installs

Running chef-solo (Installing Chef Omnibus (12.3)) on centos6.6
My recipe has the following simple code:
package 'cloud-init' do
action :install
end
log 'rpm-qi' do
message `rpm -qi cloud-init`
level :warn
end
log 'yum list' do
message `yum list cloud-init`
level :warn
end
But it outputs the following:
- install version 0.7.5-10.el6.centos.2 of package cloud-init
* log[rpm-qi] action write[2015-07-16T16:46:35+00:00] WARN: package cloud-init is not installed
[2015-07-16T16:46:35+00:00] WARN: Loaded plugins: fastestmirror, presto
Available Packages
cloud-init.x86_64 0.7.5-10.el6.centos.2 extras
I am at a loss as to why rpm/yum and actually rpmquery don't see the package as installed.
EDIT: To clarify I am specifically looking for the following string post package install to then apply a change to the file (I understand this is not a very chef way to do something I am happy to accept suggestions):
rpmquery -l cloud-init | grep 'distros/__init__.py$'
I have found that by using the following:
install_report = shell_out('yum install -y cloud-init').stdout
cloudinit_source = shell_out("rpmquery -l cloud-init | grep 'distros/__init__.py$'").stdout
I can then get the file I am looking for and perform
Chef::Util::FileEdit.new(cloudinit_source.chomp(''))
The file moves based on the distribution but I need to edit that file specifically with in place changes.
Untested code, just to give the idea:
package 'cloud-init' do
action :install
notifies :run,"ruby_block[update_cloud_init]"
end
ruby_block 'update_cloud_init' do
block do
cloudinit_source = shell_out("rpmquery -l cloud-init | grep 'distros/__init__.py$'").stdout
rc = Chef::Util::FileEdit.new(cloudinit_source.chomp(''))
rc.search_file_replace_line(/^what to find$/,
"replacement datas for the line")
rc.write_file
end
end
ruby_block example taken and adapted from here
I would better go using a template to manage the whole file, what I don't understand is why you don't know where it will be at first...
Previous answer
I assume it's a compile vs converge problem. at the time the message is stored (and so your command is executed) the package is not already installed.
Chef run in two phase, compile then converge.
At compile time it build a collection of resources and at converge time it execute code for the resource to get them in the described state.
When your log resource is compiled, the ugly back-ticks are evaluated, at this time there's a package resource in the collection but the resource has not been executed, so the output is correct.
I don't understand what you want to achieve with those log resources at all.
If you want to test your node state after chef-run use a handler maybe calling ServerSpec as in Test-Kitchen.

How to list packages and dependencies that will be installed in Macports?

Is there a way to just list all new packages and their dependencies that port will install for a given command?
For instance, consider installing the SciPy stack with the suggested:
sudo port install py27-numpy py27-scipy py27-matplotlib py27-ipython +notebook py27-pandas py27-sympy py27-nose
That installs a ton of packages and dependencies not listed in the above command.
Also, some of them I already have.
I'm already aware of the -y switch but that gives a verbose output of everything, including packages I had already installed.
I'm interested to have port tell me which new packages (be it dependencies or not) will be installed.
Is there a known way or do people just parse the -y output of the command, comparing each reported package against the existing installed packages?
Cheers
p.s. I'm fairly new to Macports and MacOSX (in Linux, apt-get always tells you which new packages will be installed)
You can use a port expression to print what will be installed:
port echo rdepof:$yourport and not installed
or for multiple ports
port echo \( rdepof:$yourport rdepof:$yourport2 ... \) and not installed
Due to the number of Portfiles involved in this and how the set operations are implemented, this will be rather slow. That being said, we're also working on improving this and providing feedback prior to installation like apt-get in a future MacPorts version.
neverpanic already gave a answer, but it seems unable to handle variants (like +notebook) and command-line options (like configure.compiler=macports-clang-3.7). I had a separate solution. The following Python script can display the new dependencies recursively:
#!/usr/bin/env python
#coding: utf-8
import re
import sys
import subprocess
# Gets command output as a list of lines
def popen_readlines(cmd):
p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
p.wait()
if p.returncode != 0:
raise subprocess.CalledProcessError(p.returncode, cmd)
else:
return map(lambda line: line.rstrip('\n'), p.stdout.readlines())
# Gets the port name from a line like " gcc6 #6.1.0_0 (active)"
def get_port_name(port_line):
return re.sub(r'^ (\S+).*', r'\1', port_line)
# Gets installed ports as a set
def get_installed():
installed_ports_lines = popen_readlines(['port', 'installed'])[1:]
installed_ports = set(map(get_port_name, installed_ports_lines))
return installed_ports
# Gets port names from items that may contain version specifications,
# variants, or options
def get_ports(ports_and_specs):
requested_ports = set()
for item in ports_and_specs:
if not (re.search(r'^[-+#]', item) or re.search(r'=', item)):
requested_ports.add(item)
return requested_ports
# Gets dependencies for the given port list (which may contain options
# etc.), as a list of tuples (combining with level), excluding items in
# ignored_ports
def get_deps(ports, ignored_ports, level):
if ports == []:
return []
deps_raw = popen_readlines(['port', 'deps'] + ports)
uninstalled_ports = []
for line in deps_raw:
if re.search(r'Dependencies:', line):
deps = re.sub(r'.*Dependencies:\s*', '', line).split(', ')
uninstalled_ports += [x for x in deps if x not in ignored_ports]
ignored_ports |= set(deps)
port_level_pairs = []
for port in uninstalled_ports:
port_level_pairs += [(port, level)]
port_level_pairs += get_deps([port], ignored_ports, level + 1)
return port_level_pairs
def main():
if sys.argv[1:]:
ports_and_specs = sys.argv[1:]
ignored_ports = get_installed() | get_ports(ports_and_specs)
uninstalled_ports = get_deps(ports_and_specs, ignored_ports, 0)
for (port, level) in uninstalled_ports:
print ' ' * (level * 2) + port
if __name__ == '__main__':
main()
It can be invoked like port_rdeps.py libomp configure.compiler=macports-clang-3.7. As a bonus, it can show the uninstalled dependencies as a tree.

Resources