系统管理员的 Ruby

利用 Ruby 的威力更有效地进行系统管理

除了用作强大的 Web 应用程序开发平台外,通过与 Rails 框架相结合,Ruby 还具有较少被提及的另一面,那就是作为一种强大的脚本语言,就像 Python 或 Perl 那样。它拥有非常强大的功能,由于可以使用很多内建的和外部的库,因此可利用它的威力来解决通常系统管理工作环境中出现的很多脚本编写需求。而且,用 Ruby 编程也很有趣!

Santhosh Krishnamoorthy, 软件工程师, WSO2 Inc

Santhosh Krishnamoorthy 是班加罗尔 IBM 软件实验室的一名 TXSeries 测试工程师,从事系统间通信领域的工作。最近,他一直研究 Ruby、Ruby on Rails 和 Python 编程。


developerWorks 投稿作者

2009 年 2 月 26 日

简介

Ruby 是一种功能极其丰富的、免费的、简单的、可扩展的、可移植的、面向对象的脚本编程语言。最近,它在 Web 领域广受欢迎。这在一定程度上要归因于非常强大的 Web 应用程序开发框架 Rails,Rails 正是用 Ruby 编写的。Rails,也称 Ruby on Rails(ROR),顾名思义,它为快速、有效地开发 Web 应用程序提供一个非常强大的平台。它是高度可伸缩的,Web 上有很多站点就是用 Ruby on Rails 构建的。

除了与 Rails 一起用作 Web 应用程序开发平台外,Ruby 还具有较少被提及的另一面,那就是作为一种强大的脚本编程语言,就像 Python 或 Perl 那样。它拥有非常强大的功能,由于可以使用很多内建的和外部的库,因此可利用它的威力来解决通常系统管理工作环境中出现的很多脚本编程需求。

系统管理需要大量编写脚本以使事情更简单、更有效。编写脚本比单调的手动工作能更好地解决用户管理、进程管理、文件管理、软件包管理和其他基本的自动化需求。在这个场景中,Ruby 非常有用。它有一套很好的库可满足这一点。

对于本文,我假设读者具有 Ruby 的应用知识。这里提供的基本例子使用纯 Ruby,因此可以在 Ruby 支持的任何类 UNIX® 系统以及 Windows® 上运行。对于更高级的 Cfruby 例子,需要能够使用一个 UNIX 系统。下面所有的例子已经在一台 Linux® 机器上使用 Ruby v1.8.4 进行了测试。它们应该也能用于最新版本的 Ruby。


实践中的 Ruby

第一个例子在指定路径中搜索符合给定模式的文件,并以用户友好的方式给出关于这些文件的详细信息。实现这一目标不必依赖于任何命令行实用程序,只需使用 Ruby 内建的 API。因此,这个例子在有 Ruby 运行的任何平台上都能运行。

而且,这个例子展示了 Ruby 在简化脚本编写需求方面有多强大。它不是简单地模拟 *nix "find" 命令,而是构建在该命令之上,因而在使用 Ruby 时具有很强的定制能力。

清单 1. 在给定路径中搜索符合给定模式的模式的文件,并显示它们的详细信息
require 'find'
puts ""
puts "-----------------------File Search-----------------------------------"
puts ""
print "Enter the search path    : "
searchpath = gets
searchpath = searchpath.chomp
puts ""
print "Enter the search pattern : "
pattern = gets
pattern = pattern.chomp
puts"----------------------------------------------------------------------"
puts "Searching in " + searchpath + " for files matching pattern " + pattern
puts"----------------------------------------------------------------------"
puts ""
 Find.find(searchpath) do |path|
   if FileTest.directory?(path)
     if File.basename(path)[0] == ?.
       Find.prune       # Don't look any further into this directory.
     else
       next
     end
   else
     if File.fnmatch(pattern,File.basename(path))
       puts  "Filename     : " +  File.basename(path)
       s = sprintf("%o",File.stat(path).mode)
       print "Permissions  : "
       puts s
       print "Owning uid   : "
       puts File.stat(path).uid
       print "Owning gid   : "
       puts File.stat(path).uid
       print "Size (bytes) : "
       puts File.stat(path).size
       puts "---------------------------------------------------"
     end
   end
 end

在这个例子中:

  • 第 5-11 行 - 请求用户提供搜索路径和搜索模式。
  • 第 16 行 - 使用 Ruby 中 “Find” 类中的 “find” 方法遍历指定的搜索路径。
  • 第 17 行 - 检查发现的文件是否为一个目录。如果是目录,并且不是 “.”,则递归地遍历该目录。
  • 第 24 行 - 使用 “File” 类中的 “fnmatch” 方法检查发现的文件是否符合给定的模式。
  • 第 25-34 行 - 如果文件符合模式,则打印文件的详细信息。

