Skip to content

Commit

Permalink
Add versionlock
Browse files Browse the repository at this point in the history
Adding versionlock class. This is a port of the versionlock class from
the yum module. The purpose of this is to prevent zypper from updating
a specified package under a normal update run.
  • Loading branch information
msurato committed Mar 3, 2020
1 parent 58c0d29 commit 0a3f085
Show file tree
Hide file tree
Showing 8 changed files with 273 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .fixtures.yml
@@ -0,0 +1,4 @@
fixtures:
repositories:
stdlib: 'https://github.com/puppetlabs/puppetlabs-stdlib.git'
concat: 'https://github.com/puppetlabs/puppetlabs-concat.git'
17 changes: 17 additions & 0 deletions README.md
Expand Up @@ -26,5 +26,22 @@ zypprepo { 'openSUSE_12.1':
}
```

### Lock a package with the *versionlock* plugin

Locks explicitly specified packages from updates. Package name must be precisely specified in format *`NAME-VERSION-RELEASE.ARCH`*. Wild card in package name is allowed provided it does not span a field seperator.

```puppet
zypprepo::versionlock { 'bash-4.1.2-9.sles12.*':
ensure => present,
}
```

Use the following command to retrieve a properly-formated string:

```sh
PACKAGE_NAME='bash'
rpm -q "$PACKAGE_NAME" --qf '%{EPOCH}}:{0}|:%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n'
```

This Puppet 'type' is a port of the 'yumrepo' type from 2.7 code base
and is licensed under the Apache-2.0.
30 changes: 30 additions & 0 deletions manifests/plugin/versionlock.pp
@@ -0,0 +1,30 @@
# Class: zypprepo::plugin::versionlock
#
# @summary This class sets the structure for the lock file
#
# @param ensure
# specifies if versionlock should be present or absent. Defaults to present.
#
# @param path
# Absolute path to the Zypper locks file. Defaults /etc/zypp/locks.
#
# @example Sample usage:
# include zypprepo::plugin::versionlock
#
class zypprepo::plugin::versionlock (
Enum['present', 'absent'] $ensure = 'present',
String $path = '/etc/zypp/locks',
) {

concat { $path:
mode => '0644',
owner => 'root',
group => 'root',
}

concat::fragment { 'versionlock_header':
target => $path,
content => '# File managed by puppet\n',
order => '01',
}
}
36 changes: 36 additions & 0 deletions manifests/versionlock.pp
@@ -0,0 +1,36 @@
# @summary Locks package from updates.
#
# @example Sample usage
# zypprepo::versionlock { '0:bash-4.1.2-9.sles12.*':
# ensure => present,
# }
#
# @param ensure
# Specifies if versionlock should be `present` or `absent`.
#
# @note The resource title must use the format
# "%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}". This can be retrieved via
# the command `rpm -q --qf ':%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}'.
# Wildcards may be used within token slots, but must not cover seperators,
# e.g., 'b*sh-4.1.2-9.*' covers Bash version 4.1.2, revision 9 on all
# architectures.
#
define zypprepo::versionlock (
Enum['present', 'absent'] $ensure = 'present',
) {
require zypprepo::plugin::versionlock

assert_type(Zypprepo::VersionlockString, $name) |$_expected, $actual | {
fail("Package name must be formatted as %{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}, not \'${actual}\'. See Zypprepo::Versionlock documentation for details.")
}

if $ensure == 'present' {
concat::fragment { "zypprepo-versionlock-${name}":
content => "\ntype: package\n\
match_type: glob\n\
case_sensitive: on\n\
solvable_name: ${name}\n",
target => $zypprepo::plugin::versionlock::path,
}
}
}
8 changes: 8 additions & 0 deletions metadata.json
Expand Up @@ -10,6 +10,14 @@
"issues_url": "https://github.com/voxpupuli/puppet-zypprepo/issues",
"dependencies": [],
"requirements": [
{
"name": "puppetlabs/stdlib",
"version_requirement": ">= 4.18.0 < 7.0.0"
},
{
"name": "puppetlabs/concat",
"version_requirement": ">= 1.2.5 < 7.0.0"
},
{
"name": "puppet",
"version_requirement": ">= 5.5.8 < 7.0.0"
Expand Down
31 changes: 31 additions & 0 deletions spec/classes/plugin/versionlock_spec.rb
@@ -0,0 +1,31 @@
require 'spec_helper'

shared_examples 'a Zypprepo::plugin::versionlock class' do
it {
is_expected.to contain_concat('/etc/zypp/locks').with(
mode: '0644',
owner: 'root',
group: 'root'
)
}

it {
is_expected.to contain_concat__fragment('versionlock_header').with(
target: '/etc/zypp/locks',
content: '# File managed by puppet\n',
order: '01'
)
}
end

describe 'zypprepo::plugin::versionlock' do
on_supported_os.each do |os, os_facts|
context "on #{os}" do
let(:facts) { os_facts }

context 'without any parameters' do
it_behaves_like 'a Zypprepo::plugin::versionlock class'
end
end
end
end
107 changes: 107 additions & 0 deletions spec/defines/versionlock_spec.rb
@@ -0,0 +1,107 @@
require 'spec_helper'

shared_examples 'a well-defined versionlock' do
it { is_expected.to compile.with_all_deps }
it { is_expected.to contain_class('zypprepo::plugin::versionlock') }
end

describe 'zypprepo::versionlock' do
on_supported_os.each do |os, os_facts|
context "on #{os}" do
let(:facts) { os_facts }

context 'with a simple, well-formed title' do
let(:title) { 'bash-4.4-9.10.1.x86_64' }

context 'and no parameters' do
it_behaves_like 'a well-defined versionlock'
it 'contains a well-formed Concat::Fragment' do
is_expected.to contain_concat__fragment("zypprepo-versionlock-#{title}").with_content(
"\ntype: package\n" \
"match_type: glob\n" \
"case_sensitive: on\n" \
"solvable_name: #{title}\n"
)
end
end

context 'and ensure set to present' do
let(:params) { { ensure: 'present' } }

it_behaves_like 'a well-defined versionlock'
it 'contains a well-formed Concat::Fragment' do
is_expected.to contain_concat__fragment("zypprepo-versionlock-#{title}").with_content(
"\ntype: package\n" \
"match_type: glob\n" \
"case_sensitive: on\n" \
"solvable_name: #{title}\n"
)
end
end

context 'and ensure set to absent' do
let(:params) { { ensure: 'absent' } }

it_behaves_like 'a well-defined versionlock'
it 'contains a well-formed Concat::Fragment' do
is_expected.not_to contain_concat__fragment("zypprepo-versionlock-#{title}")
end
end
end

context 'with a trailing wildcard title' do
let(:title) { 'bash-4.4-9.10.1.*' }

it_behaves_like 'a well-defined versionlock'
it 'contains a well-formed Concat::Fragment' do
is_expected.to contain_concat__fragment("zypprepo-versionlock-#{title}").with_content(
"\ntype: package\n" \
"match_type: glob\n" \
"case_sensitive: on\n" \
"solvable_name: #{title}\n"
)
end
end

context 'with a complex wildcard title' do
let(:title) { 'bash-4.*-*.1' }

it_behaves_like 'a well-defined versionlock'
it 'contains a well-formed Concat::Fragment' do
is_expected.to contain_concat__fragment("zypprepo-versionlock-#{title}").with_content(
"\ntype: package\n" \
"match_type: glob\n" \
"case_sensitive: on\n" \
"solvable_name: #{title}\n"
)
end
end

context 'with a release containing dots' do
let(:title) { 'java-1.7.0-openjdk-1.7.0.121-2.6.8.0.3.x86_64' }

it_behaves_like 'a well-defined versionlock'
it 'contains a well-formed Concat::Fragment' do
is_expected.to contain_concat__fragment("zypprepo-versionlock-#{title}").with_content(
"\ntype: package\n" \
"match_type: glob\n" \
"case_sensitive: on\n" \
"solvable_name: #{title}\n"
)
end
end

context 'with an invalid title' do
let(:title) { 'bash-4.4.1' }

it { is_expected.to raise_error(Puppet::PreformattedError, %r(%\{NAME\}-%\{VERSION\}-%\{RELEASE\}\.%\{ARCH\})) }
end

context 'with an invalid wildcard pattern' do
let(:title) { 'bash-4.4.9*' }

it { is_expected.to raise_error(Puppet::PreformattedError, %r(%\{NAME\}-%\{VERSION\}-%\{RELEASE\}\.%\{ARCH\})) }
end
end
end
end
40 changes: 40 additions & 0 deletions types/versionlockstring.pp
@@ -0,0 +1,40 @@
# This type matches strings appropriate for use with zypprepo-versionlock.
# Its basic format, using the `rpm(8)` query string format, is
# `%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}`. As a Regex, it
# breaks down into five distinct parts, plus the seperators.
#
# # NAME: Any valid package name (see https://github.com/rpm-software-management/rpm/blob/master/doc/manual/spec)
# type Zypprepo::PackageName = Regexp[/[0-9a-zA-Z\._\+%\{\}\*-]+/]
#
# # VERSION: Any valid version string. The only limitation here, according to the RPM manual, is that it may not contain a dash (`-`).
# type Zypprepo::PackageVersion = Regexp[/[^-]+/]
#
# # RELEASE: Any valid release string. Only limitation is that it is not a dash (`-`)
# type Zypprepo::PackageRelease = Regexp[/[^-]+/]
#
# # ARCH: Matches a string such as `sles12.x86_64`. This is actuall two sub-expressions. See below.
# type Zypprepo::PackageArch = Regexp[/([0-9a-zZ-Z_\*]+)(?:\.(noarch|x86_64|i386|arm|ppc64|ppc64le|sparc64|ia64|alpha|ip|m68k|mips|mipsel|mk68k|mint|ppc|rs6000|s390|s390x|sh|sparc|xtensa|\*))?/]
#
# The `%{ARCH}` sub-expression is composed of two sub-expressions
# separated by a dot (`.`), where the second part is optional. The RPM
# specification calls the first field the `DistTag`, and the second the
# `BuildArch`.
#
# # DistTag: Any string consiting of only letters, numbers, or an underscore, e.g., `sles12` or `suse15`.
# type Zypprepo::PackageDistTag = Regexp[/[0-9a-zZ-Z_\*]+/]
#
# # BuildArch: Any string from the list at https://github.com/rpm-software-management/rpm/blob/master/rpmrc.in. Strings are roughly listed from most common to least common to improve performance.
# type Zypprepo::PackageBuildArch = Regexp[/noarch|x86_64|i386|arm|ppc64|ppc64le|sparc64|ia64|alpha|ip|m68k|mips|mipsel|mk68k|mint|ppc|rs6000|s390|s390x|sh|sparc|xtensa/]
#
# @note Each field may contain wildcard characters (`*`), but the
# wildcard characters may not span the fields, may not cover the
# seperators. This is an undocumented but tested limitation of
# yum-versionlock.
#
# @example A complete, well-formed string: `ash-4.1.2-9.sles12_2.x86_64'
# @example A well-formed string that has dropped the optional BuildArch sub-field: `bash-4.1.2-9.suse15`
# @example A well-formed string using wildcards: `*0:bash*-4.*-*.*`
# @example An invalid string (wildcard spans the VERSION and RELEASE fields): `0:bash-4.*-sles12.x86_64
# @example An invlaid string (wildcard spans the VERSION, RELEASE, and ARCH fields): `0:bash-*`
#
type Zypprepo::VersionlockString = Pattern[/^([0-9a-zA-Z\._\+%\{\}\*-]+)-([^-]+)-([^-]+)\.(([0-9a-zZ-Z_\*]+)(?:\.(noarch|x86_64|i386|arm|ppc64|ppc64le|sparc64|ia64|alpha|ip|m68k|mips|mipsel|mk68k|mint|ppc|rs6000|s390|s390x|sh|sparc|xtensa|\*))?)$/]

0 comments on commit 0a3f085

Please sign in to comment.