Skip to content

Commit

Permalink
Fixes #8952: Add generic methods using new package promises
Browse files Browse the repository at this point in the history
  • Loading branch information
amousset committed Sep 9, 2016
1 parent 6b3fe1e commit 855e3dd
Show file tree
Hide file tree
Showing 7 changed files with 1,385 additions and 0 deletions.
61 changes: 61 additions & 0 deletions tree/20_cfe_basics/package_lib.cf
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#####################################################################################
# Copyright 2016 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################

# @agent_version >=3.7
# Comes from CFEngine's stdlib
#
# This collection of bodies configure the package modules
# As it require the new package modules introduced in 3.7, we need to load it only on CFEngine 3.7.

bundle common package_module_knowledge
# @brief common package_module_knowledge bundle
#
# This common bundle defines which package modules are the defaults on different
# platforms.
{
vars:
debian::
"platform_default" string => "apt";

redhat::
"platform_default" string => "yum";

freebsd::
"platform_default" string => "pkg";
}

body package_module apt_get
{
query_installed_ifelapsed => "60";
query_updates_ifelapsed => "1440";
#default_options => {};
}

body package_module yum
{
query_installed_ifelapsed => "60";
query_updates_ifelapsed => "1440";
#default_options => {};
}

body package_module pkg
{
query_installed_ifelapsed => "60";
query_updates_ifelapsed => "1440";
#default_options => {};
}
197 changes: 197 additions & 0 deletions tree/30_generic_methods/_package_state.cf
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
#####################################################################################
# Copyright 2016 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################

# @name Package state
# @agent_version >=3.7
# @description Enforce the state of a package
# @documentation See package_present and package_absent for documentation.
# @parameter name Name of the package, or path to a local package if state is present
# @parameter version Version of the package, can be "latest" for latest version or "any" for any version (defaults to "any")
# @parameter architecture Architecture of the package, can be an architecture name or "default" (defaults to "default")
# @parameter provider Package provider to use, can be "yum", "apt", "pkg" or "default" for system default package manager (defaults to "default")
#
# @class_prefix package_${state}
# @class_parameter name

bundle agent package_state(name, version, architecture, provider, state)
{

vars:
"canonified_name" string => canonify("${name}");
"old_class_prefix" string => "package_${state}_${canonified_name}";
"promisers" slist => { @{this.callers_promisers}, cf_null }, policy => "ifdefined";
"class_prefix" string => canonify(join("_", "promisers"));
"args" slist => { "${name}", "${version}", "${architecture}", "${provider}", "${state}" };

# Build string vars used for reporting

# State
state_present::
"state_descritpion" string => "Presence";
!state_present::
"state_descritpion" string => "Absence";

# Architecture
architecture_specified::
"architecture_description" string => " for ${architecture} architecture ";
!architecture_specified::
"architecture_description" string => " ";

# Version
version_latest::
"version_description" string => "in latest available version";
!version_specified::
"version_description" string => "in any version";
version_specified.!version_latest::
"version_description" string => "in version ${version}";

defaults:
"version" string => "any", if_match_regex => "";
"architecture" string => "default", if_match_regex => "";
"provider" string => "default", if_match_regex => "";
# Select the default packager for this platform if "default"
"provider" string => "${package_module_knowledge.platform_default}", if_match_regex => "default";

classes:
"version_latest" expression => strcmp("latest", "${version}");
# As "latest" is understood by package promises,
# the only special case is "any", which maps to
# no specified version in the promise
"version_specified" not => strcmp("any", "${version}");

"state_present" expression => strcmp("present", "${state}");

# If architecture is not specified, do not add it to the promise.
# The package module will pick the default one for the local platform
"architecture_specified" not => strcmp("default", "${architecture}");

# Select the right package manager
# Always use the specified one, and select a default based on the OS
"use_apt_provider" expression => strcmp("apt", "${provider}");
"use_yum_provider" expression => strcmp("yum", "${provider}");
"use_pkg_provider" expression => strcmp("pkg", "${provider}");

any::
"supported_provider" expression => "use_apt_provider|use_yum_provider|use_pkg_provider";


packages:

# Unfortunately, we have to duplicate the 4 cases for each supported package module

#### apt ####

use_apt_provider.architecure_specified.version_specified::
"${name}"
policy => "${state}",
package_module => apt_get,
architecture => "${architecture}",
version => "${version}",
classes => classes_generic_two("${old_class_prefix}", "${class_prefix}");

use_apt_provider.architecure_specified.!version_specified::
"${name}"
policy => "${state}",
package_module => apt_get,
architecture => "${architecture}",
classes => classes_generic_two("${old_class_prefix}", "${class_prefix}");

use_apt_provider.!architecure_specified.version_specified::
"${name}"
policy => "${state}",
package_module => apt_get,
version => "${version}",
classes => classes_generic_two("${old_class_prefix}", "${class_prefix}");

use_apt_provider.!architecure_specified.!version_specified::
"${name}"
policy => "${state}",
package_module => apt_get,
classes => classes_generic_two("${old_class_prefix}", "${class_prefix}");

#### yum ####

use_yum_provider.architecure_specified.version_specified::
"${name}"
policy => "${state}",
package_module => yum,
architecture => "${architecture}",
version => "${version}",
classes => classes_generic_two("${old_class_prefix}", "${class_prefix}");

use_yum_provider.architecure_specified.!version_specified::
"${name}"
policy => "${state}",
package_module => yum,
architecture => "${architecture}",
classes => classes_generic_two("${old_class_prefix}", "${class_prefix}");

use_yum_provider.!architecure_specified.version_specified::
"${name}"
policy => "${state}",
package_module => yum,
version => "${version}",
classes => classes_generic_two("${old_class_prefix}", "${class_prefix}");

use_yum_provider.!architecure_specified.!version_specified::
"${name}"
policy => "${state}",
package_module => yum,
classes => classes_generic_two("${old_class_prefix}", "${class_prefix}");

#### pkg ####

use_pkg_provider.architecure_specified.version_specified::
"${name}"
policy => "${state}",
package_module => pkg,
architecture => "${architecture}",
version => "${version}",
classes => classes_generic_two("${old_class_prefix}", "${class_prefix}");

use_pkg_provider.architecure_specified.!version_specified::
"${name}"
policy => "${state}",
package_module => pkg,
architecture => "${architecture}",
classes => classes_generic_two("${old_class_prefix}", "${class_prefix}");

use_pkg_provider.!architecure_specified.version_specified::
"${name}"
policy => "${state}",
package_module => pkg,
version => "${version}",
classes => classes_generic_two("${old_class_prefix}", "${class_prefix}");

use_pkg_provider.!architecure_specified.!version_specified::
"${name}"
policy => "${state}",
package_module => pkg,
classes => classes_generic_two("${old_class_prefix}", "${class_prefix}");

methods:

supported_provider::
"reports" usebundle => _log("${state_descritpion} of package ${name}${architecture_description}${version_description}", "${old_class_prefix}", "${class_prefix}", @{args});

!supported_provider::
"force failure class" usebundle => _classes_failure("${class_prefix}");
"force failure class" usebundle => _classes_failure("${old_class_prefix}");
"report failure" usebundle => _log("Presence of package ${name} - package managers other than yum, apt and pkg are not currently supported", "${old_class_prefix}", "${class_prefix}", @{args});

}
46 changes: 46 additions & 0 deletions tree/30_generic_methods/package_absent.cf
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#####################################################################################
# Copyright 2016 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################

