While watching MHA source, learn the three nodeutil.pm of Perl language

Source: Internet
Author: User
Tags get ip sprintf


While watching MHA source and learning Perl language three NodeUtil.pmNodeUtil.pm source analysis


MHA code is divided into Mha4mysql-manager (Management node) and Mha4mysql-node (Database node) two parts, maybe some people think mha4mysql-node only need to install the database node on it, but through the source can be seen, The node node also needs to be installed in the Management Point section, as the Manager node also calls the methods in Nodeutil. The following is the code for the Mha4mysql-node that has been added comment:


#! / usr / bin / env perl

# Copyright (C) 2011 DeNA Co., Ltd.
#
# 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; either version 2 of the License, or
# (at your option) any later version.
#
# 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.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

# Declare package name
package MHA :: NodeUtil;

# Perl is terrible, so it is recommended to use strict syntax
use strict;
use warnings FATAL => ‘all’;

# Introduce package, if the corresponding file is not found in Perl's lib path, an error will be reported
use Carp qw (croak);
use MHA :: NodeConst;
use File :: Path;
use Errno ();

# Create a directory when the directory does not exist.
sub create_dir_if ($) {
  my $ dir = shift;
  #Judge the directory before it is created
  if (! -d $ dir) {
    eval {
      print "Creating directory $ dir ..";
      mkpath ($ dir);
      print "done. \ n";
    };
    # [email protected] is the error message of the eval command. If it is empty, it means that the last eval command was executed successfully
    if ([email protected]) {
      # Details: [email protected] is global, in order to prevent affecting other programs, all the values must be assigned to the local variable $ e, and then reset by undef
      my $ e = [email protected];
      undef [email protected];
      # The directory already exists, this logic is a bit problematic, because it is already judged that the directory does not exist before going here
      if (-d $ dir) {
        print "ok. already exists. \ n";
      }
      else {
        # Output error information, using croak will output useful debugging information such as script name and code location, making it easier to find the problem
        croak "failed to create dir: $ dir: $ e";
      }
    }
  }
}

# Compare local and remote host files
# Parameter 1: local file
# Parameter 2: file on remote host
# Parameter 3: ssh user
# Parameter 4: remote host IP
# Parameter 5: remote host port, default is 22
# return value:
# 1: file does not exist
# 2: Inconsistent files
# 0: files are consistent

# Compare file checksum between local and remote host
sub compare_checksum {
  my $ local_file = shift;
  my $ remote_path = shift;
  my $ ssh_user = shift;
  my $ ssh_host = shift;
  my $ ssh_port = shift;
  # Default port number
  $ ssh_port = 22 unless ($ ssh_port);

  my $ local_md5 = `md5sum $ local_file`;
  return 1 if ($?);
  chomp ($ local_md5);
  $ local_md5 = substr ($ local_md5, 0, 32);
  my $ ssh_user_host = $ ssh_user. ‘@‘. $ ssh_host;
  my $ remote_md5 =
`ssh $ MHA :: NodeConst :: SSH_OPT_ALIVE -p $ ssh_port $ ssh_user_host \" md5sum $ remote_path \ "`;
  return 1 if ($?);
  chomp ($ remote_md5);
  $ remote_md5 = substr ($ remote_md5, 0, 32);
  return 2 if ($ local_md5 ne $ remote_md5);
  return 0;
}

