#  This file is part of CFEngine 3 - written and maintained by Northern.tech AS.
#  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, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
# To the extent this program is licensed as part of the Enterprise
# versions of Cfengine, the applicable Commercial Open Source License
# (COSL) may apply to this file if you as a licensee so wish it. See
# included file COSL.txt.
#########################################################################
#
#   software_local.cf - Application Deployment From Directory Repository
#
#   NOTE: Windows needs to support WMI queries about installed msi files
#         in order for Cfengine to detect them. On Windows 2003,
#         go to Control Panel -> Add/Remove Programs ->
#         Windows Components -> Mgmnt and Monitoring Tools and check
#         WMI Windows Installer Provider.
#
#   NOTE: Naming conventions are important when updating packages.
#         By default, Cfengine expects "name-version-arch.msi"
#         on Windows, where name is lowercase, and arch is
#         i686 or x86_64. No spaces should be included in the filename.
#         The Caption and Version fields inside the msi package
#         are important. They must correspond to the file name as
#         follows: name = lowercase(spacetodash(Caption)),
#         version = Version. For any msi-file, use InstEd
#         (www.instedit.com) to check/modify the
#         Caption and Version fields
#         (Tables->Property->ProductName/ProductVersion).
#
#         For example, ProductName "CFEngine Nova" with ProductVersion
#         "1.1.2" for 32-bit Windows will correspond to the filename
#         "cfengine-nova-1.1.2-i686.msi".
#
#########################################################################
body common control
{
  inputs => { "$(sys.libdir)/stdlib.cf" };
  bundlesequence => { "check_software" };
}

bundle agent check_software
{
  vars:
    # software to install if not installed
    "include_software" slist => { "7-zip-4.50-$(sys.arch).msi" };

    # this software gets updated if it is installed
    "autoupdate_software" slist => { "7-zip" };

    # software to uninstall if it is installed
    "exclude_software" slist => { "7-zip-4.65-$(sys.arch).msi" };

  methods:

  # TODO: Fix the following bundles, msi_implicit is giving errors:
  #  "any" usebundle => add_software( "@(check_software.include_software)", "$(sys.policy_hub)" );
  #  "any" usebundle => update_software( "@(check_software.autoupdate_software)", "$(sys.policy_hub)" );
  #  "any" usebundle => remove_software( "@(check_software.exclude_software)", "$(sys.policy_hub)" );
}

#########################################################################
bundle agent add_software(pkg_name, srv)
{
  vars:
    # dir to install from locally - can also check multiple directories
    "local_software_dir" string => "C:\Program Files\Cfengine\software\add";

  files:
    "$(local_software_dir)"
      copy_from => remote_cp(
        "/var/cfengine/master_software_updates/$(sys.flavour)_$(sys.arch)/add",
        "$(srv)"
      ),
      depth_search => recurse("1"),
      classes => if_repaired("got_newpkg"),
      comment => "Copy software from remote repository";

  packages:
    # When to check if the package is installed ?
    got_newpkg|any::
      "$(pkg_name)"
        package_policy => "add",
        package_method => msi_implicit("$(local_software_dir)"),
        classes => if_else("add_success", "add_fail"),
        comment => "Install new software, if not already present";

  reports:
    add_fail::
      "Failed to install one or more packages";
}

#########################################################################
bundle agent update_software(sw_names, srv)
{
  vars:
    # dir to install from locally - can also check multiple directories
    "local_software_dir" string => "C:\Program Files\Cfengine\software\update";

  files:
    "$(local_software_dir)"
      copy_from => remote_cp(
        "/var/cfengine/master_software_updates/$(sys.flavour)_$(sys.arch)/update",
        "$(srv)"
      ),
      depth_search => recurse("1"),
      classes => if_repaired("got_newpkg"),
      comment => "Copy software updates from remote repository";

  packages:
    # When to check if the package is updated ?
    got_newpkg|any::
      "$(sw_names)"
        package_policy => "update",
        package_select => ">=", # picks the newest update available
        package_architectures => { "$(sys.arch)" }, # install 32 or 64 bit package ?
        package_version => "1.0", # at least version 1.0
        package_method => msi_explicit("$(local_software_dir)"),
        classes => if_else("update_success", "update_fail");

  reports:
    update_fail::
      "Failed to update one or more packages";
}

#########################################################################
bundle agent remove_software(pkg_name, srv)
{
  vars:
    # dir to install from locally - can also check multiple directories
    "local_software_dir" string => "C:\Program Files\Cfengine\software\remove";

  files:
    "$(local_software_dir)"
      copy_from => remote_cp(
        "/var/cfengine/master_software_updates/$(sys.flavour)_$(sys.arch)/remove",
        "$(srv)"
      ),
      depth_search => recurse("1"),
      classes => if_repaired("got_newpkg"),
      comment => "Copy removable software from remote repository";

  packages:
    got_newpkg::
      "$(pkg_name)"
        package_policy => "delete",
        package_method => msi_implicit("$(local_software_dir)"),
        classes => if_else("remove_success", "remove_fail"),
        comment => "Remove software, if present";

  reports:
    remove_fail::
      "Failed to remove one or more packages";
}