# @name Package absent
# @agent_version >=3.7
# @description Enforce the absence of a package
# @documentation *Example*:
# ```
# methods:
# "any" usebundle => package_absent("postgresql", "9.1", "x86_64", "");
# "any" usebundle => package_absent("postgresql", "any", "", "");
# "any" usebundle => package_absent("postgresql", "", "", "");
# ```
#
# @parameter name Name of the package
# @parameter version Version of the package or "any" for any version (defaults to "any")
# @parameter_constraint version "allow_empty_string" : true
# @parameter architecture Architecture of the package, can be an architecture name or "default" (defaults to "default")
# @parameter_constraint architecture "allow_empty_string" : true
# @parameter provider Package provider to use, can be "yum", "apt", "pkg" or "default" for system default package manager (defaults to "default")
# @parameter_constraint provider "allow_empty_string" : true
# @parameter_constraint provider "select" : [ "", "default", "yum", "apt", "pkg" ]
#
# @class_prefix package_absent
# @class_parameter name

bundle agent package_absent(name, version, architecture, provider)
{
methods:
"enforce absence" usebundle => package_state("${name}", "${version}", "${architecture}", "${provider}", "absent");
}
86 changes: 86 additions & 0 deletions tree/30_generic_methods/package_present.cf
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
#####################################################################################
# Copyright 2016 Normation SAS
#####################################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, Version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#####################################################################################

# @name Package present
# @agent_version >=3.7
# /!\ Please be careful to maintain this documentation in sync with package_absent
# @description Enforce the presence of a package
# @documentation This method manages packages using a package manager
#
# It uses a new package implementation, different from `package_install_*`.
# It is compatible thouth, and you can call generic methods from both implementations on the same host.
# The only drawback is that the agent will have to maintain double caches for package lists.
#
# #### Package options
#
# There is only one mandatory parameter, which is the package name to install.
# When it should be installed from a local package, you need to specify the full path to the package as name.
#
# The version parameter allows specifying a version you want installed.
# It should be the complete versions string as used by the used package manager.
# This parameter allows two special values:
#
# * *any* which is the default value, and is satisfied by any version of the given package
# * *latest* which will ensure, at each run, that the package is at the latest available version.
#
# #### Package providers
#
# This method supports several package managers. You can specify the package manager
# you want to use or let the method choose the default for the local system.
#
# The package providers include a caching systems for package information.
# The package lists (installed, available and available updates) are only updated
# when the cache expires, or when an operation is made by the agent on packages.
#
# ##### apt
#
# This package provider uses apt/dpkg to manage packages on the system.
#
# ##### rpm
#
# This package provider uses yum/rpm to manage packages on the system. It
# is able to downgrade packages when specifying an older version.
#
# ##### Name
#
# plop
#
# ```
# methods:
# "any" usebundle => package_present("postgresql", "9.1", "x86_64", "");
# "any" usebundle => package_present("postgresql", "latest", "", "");
# "any" usebundle => package_present("postgresql", "", "", "");
# ```
#
# @parameter name Name of the package, or path to a local package
# @parameter version Version of the package, can be "latest" for latest version or "any" for any version (defaults to "any")
# @parameter_constraint version "allow_empty_string" : true
# @parameter architecture Architecture of the package, can be an architecture name or "default" (defaults to "default")
# @parameter_constraint architecture "allow_empty_string" : true
# @parameter provider Package provider to use, can be "yum", "apt", "pkg" or "default" for system default package manager (defaults to "default")
# @parameter_constraint provider "allow_empty_string" : true
# @parameter_constraint provider "select" : [ "", "default", "yum", "apt", "pkg" ]
#
# @class_prefix package_present
# @class_parameter name

bundle agent package_present(name, version, architecture, provider)
{
methods:
"enforce presence" usebundle => package_state("${name}", "${version}", "${architecture}", "${provider}", "present");
}
Loading

0 comments on commit 855e3dd

Please sign in to comment.