# Copy the local file to the remote host
# Parameter: slightly
sub file_copy {
  my $ to_remote = shift;
  my $ local_file = shift;
  my $ remote_file = shift;
  my $ ssh_user = shift;
  my $ ssh_host = shift;
  my $ log_output = shift;
  my $ ssh_port = shift;
  $ ssh_port = 22 unless ($ ssh_port);

  my $ ssh_user_host = $ ssh_user. ‘@‘. $ ssh_host;
  my ($ from, $ to);
  if ($ to_remote) {
    $ from = $ local_file;
    $ to = "$ ssh_user_host: $ remote_file";
  }
  else {
    $ to = $ local_file;
    $ from = "$ ssh_user_host: $ remote_file";
  }

  my $ max_retries = 3;
  my $ retry_count = 0;
  my $ copy_fail = 1;
  my $ copy_command =
    "scp $ MHA :: NodeConst :: SSH_OPT_ALIVE -P $ ssh_port $ from $ to";
  if ($ log_output) {
    $ copy_command. = ">> $ log_output 2> & 1";
  }

  while ($ retry_count <$ max_retries) {
    if (
      system ($ copy_command)
      || compare_checksum (
        $ local_file, $ remote_file, $ ssh_user, $ ssh_host, $ ssh_port
      )
      )
    {
      my $ msg = "Failed copy or checksum. Retrying ..";
      if ($ log_output) {
        system ("echo $ msg >> $ log_output 2> & 1");
      }
      else {
        print "$ msg \ n";
      }
      $ retry_count ++;
    }
    else {
      $ copy_fail = 0;
      last;
    }
  }
  return $ copy_fail;
}

# Split error code into upper 8 bits and lower 8 bits
sub system_rc ($) {
  my $ rc = shift;
  my $ high = $ rc >> 8;
  my $ low = $ rc & 255;
  return ($ high, $ low);
}

# When the file does not exist, create an empty file
sub create_file_if {
  my $ file = shift;
  if ($ file && (! -f $ file)) {
    open (my $ out, ">", $ file) or croak "$!: $ file";
    close ($ out);
  }
}

# Delete a file when the file exists
sub drop_file_if ($) {
  my $ file = shift;
  if ($ file && -f $ file) {
    unlink $ file or croak "$!: $ file";
  }
}

# Analyze the IP address of the host
sub get_ip {
  my $ host = shift;
  my ($ bin_addr_host, $ addr_host);
  if (defined ($ host)) {
    $ bin_addr_host = gethostbyname ($ host);
    unless ($ bin_addr_host) {
      croak "Failed to get IP address on host $ host! \ n";
    }
    $ addr_host = sprintf ("% vd", $ bin_addr_host);
    return $ addr_host;
  }
  return;
}

# Get the current system time, accurate to the second
sub current_time () {
  my ($ sec, $ min, $ hour, $ mday, $ mon, $ year) = localtime ();
  $ mon + = 1;
  $ year + = 1900;
  my $ val = sprintf ("% d-% 02d-% 02d% 02d:% 02d:% 02d",
    $ year, $ mon, $ mday, $ hour, $ min, $ sec);
  return $ val;
}

# Check the version of the manager.If it is lower than the node version, it will report an error and exit.
sub check_manager_version {
  my $ manager_version = shift;
  if ($ manager_version <$ MHA :: NodeConst :: MGR_MIN_VERSION) {
    croak
"MHA Manager version is $ manager_version, but must be $ MHA :: NodeConst :: MGR_MIN_VERSION or higher. \ N";
  }
}

# From words Parse out the version number of mysql in the string, only take numbers to compare the version size
# $ str = "SELECT VERSION () AS Value"
sub parse_mysql_version ($) {
  my $ str = shift;
  my $ result = sprintf (‘% 03d% 03d% 03d’, $ str = ~ m / (\ d +) / g);
  return $ result;
}

# Parse out the major version number of mysql from the string, only take numbers to compare the version size
# $ str = "SELECT VERSION () AS Value"
sub parse_mysql_major_version ($) {
  my $ str = shift;
  my $ result = sprintf (‘% 03d% 03d’, $ str = ~ m / (\ d +) / g);
  return $ result;
}

# Compare if $ my_version is higher than $ target_version
# mysql master-slave structure
sub mysql_version_ge {
  my ($ my_version, $ target_version) = @_;
  my $ result =
    parse_mysql_version ($ my_version) ge parse_mysql_version ($ target_version)
    ? 1
    : 0;
  return $ result;
}

