Rex::C...s::Pkg(3pm)

πŸŽ€ NAME πŸŽ€

Bestie, meet Rex::C...s::Pkg (that's the 3pm-flavored Perl doc for it, living in User Contributed Perl Documentation) β€” the Rex module that goes Install/Remove Software packages for you. Lowkey the whole point of your deploy scripts, no cap. πŸ’–


🌸 DESCRIPTION 🌸

With this module you can install packages and files. That's the whole vibe. Package goes in, package goes out, files get dropped places. Iconic behavior, honestly. ✨


πŸ¦‹ SYNOPSIS πŸ¦‹

Okay so here's the vibe check, three flavors of pkg:

pkg "somepkg",
  ensure => "present";
pkg "somepkg",
  ensure => "latest",
  on_change => sub {
    say "package was updated.";
    service someservice => "restart";
  };
pkg "somepkg",
  ensure => "absent";

present, latest-with-a-glow-up-and-a-restart, gone. Chef's kiss. πŸ’…


πŸ‘‘ EXPORTED FUNCTIONS πŸ‘‘

πŸ“ pkg($package [, %options])

Since: 0.45

Use this resource to install or update a package. And the way that it generates reports, bestie β€” yes, it does that too. 🫢

pkg "httpd",
  ensure    => "latest",    # ensure that the newest version is installed (auto-update)
  on_change => sub { say "package was installed/updated"; };

pkg "httpd",
  ensure => "absent";    # remove the package

pkg "httpd",
  ensure => "present";   # ensure that some version is installed (no auto-update)

pkg "httpd",
  ensure => "2.4.6";    # ensure that version 2.4.6 is installed

pkg "apache-server",    # with a custom resource name
  package => "httpd",
  ensure  => "present";

Look at those comments, they're literally the whole personality of ensure. "latest" = auto-update energy, "present" = just be here, "2.4.6" = pin it and don't you dare move, "absent" = bye. 🌈


πŸ’œ install($type, $data, $options)

The install function can install packages (for CentOS, OpenSuSE and Debian) and files.

Heads up: if you want reports, please use the pkg() resource instead. Don't come for install for the report gossip. 😭

Installing a package

(This is only supported on CentOS, OpenSuSE and Debian systems. Fr fr, just those three.)

task "prepare", "server01", sub {
  install package => "perl";

  # or if you have to install more packages.
  install package => [
                 "perl",
                 "ntp",
                 "dbus",
                 "hal",
                 "sudo",
                 "vim",
               ];
};

Installing a file

⚠️ This is deprecated since 0.9. Please use File file instead. Deprecated is deprecated, bestie, I don't make the rules. πŸ’€
task "prepare", "server01", sub {
  install file => "/etc/passwd", {
               source => "/export/files/etc/passwd",
               owner  => "root",
               group  => "root",
               mode  => 644,
             };
};

Installing a file and doing something if the file was changed

This is the "notify me when it moves" pipeline:

task "prepare", "server01", sub {
  install file => "/etc/httpd/apache2.conf", {
               source   => "/export/files/etc/httpd/apache2.conf",
               owner    => "root",
               group    => "root",
               mode     => 644,
               on_change => sub { say "File was modified!"; }
             };
};

Installing a file from a template

Kind of giving main character template energy:

task "prepare", "server01", sub {
  install file => "/etc/httpd/apache2.tpl", {
               source   => "/export/files/etc/httpd/apache2.conf",
               owner    => "root",
               group    => "root",
               mode     => 644,
               on_change => sub { say "File was modified!"; },
               template  => {
                          greeting => "hello",
                          name    => "Ben",
                        },
             };
};

Hooks

This function supports the following hooks. Girl, these are your little side quests that fire at very specific moments:

before

This gets executed before anything is done. All original parameters are passed to it.

And watch this: the return value of this hook overwrites the original parameters of the function-call. Yes, it rewrites the vibes. πŸ‘‘

before_change

This gets executed right before the new package is installed. All original parameters are passed to it.

This hook is only available for package installations. If you need file hooks, you have to use the file() function. iykyk.

after_change

This gets executed right after the new package was installed. All original parameters, and the fact of change ("{ changed =" TRUE|FALSE }>) are passed to it.

This hook is only available for package installations. If you need file hooks, you have to use the file() function.

after

This gets executed right before the install() function returns. All original parameters, and any returned results are passed to it. The closing-the-bookend hook. πŸŽ€


🧚 remove($type, $package, $options)

This function will remove the given package from a system. Straight-up deletion arc.