下面是这个脚本的一个示例输出。

清单 2. 第一个例子的示例输出
[root@logan]# ruby findexample.rb

-----------------------File Search-----------------------------------

Enter the search path    : /test

Enter the search pattern : *.rb
----------------------------------------------------------------------
Searching in /test for files matching pattern *.rb
----------------------------------------------------------------------

Filename     : s.rb
Permissions  : 100644
Owning uid   : 1
Owning gid   : 1
Size (bytes) : 57
---------------------------------------------------
Filename     : test.rb
Permissions  : 100644
Owning uid   : 0
Owning gid   : 0
Size (bytes) : 996
---------------------------------------------------
Filename     : s1.rb
Permissions  : 100644
Owning uid   : 1
Owning gid   : 1
Size (bytes) : 39
---------------------------------------------------

在系统管理期间,最常见的一个需求是有效地使用 zip 文件来管理备份,或者将一组文件从一台计算机转移到另一台计算机。在这个方面,Ruby 很有优势。这里的第二个例子构建在第一个例子的基础上,但是包含了一个场景,在此场景中,需要将搜索到的文件打包到 zip 文件中。

内建的 zlib 模块可帮助处理 gzip 文件,对于大多数情况它都够好。但是,在这里我将使用另一个很好的 Ruby 库,即 “rubyzip”,来创建和处理 zip 归档文件。请查看 参考资料 小节,找到下载它的链接。而且要注意,这个例子使用纯 Ruby,它不依赖于计算机上当前提供的任何命令行实用程序。

安装 rubyzip

  • 通过提供的链接下载 “rubyzip” gem,并将它复制到系统中。(在撰写本文之际,它的文件名是 “rubyzip-0.9.1.gem”)。
  • 运行 gem 安装 rubyzip-0.9.1.gem
清单 3. 使用 zip 文件
require 'rubygems'
require_gem 'rubyzip'
require 'find'
require 'zip/zip'

puts ""
puts "------------------File Search and Zip-----------------------------"
puts ""
print "Enter the search path    : "
searchpath = gets
searchpath = searchpath.chomp
puts ""
print "Enter the search pattern : "
pattern = gets
pattern = pattern.chomp
puts"----------------------------------------------------------------------"
puts "Searching in " + searchpath + " for files matching pattern " + pattern
puts"----------------------------------------------------------------------"
puts ""
puts"----------------------------------------------------------------------"
puts "Zipping up the found files..."
puts"----------------------------------------------------------------------"
 Zip::ZipFile.open("test.zip", Zip::ZipFile::CREATE) {
  |zipfile|
 Find.find(searchpath) do |path|
  if FileTest.directory?(path)
     if File.basename(path)[0] == ?.
       Find.prune       # Don't look any further into this directory.
     else
       next
     end
   else
       if File.fnmatch(pattern,File.basename(path))
               p File.basename(path)
               zipfile.add(File.basename(path),path)
       end
    end
 end
 }

这个脚本为根据提供的搜索路径和搜索模式搜索到的文件创建一个名为 “test.zip” 的 zip 文件。

这个例子做以下事情:

  • 第 9-15 行 - 请求用户提供搜索路径和搜索模式。
  • 第 23 行 - 创建一个新的名为 “test.zip” 的 ZipFile。
  • 第 25 行 - 使用 Ruby 中 “Find” 类中的 “find” 方法遍历指定的搜索路径。
  • 第 26 行 - 检查发现的文件是否为一个目录。如果是目录,并且不是 “.”,则递归地遍历该目录。
  • 第 33 行 - 使用 “File” 类中的 “fnmatch” 方法检查发现的文件是否符合给定的模式。
  • 第 35 行 - 将符合的文件添加到 zip 归档中。

下面是一个示例输出:

清单 4. 第二个例子的示例输出
[root@logan]# ruby zipexample.rb

-----------------------File Search-----------------------------------

Enter the search path    : /test

Enter the search pattern : *.rb
----------------------------------------------------------------------
Searching in /test for files matching pattern *.rb
----------------------------------------------------------------------

----------------------------------------------------------------------
Zipping up the found files...
----------------------------------------------------------------------
"s.rb"
"test.rb"
"s1.rb"

[root@logan]# unzip -l test.zip
Archive:  test.zip
 Length     Date   Time    Name
 --------    ----   ----    ----
     996  09-25-08 21:01   test.rb
      57  09-25-08 21:01   s.rb
      39  09-25-08 21:01   s1.rb
 --------                   -------
    1092                   3 files

Cfruby - 高级的系统管理