# Array of special characters to be escaped by the shell
my @shell_escape_chars = (
  ‘” ’,‘! ’,‘ # ’,‘ & ’,‘; ’,‘ `‘, ‘|’, ‘*’,
  ‘?’, ‘~’, ‘<‘, ‘>’, ‘^’, ‘(‘, ‘)’, ‘[’,
  ‘]’, ‘{’, ‘}’, ‘$’, ‘,’, ‘‘, ‘\ X0A’, ‘\ xFF’
);

# Reverse the special characters of the shell
sub unescape_for_shell {
  my $ str = shift;
  if (! index ($ str, ‘\\\\‘)) {
    return $ str;
  }
  foreach my $ c (@shell_escape_chars) {
    my $ x = quotemeta ($ c);
    my $ pattern = "\\\\ (". $ x. ")";
    $ str = ~ s / $ pattern / $ 1 / g;
  }
  return $ str;
}

# Escape shell special characters
sub escape_for_shell {
  my $ str = shift;
  my $ ret = "";
  foreach my $ c (split //, $ str) {
    my $ x = $ c;
    my $ escape = 0;
    foreach my $ e (@shell_escape_chars) {
      if ($ e eq $ x) {
        $ escape = 1;
        last;
      }
    }
    if ($ x eq "‘ ") {
      $ x = ~ s / ‘/‘ \\ ‘‘ /;
    }
    if ($ x eq "\\") {
      $ x = "\\\\";
    }
    if ($ escape) {
      $ x = "\\". $ x;
    }
    $ ret. = "$ x";
  }
  $ ret = "‘ ". $ ret." ‘";
  return $ ret;
}

# Escape special characters of mysql_command
sub escape_for_mysql_command {
  my $ str = shift;
  my $ ret = "";
  foreach my $ c (split //, $ str) {
    my $ x = $ c;
    if ($ x eq "‘ ") {
      $ x = ~ s / ‘/‘ \\ ‘‘ /;
    }
    $ ret. = $ x;
  }
  $ ret = "‘ ". $ ret." ‘";
  return $ ret;
}

# mysql terminal command preprocessing
sub client_cli_prefix {
  my ($ exe, $ bindir, $ libdir) = @_;
  croak "unexpected client binary $ exe \ n" unless $ exe = ~ / ^ mysql (?: binlog)? $ /;
  my% env = (LD_LIBRARY_PATH => $ libdir);
  my $ cli = $ exe;
  if ($ bindir) {
    if (ref $ bindir eq "ARRAY") {
      $ env {‘PATH‘} = $ bindir;
    }
    elsif (ref $ bindir eq "") {
      $ cli = escape_for_shell ("$ bindir / $ exe");
    }
  }
  for my $ k (keys% env) {
    if (my $ v = $ env {$ k}) {
      my @dirs = ref $ v eq "ARRAY"? @ {$ v}: (ref $ v eq ""? ($ v): ());
      @dirs = grep {$ _ &&! /: /} @dirs;
      if (@dirs) {
        $ cli = "$ k ="
          . join (":", (map {escape_for_shell ($ _)} @dirs), "\ $$ k")
          . "$ cli";
      }
    }
  }

  # $ cli. = "--no-defaults";
  return $ cli;
}

1;  
NODEUTIL.PM Summary


Through the previous section, we have a basic understanding of Perl, I believe that in the Nodeutil source code, it will be a lot easier, inside are some of the method as the name implies, the specific call instance code to leave you crossing free play.



The only point worth mentioning is Perl's regular expression processing, but this online already has quite a tutorial, here does not repeat to explain, give everyone two address:



Introductory version:



Http://www.runoob.com/perl/perl-regular-expressions.html



Detailed version:



http://blog.csdn.net/eroswang/article/details/1812528



While watching MHA source, learn the three nodeutil.pm of Perl language


Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.