SoFunction
Updated on 2025-03-03

Rex Concise Manual for Perl Cluster Configuration Management System

Rex is a cluster configuration management system based on SSH links written by Perl, which is syntactically similar to Puppet DSL. See the Chinese version of the official website. This article is only an introduction document written by me on the department’s wiki.

Common command parameters

The rex command has many parameters, but because our environment is krb certified, some parameters can only be written in Rexfile. Therefore, if you usually execute commands under /etc/puppet/webui with Rexfile, many configurations will be automatically loaded. Then there are basically only the following command parameters:
-Tv:Check which Task tasks are defined in the current Rexfile and the server group.
-H:Specifies which hosts the Task will be executed. The more convenient part here is that it supports the writing method of 10.5.16.[95..110].
-G:Specifies on which groups the Task will be executed. There are many ways to define Group. Rex supports defaults: directly specified in Rexfile through group instructions, setting through ini configuration files, etc. Currently I have implemented a groups_db directive to get it from our sqlite. groups_db('cdnbj::nginx') will automatically generate a server group called 'cdnbj::nginx', including all servers in cdnbj that have nginx deployed.
-e:Specify a temporary task. It is usually a simple command form such as 'say run "ipconfig". If you need complex logic, just write a Task in Rexfile.
-q:Specify the run log level, with -q and -qq.
-d:Specifies the run log level, with -d and -dd.

Rexfile Introduction

Parameter setting part:

Copy the codeThe code is as follows:

    set connection => "OpenSSH";
    user "root";
    krb5_auth;
    parallelism 10;

These four lines specify that kerberos authentication is used and 10 processes execute the ssh command.
Copy the codeThe code is as follows:

    desc "install puppet agent";
    task "puppet_install", sub {
    }
    before "puppet_install", sub {
    }
    after "puppet_install", sub {
    }

These lines are the Rexfile task definition body format. The task directive defines a task, and the task will be executed on a specific -H or -G server. The others are optional, and the desc content will be displayed when -Tv; the tasks defined by before and after will be executed before or after the corresponding task will be executed at the '''rex command execution, that is, 10.4.1.21 local '''.

Introduction to common instructions

run

Run the command. If there is a callback function, then stdout and stderr will be passed to the callback function; if not, stdout will be used as the return value.

for example:

Copy the codeThe code is as follows:

say run "uptime";
    run "nginx -v", sub { my ($out, $err) = @_; say $err };

file

Distribute files. The syntax is similar to Puppet's file. Supports source, template, ensure, on_change and other operations. Note: rex executes Rexfiles in sequence, so there is no need to set the Puppet require command.

for example:

Copy the codeThe code is as follows:

    file "/etc//",
      source => "repos/";
    file "/etc/nginx/",
      content => template("templates/etc/nginx/"),
      owner  => "nginx",
      group  => "nginx",
      mode   => 644,
      ensure => 'file',
      on_change => sub { service nginx => "restart"; };
    file "/etc/nginx/",
      ensure => "directory",

pkg

Install the software package, write the command in the early version of the command install package => "nginx" , and it has recently been changed to pkg , which is more like the Puppet syntax.

Passing arrays as pkg content is also supported. In addition, rex also provides an update_package_db directive to execute yum clean all or apt-get update operations. This is something Puppet lacks.

for example:

Copy the codeThe code is as follows:

 update_package_db();
   my $packages = case operating_system,
      Debian => ["apache2", "libphp5-apache2"],
      CentOS => ["httpd", "php5"],
   pkg $packages,
     ensure => "present";

ensure also supports several meanings such as present, absent, and latest. Same as Puppet.

account

User management used the create_user and create_group instructions, and recently updated the create_user to the account instruction.

for example:

Copy the codeThe code is as follows:

  create_group 'puppet';
  account "puppet",
    ensure   => "present",
    uid      => 509,
    home     => '/home/puppet',
    comment  => 'Puppet Account',
    expire   => '2015-05-30',
    groups   => ['puppet'],
    password => 'puppet',
    system   => 1,
    no_create_home => TRUE,
    ssh_key        => "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQChUw...";

tail

Used to observe the latest addition of logs of multiple hosts at the same time. It should be a relatively useful small function. The code is as follows:

Copy the codeThe code is as follows:

   tail "/var/log/syslog", sub {
     my ($data) = @_;
     my $server = Rex->get_current_connection()->{'server'};
     print "$server>> $data\n";
   };

Remote host details related variables

Puppet has a special Facts variable to determine the details of the remote host. Because Rex uses SSH connection, it will not run an agent on the remote host to collect this information, so it still provides relevant content by remotely executing commands. Several commonly used functions (can also be considered variables) are:

is_redhat

This is used to determine whether the operating system is the RedHat series. Before, because there were a batch of Debian machines, there was always such an operation logic in the Rexfile:

Copy the codeThe code is as follows:

    if ( is_debian ) {
    } elsif ( is_redhat ) {
    } else {
    }

operating_system_version

This is used to determine the specific operating system version number. For example, the operations that should be applied by CentOS5 and CentOS6 are different, and even CentOS6.5 and CentOS6.2 may be inconsistent.

For example, the 1w10 task in Rexfile:

Copy the codeThe code is as follows:

    if ( is_redhat and operating_system_version >= 64 )
    }

route

Rex can collect much more information than puppet, such as network-related, sysctl-related, etc. The 1w10 task in Rexfile uses route information to obtain the default gateway and network card interface.

Copy the codeThe code is as follows:

    my ($default_route) = grep {
      $_->{"flags"} =~ m/UG/ && (
        $_->{"destination"} eq "0.0.0.0" ||
        $_->{"destination"} eq "default" )
      } route;
    if ($default_route) {
        my $default_gw = $default_route->{"gateway"};
        my $default_if = $default_route->{"iface"};
        run "ip route change default via ${default_gw} dev ${default_if} initcwnd 10 initrwnd 10";
    };

connection

When multiple hosts perform tasks, most people want to see which host returns a certain result when outputting. I used the tail task before, but it looks very complicated to write. In fact, rex provides a more concise way of writing. That is connection->server.

Copy the codeThe code is as follows:

  task 'tellmewhoyouare', sub {
    say connection->server;
  }

The entire information of the currently connected server can also be obtained through the get_system_information command, which are actually equivalent. However, according to the literal meaning, it is generally used in different contexts.

If you want to view this information in full, you can view it through the dump_system_information directive. This command is different from print Dumper get_system_information() in that it will use each key as a separate variable. And these variables are embedded variables that can be directly used in the template of rex. for example:

Copy the codeThe code is as follows:

  listen <%= $eth0_ip %>:80;
  visible_hostname <%= $hostname %>

Variables that are not in the dump_system_information list and want to be used in template must be explicitly passed. This is inconsistent with Puppet. Puppet can obtain variables set in any pp class through the () directive in template, which completely ignores the existence of the lexical scope ==!

for example:

Copy the codeThe code is as follows:

   file '/etc/elasticsearch/',
     content => template('files/', conf => {
       clustername => 'logstash'
     });

Corresponding writing:
Copy the codeThe code is as follows:

  clustername: <%= $conf->{'clustername'} %>

That's all.