根据 Cfruby 站点的定义,“Cfruby 允许使用 Ruby 进行系统管理。它既是一个用于系统管理的 Ruby 函数库,又是一个类 Cfengine 的克隆品(实际上是用于系统管理的一种特定领域语言,即 DSL)”。

Cfruby 基本上是一个由两部分组成的包:

  • Cfrubylib – 一个纯 Ruby 库,其中包含用于系统管理的类和方法。这包括文件复制、查找、校验和检查、包管理、用户管理等。
  • Cfenjin – 一种简单的脚本编程语言,可帮助为系统管理任务编写脚本(不必知道 Ruby)。

Cfruby 可以作为一个 Ruby gem 或 tar 压缩文件下载。gem 是最简单、最容易的方式。获取 gem,并使用 “gem install” 命令安装它。

安装 Cfruby:

  • 将下载的 Cfruby gem 文件复制到系统中。(在撰写本文之际,它的文件名是 “cfruby-1.01.gem”)。
  • 运行 gem 安装 cfruby-1.01.gem。

Cfruby 现在应该被安装到系统上。

使用 Cfruby

现在,我将展示 Cfruby 的功能,以及它如何大大简化系统管理。

有两种基本的方式可访问 Cfruby 库提供的功能:

  • 直接使用 libcfgruby 中的 Ruby 类。
  • 使用 cfrubyscript 包装器,它为 libcfruby 提供了一个更简洁的接口。

直接使用 libcfruby 中的 Ruby 类

Libcfruby 是 Cfruby 的核心,它包含一组模块,这些模块提供了各种用于简化系统维护和设置的功能。为了使用 libcfruby,需要在安装 Cfruby gem 之后,将 “require_gem 'cfruby'” 添加到脚本的顶端。这样便可以直接访问 libcfruby 中的所有核心模块,在脚本中可以根据需要按任意方式使用它们。这种方法惟一的缺点是 libcfruby 比较大,它将所有的类和方法都放入到它们各自的名称空间中。所以,为了访问任何一个类,都需要以名称空间加以限定。例如,libcfruby 提供了一个用于获得系统类型的方法。要获取操作系统的类型,需要做以下事情:

清单 5. 使用 libcfruby 获取操作系统类型
require 'rubygems'

require_gem 'cfruby'

os = Cfruby::OS::OSFactory.new.get_os()

puts(os.name)

这只是获得操作系统的名称。随着您用 libcfruby 做更多的事情,您的脚本中将充斥着更多指定名称空间的语句。正是由于这一点,另一种使用 Cfruby 的方法就显得很方便。

使用 cfrubyscript 包装器,这个包装器为 libcfruby 提供了一个更简洁的接口

为了使用 cfrubyscript 包装器,需要添加:

清单 6. 使用 cfrubyscript
require 'rubygems'

require_gem 'cfruby'

require 'libcfruby/cfrubyscript'

这样会将 cfrubyscript 包括到脚本中,然后就可以通过一个更简单的接口来访问 libcfruby 的功能。

cfrubyscript 做到了以下几点:

  • 它将一组变量导出到全局名称空间,例如 $os、$pkg、$user、$proc 和 $sched。
  • 它将大多数主要模块放到主名称空间中,所以可以调用 FileEdit.set 而不是 Cfruby::FileEdit.set。
  • 它为 String 和 Array 添加了很多助手方法,这些方法可以做一些 Cfruby 事情(安装程序、编辑文件等)。
  • 它还提供了一个很好的日志记录器。

所以,不再需要在脚本中指定一大堆的名称空间。上面用于获取操作系统类型的例子现在变成这样:

清单 7. 使用 cfrubyscript 获取操作系统的类型
require 'rubygems'

require_gem 'cfruby'

require 'libcfruby/cfrubyscript'

puts($os.name)

这可以翻译成一个单独的调用,该调用使用全局变量 $os。Cfruby 的确强大,它为管理类 *nix 系统提供了很多功能。

现在来看看其中一些功能,以及使用它们的一些基本例子。

用户管理

在系统管理中,最常见、最重要的任务之一就是用户和组的管理。Cfruby 以一种可移植的、简单的方式提供了一套强大的方法来实现该任务。

该任务是使用 UserManager 对象实现的,这个对象可以像下面这样从 OS 模块获得。

清单 8. 使用 libcfruby 获得 UserManager 对象
require 'rubygems'

require_gem 'cfruby'

osfactory = Cfruby::OS::OSFactory.new()

os = osfactory.get_os()

usermgr = os.get_user_manager()

如果使用 cfrubyscript 方式,那么已经有一个全局用户管理对象,即 $user,它可以直接用于调用方法。我将使用这种方法,因为这样更简单,更易于阅读。

下面展示如何使用它来创建和删除一个用户。

清单 9. 使用 cfgrubyscript 进行用户管理
require 'rubygems'