task "cleanup", "server01", sub {
  remove package => "vim";
};

Goodbye vim. Gone but never forgotten. 🌸


⭐ update_system

This function does a complete system update. Like, the whole thing.

For example apt-get upgrade or yum update.

task "update-system", "server1", sub {
  update_system;
};

If you want to get the packages that where updated, you can use the on_change hook:

task "update-system", "server1", sub {
  update_system
    on_change => sub {
      my (@modified_packages) = @_;
      for my $pkg (@modified_packages) {
        say "Name: $pkg->{name}";
        say "Version: $pkg->{version}";
        say "Action: $pkg->{action}";   # some of updated, installed or removed
      }
    };
};

Options for update_system

  • update_metadata β€” set to TRUE if the package metadata should be updated. Since 1.5 default to FALSE if possible. Before 1.5 it depends on the package manager.
  • update_package β€” set to TRUE if you want to update the packages. Default is TRUE.
  • dist_upgrade β€” set to TRUE if you want to run a dist-upgrade if your distribution supports it. Default is FALSE.

πŸ’– installed_packages

This function returns all installed packages and their version. The full roster, bestie.

task "get-installed", "server1", sub {

   for my $pkg (installed_packages()) {
     say "name    : " . $pkg->{"name"};
     say "  version: " . $pkg->{"version"};
   }

};

πŸ¦‹ is_installed

This function tests if $package is installed. Returns 1 if true. 0 if false. Simple, clean, no drama.

task "isinstalled", "server01", sub {
  if( is_installed("rex") ) {
    say "Rex is installed";
  }
  else {
    say "Rex is not installed";
  }
};

🌈 update_package_db

This function updates the local package database. For example, on CentOS it will execute yum makecache.

task "update-pkg-db", "server1", "server2", sub {
  update_package_db;
  install package => "apache2";
};

Refresh the cache, then install. The way that that's just the correct order. ✨


πŸŽ€ repository($action, %data)

Add or remove a repository from the package manager. Repo chaos management, but make it cute.

For Debian: If you have no source repository, or if you don't want to add it, just remove the source parameter.
task "add-repo", "server1", "server2", sub {
  repository "add" => "repository-name",
     url      => "http://rex.linux-files.org/debian/squeeze",
     key_url  => "http://rex.linux-files.org/DPKG-GPG-KEY-REXIFY-REPO"
     distro    => "squeeze",
     repository => "rex",
     source    => 1;
};

To specify a key from a file use key_file => '/tmp/mykeyfile'.

To use a keyserver use key_server and key_id.

For ALT Linux: If repository is unsigned, just remove the sign_key parameter.
task "add-repo", "server1", "server2", sub {
  repository "add" => "altlinux-sisyphus",
     url      => "ftp://ftp.altlinux.org/pub/distributions/ALTLinux/Sisyphus",
     sign_key  => "alt",
     arch     => "noarch, x86_64",
     repository => "classic";
};
For CentOS, Mageia and SuSE only the name and the url are needed.
task "add-repo", "server1", "server2", sub {
  repository add => "repository-name",
     url => 'http://rex.linux-files.org/CentOS/$releasever/rex/$basearch/';

};

To remove a repository just delete it with its name. Poof. πŸ’…

task "rm-repo", "server1", sub {
  repository remove => "repository-name";
};

You can also use one call to repository to add repositories on multiple platforms:

task "add-repo", "server1", "server2", sub {
 repository add => myrepo => {
   Ubuntu => {
     url => "http://foo.bar/repo",
     distro => "precise",
     repository => "foo",
   },
   Debian => {
     url => "http://foo.bar/repo",
     distro => "squeeze",
     repository => "foo",
   },
   CentOS => {
     url => "http://foo.bar/repo",
   },
 };
};

One call, three platforms. That's not just slay, that's a group chat of repos. πŸ”₯


🧚 package_provider_for $os => $type;

To set another package provider as the default, use this function.

user "root";

group "db" => "db[01..10]";
package_provider_for SunOS => "blastwave";

task "prepare", group => "db", sub {
   install package => "vim";
};

This example will install vim on every db server. And if the server is a Solaris (SunOS) it will use the blastwave Repositories. Different OS, different provider, same icon behavior. πŸ‘‘


And that's the whole page, bestie!! Signing off with the receipts: this glorious thing is perl v5.40.1, dated 2025-10-03, and yes it's Rex::C...s::Pkg(3pm) β€” read it, love it, install package => "vim"; it. Periodt. πŸ’œβœ¨

πŸ“¦ where this page comes from