require_gem 'cfruby'

require 'libcfruby/cfrubyscript'

$user.adduser('newusername','password')

$user.deleteuser('usernametodelete',true)

上述代码做什么事情?

  • 第 1、2 行 – 和通常一样,将 libcfruby 和 cfrubyscript 包括到脚本中。
  • 第 3 行 – 以用户名 “newusername” 和第二个参数指定的密码创建一个新用户。
  • 第 4 行 – 删除用户名为 “usernametodelete” 的用户。第二个参数的值可以是 true 或 false,用于指定是否删除被删除用户的主目录。

类似地,组操作也可以使用 UserManager 对象中的 addgroup() 和 deletegroup() 方法来完成。

进程管理

管理员的另一项重要的任务是跟踪系统上运行的进程,并管理它们。Cfruby 在这方面也很有用,它为有效地处理进程提供了方法。

您可以使用 Cfruby 实现它。

清单 10. 使用 cfgrubyscript 进行进程管理
require 'rubygems'

require_gem 'cfruby'

require 'libcfruby/cfrubyscript'

$proc.kill($proc.vim)

'ps –aef'.exec()

上述代码做什么事情?

  • 第 3 行 – 使用全局 ProcessManager 对象 $proc 关闭由参数指定的 “vim” 进程。$proc.vim 是在系统上运行的 “vim” 进程的一个 ProcessInfo 类型的对象。它们是由 cfrubyscript 自动创建的。
  • 第 4 行 – 用指定的命令 “ps –aef” 启动一个新进程。可以从命令字符串中直接调用 exec 方法。

包管理

系统管理员必须负责的另一项任务是管理系统上的包。Cfruby 提供了一些方法用于方便地在系统上安装和删除软件。

清单 11. 使用 cfgrubyscript 进行包管理
require 'rubygems'

require_gem 'cfruby'

require 'libcfruby/cfrubyscript'

all = $pkg.packages()

installed = $pkg.installed_packages()

ruby.install()

上述代码做什么事情?

  • 第 3 行 – 使用 cfrubyscript 创建的全局 $pkg PackageManager 对象,通过调用 packages() 方法获得系统上所有可用的包。
  • 第 4 行 – 获得所有已安装的包的列表。
  • 第 5 行 – 通过调用 install 方法安装 Ruby 包。可以通过包名本身直接调用 install 助手方法。

事情就是这么简单。

文件管理

Cfruby 还可以帮助管理系统上的文件。通过使用 Cfruby 提供的方法,可以轻松地创建、编辑、删除、更改所有权和更改许可等等。

清单 12. 使用 cfgrubyscript 进行文件管理
require 'rubygems'

require_gem 'cfruby'

require 'libcfruby/cfrubyscript'

'/etc/ssh'.chown_mod('root', 'wheel', 'u=rw,g=r,o-rwx', `:recursive` => true)

上述代码做什么事情?

  • 第 3 行 – 更改文件 “/etc/ssh” 的所有者和组以及许可。直接从文件本身调用 chown_mod() 方法。这样,这是通过 cfrubyscript 的助手对象和方法实现的。注意,这里只用一行就实现了该功能。

所以,上述例子应该已经让您了解到 Cfruby 有多强大,使用它来管理系统有多容易。而且,由于提供了一套非常直观的类和方法,它使得系统管理的整个任务变得更加容易,也更加有趣。

关于 Cfruby 和它的那一整套功能还有很多需要知道的。它附带有一套很好的文档。建议您看一看这些文档,这样才能将这个 Ruby 库的全部威力释放出来。请查看参考资料小节,获取相关链接。


结束语

Ruby 不仅可以与 Rails 框架一起用于 Web 应用程序开发。它还可以像脚本编程语言一样强大,作为通常的 shell 脚本编程的一个很好的替代品,常用于实现系统管理中的脚本编程需求。

通过使用 Ruby 的一套内建模块和一些外部的库,系统管理员可以变得更加高效,工作更加有趣。Ruby 是一个非常有用、非常强大的工具,是每个系统管理员工具箱中必备的工具。

参考资料

学习

获得产品和技术

  • Ruby:下载最新版本的 Ruby。
  • Cfruby:下载 Ruby 的系统管理库。
  • RubyZip:下载用于 Ruby 的库的 zip 文件。

讨论

条评论

developerWorks: 登录

标有星(*)号的字段是必填字段。


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件

 


在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。

所有提交的信息确保安全。

选择您的昵称



当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

标有星(*)号的字段是必填字段。

(昵称长度在 3 至 31 个字符之间)

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

 


所有提交的信息确保安全。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=AIX and UNIX, Linux
ArticleID=372970
ArticleTitle=系统管理员的 Ruby
publish-date=02262009