TranslateProject/translated/tech/20170523 An introduction to Libral a systems management library for Linux.md

265 lines
27 KiB
Markdown
Raw Normal View History

Libral 简介:开源的 Linux 系统管理库
2017-05-26 09:38:38 +08:00
============================================================
> Libral 对系统资源和服务提供了一个统一的管理 API ,其可以作为脚本管理任务和配置管理系统的构建的坚实基础。
2017-05-26 09:38:38 +08:00
![An introduction to Libral, a systems management library for Linux](https://opensource.com/sites/default/files/styles/image-full-size/public/images/business/yearbook-haff-rx-linux-file-lead_0.png?itok=48iDNoH8 "An introduction to Libral, a systems management library for Linux")
作为继承了 Unix 的传统的 Linux 操作系统,其并没有一个综合的系统管理 API 接口,相反,管理操作是通过多种特定用途的工具和 API 来实现的,其每一个都有自己约定和特有的风格。这就使得编写一个极其简单的系统管理任务脚本将变得很困难很脆弱。
2017-07-13 22:20:35 +08:00
举个例子来说,改变 “app” 用户的登录 shell 要运行 `usermod -s /sbin/nologin app`。这个命令运行的很好,除了系统上没有 “app” 用户的情况之外。为了修复这个例外错误,具有创新精神的脚本编写者也许要这样写:
2017-07-13 22:20:35 +08:00
2017-05-26 09:38:38 +08:00
```
grep -q app /etc/passwd \
  && usermod -s /sbin/nologin app \
  || useradd ... -s /sbin/nologin app
2017-05-26 09:38:38 +08:00
```
因此,当 “app” 用户存在于系统中时,会执行更改登录 shell 的操作;而当此用户不存在时,此用户就会被创建。不幸的是,这种利用编写系统管理任务脚本的途径是不适合的:对于每一种资源来说,就会有一套不同的工具,而且必须考虑其不同的使用惯例;不一致和经常性的不完备的错误报告将会使错误的处理变得困难;再者会因为工具所具有的本质特性引起的故障而导致执行失败。
2017-05-26 09:38:38 +08:00
实际上,以上所举的例子是不正确的:`grep` 并不是用来查找 “app” 用户的,它只能简单的查找文件 `/etc/passwd` 的一些行中是否有字符串 “app”在大多数情况下它或许可以工作但是也可能会在最关键的时刻出错。
2017-05-26 09:38:38 +08:00
很显然,管理工具不是执行简单的任务的脚本,充其量其也难以构成一个较大的管理系统。认识到这一点,现有的配置管理系统,比如 Puppet、Chef及 Ansible围绕基本的操作系统资源的管理竭尽全力的建立其内部 API 就是明智之举。这些资源由各自需要的密切相关的工具抽象成内部的 API。这不仅导致大量的重复性工作也为尝试一个新的和创新管理工具设置了强大的障碍。
2017-05-26 09:38:38 +08:00
在创建虚拟机或者容器镜像这一领域,这种障碍就变得非常明显:比如在创建镜像的过程中,就需要要么回答关于它们的简单问题,要么对其进行简单的更改。但是要使工具完成所有的任务就需要特殊的处理,这些问题和变化正好是一些人试图利用脚本解决的问题。因此,镜像构建要么依靠特定的脚本,要么需要使用(和安装)一个相当强大的配置管理系统。
2017-05-26 09:38:38 +08:00
[Libral][11] 将为管理工具和任务提供一个可靠的保证,通过对系统资源提供一个公用的管理 API并使其可以通过命令行工具 `ralsh` 使用,它允许用户按照相同的方法查询和修改系统资源,能够有可预见的错误报告。对以上的举例来说,可以通过命令 `ralsh -aq user app` 检查 “app” 用户是否存在;通过 `ralsh -aq package foo` 检查 “foo” 软件包是否已经被安装;一般情况下,通过命令 `ralsh -aq TYPE NAME` 检查 ”NAME“ 是否是 ”TYPE“ 资源类型。类似的,创建或更改存在的用户,可以运行:
2017-07-14 09:25:04 +08:00
2017-05-26 09:38:38 +08:00
```
ralsh user app home=/srv/app shell=/sbin/nologin
2017-05-26 09:38:38 +08:00
```
接下来在文件 `/etc/hosts` 创建和修改条目,可以运行命令:
2017-07-14 16:21:11 +08:00
2017-05-26 09:38:38 +08:00
```
ralsh hostmyhost.example.com ip=10.0.0.1 \
host_aliases=myhost,apphost
2017-05-26 09:38:38 +08:00
```
以这种方式运行“ralsh” 的用户事实上完全与那两个命令的内部运行工作机制相隔离:第一个需要适当的调用命令 `useradd` 或者 `usermod`,而第二个需要在 `/etc/hosts` 文件中进行编辑。而对于该用户来说,他们似乎都采取同样的模型:“确保资源处于我所需要的状态。”
2017-05-26 09:38:38 +08:00
2017-07-14 16:21:11 +08:00
### 怎样获取和使用 Libral 呢?
2017-07-14 16:21:11 +08:00
Libral 可以在[这个 git 仓库][12]找到并下载。其核心是由 C++ 编写的,构建它的说明可以[在该仓库中][13]找到,不过只是在你想要为 Libral 的 C++ 核心做贡献的时候才需要看它。Libral 的网站上包含了一个 [预构建的 tarball][14],可以用在任何使用 “glibc 2.12” 或者更高版本的 Linux 机器上。可以使用该 “tarball” 的内容进一步探究 ralsh 和开发新的提供者provider它使得 Libral 具备了管理新类型资源的能力。
2017-07-14 16:21:11 +08:00
在下载解压“tarball”后在目录“ral/bin”下就会生成“ralsh”命令。运行不需要任何参数的“ralsh”命令就会将 Libral 的所有资源类型列举出来。利用“--help“选项打印输出关于”ralsh“更多的说明。
2017-07-14 16:21:11 +08:00
### 与配置管理系统的关系
2017-07-14 16:21:11 +08:00
知名的配置管理系统,如 Puppet、Chef 及 Ansible解决了一些 Libral 所解决的同样的问题。将 Libral 与它们的区别是是它们所做大部分工作和 Libral 不同。配置管理系统被构建来处理跨大量节点的管理各种事物的多样复杂性。而另一方面 Libral 旨在提供一个定义明确的低级别的系统管理 API ,独立于任何特定的工具,可用于各种各样的编程语言。
2017-05-26 09:38:38 +08:00
通过消除大型配置管理系统中包含的应用程序逻辑Libral 在如何使用方面是非常万能的,从介绍里提及的简单的脚本任务,到作为构建复杂的管理应用的构建块。专注与这些基础层面也使其保持很小,目前不到 2.5 MB这对于资源严重受限的环境如容器和小型设备来说是一个重要考虑因素。
2017-07-14 16:21:11 +08:00
### Libral API
2017-05-26 09:38:38 +08:00
在过去的十年里Libral API 的设计是由实现配置管理系统的经验所指导的,虽然它并没有直接绑定到它们其中任何一个应用上,但它考虑这些问题,做出选择克服它们的缺点。
2017-07-14 16:21:11 +08:00
在 API 设计中四个重要的原则:
2017-05-26 09:38:38 +08:00
* 期望的状态
* 双向性
* 轻量级抽象
* 易于扩展
2017-07-14 16:21:11 +08:00
2017-05-26 09:38:38 +08:00
Basing a management API on desired state, i.e., the idea that the user expresses what the system should look like after an operation rather than how to get into that state, is hardly controversial at this point. Bidirectionality makes it possible to use the same API and, more importantly, the same resource abstractions to read existing state and to enforce changes to it. Lightweight abstractions ensure that it is easy to learn the API and make use of it quickly; past attempts at such management APIs have unduly burdened the user with learning a modeling framework, an important factor in their lack of adoption.
建立一个期望状态的管理 API举个例子来说用户表示当操作执行后希望系统看起来是什么状态而不是怎样进入这个状态是很难引起争议的。双向性使得使用相同的 API 成为可能,更重要的是,相同的资源抽象成读取现有状态和强制修改成这种状态。轻量级的抽象行为确保能容易的学习 API 并能快速的使用;过去尝试管理 API 的方式已经过度加重了学习建模框架的使用者的负担了,一个重要的因素是他们的接受力缺乏。
-->
2017-07-14 16:21:11 +08:00
2017-05-26 09:38:38 +08:00
Finally, it has to be easy to extend Libral's management capabilities so that users can teach Libral how to manage new kinds of resources. This is important both because of the sheer amount of resources that one might want to manage (and that Libral will manage in due time), as well as because even a fully built-out Libral will always fall short of a user's custom management needs.
2017-07-14 16:21:11 +08:00
终于,它必须易于扩展 Libral 的管理功能,这样用户可以让 Libral 如何管理新类型的资源。这很重要因为绝对数量的资源一种情况可能需要管理Libral 将在适当时间进行管理),再者,因为既是一个完全成熟的 Libral 也总是存在达不到用户自定义的管理需求。
2017-05-26 09:38:38 +08:00
Currently, the main way to interact with the Libral API is through the **ralsh **command line tool. It exposes the underlying C++ API, which is still in flux, and is mainly geared at simple scripting tasks. The project also provides language bindings for CRuby, with others to follow.
2017-07-15 16:44:29 +08:00
目前与 Libral API 进行交互的主要方式是通过“ralsh”命令行工具。它公开了底层的 C++ API ,不过人处在不断的演变当中,主要的还是为面向简单的脚本任务做准备。该项目提供了为 CRuby提供语言绑定并且会有更多的参加者共同参与。
2017-07-14 16:21:11 +08:00
2017-05-26 09:38:38 +08:00
In the future, Libral will also provide a daemon with a remote API, so that it can serve as the basis for management systems that do not need to install additional agents on managed nodes. This, coupled with the ability to tailor the management capabilities of Libral, makes it possible to tightly control which aspects of a system can be managed and which ones are protected from any interference.
2017-07-15 16:44:29 +08:00
未来Libral 还将提供一个可远程支持的虚拟光驱 API ,因此它可以成为一个管理系统的基本服务,在此基础上管理节点不需要安装额外的代理。这一点,共轭能力能够更加适合 Libral 的管理功能,使其在更加紧密的控制系统方面和对来自任何干扰的保护成为一种可能。
2017-05-26 09:38:38 +08:00
For example, a Libral installation that is restricted to managing users and services will be guaranteed to not interfere with the packages installed on a node. Controlling what gets managed in this manner is currently not possible with any of the existing configuration-management systems; in particular, systems that require arbitrary SSH access to a managed node also expose that system to unwanted accidental or malicious interference.
2017-07-15 16:44:29 +08:00
举个例子来说Libral 仅限于管理用户和服务的安装将受到保护,在一个节点上进行包安装的时候不会受到干扰。获得以这种方式的管理控制在当前是不可能与现有的配置管理系统共存的;尤其当系统需要通过任意的 SSH 访问一个托管的节点并同时显示对系统有害的信息或者是恶意干扰。
2017-05-26 09:38:38 +08:00
The basis of the Libral API is formed by two very simple operations: **get** to retrieve the current state of resources, and **set** to enforce the state of current resources. Idealizing a little from the actual implementation, they can be thought of as:
2017-07-15 16:44:29 +08:00
Libral API 的基础是由两个非常简单的操作构成的“get” 用来检索当前资源的状态“set” 用来强制当前资源的状态。理想化的实现当前安装启用状态,可能要通过以下步骤:
2017-05-26 09:38:38 +08:00
```
provider.get(names) -> List[resource]
provider.set(List[update]) -> List[change]
```
The **provider** is the object that knows how to manage a certain kind of resource, like a user, a service, or a package, and the Libral API provides ways to look up the provider for a certain kind of resource.
2017-07-15 16:44:29 +08:00
“provider" 是要了解怎样管理一种资源的对象就像用户服务包文件Libral API 提供了一种查找资源的方法。
2017-05-26 09:38:38 +08:00
The **get** operation receives a list of resource names, e.g., usernames, and needs to produce a list of resources, which are essentially hashes listing the attributes of each resource. This list must contain resources with the provided names, but might contain more, so that a naive **get** implementation can simply ignore the names and list all the resources it knows about.
2017-07-15 16:44:29 +08:00
”get“ 操作能够接收资源名称列表举例子来说用户名需要产生一个资源列表本质来说是利用散列的方式列出每种资源的属性。这个列表必须包含提供名称的资源但是可能包含更多内容因此”get“ 的启用可以忽略名称列出所有它知道的资源。
2017-05-26 09:38:38 +08:00
The **set** operation is used to enforce desired state and receives a list of updates. Each update contains **update.is**, a resource representing the current state, and **update.should**, a resource representing the desired state. Calling the **set** method will make sure that the resources mentioned in the update list will be in the state indicated in **update.should** and produces a list of the changes made to each resource.
2017-07-15 16:44:29 +08:00
”set“ 操作被用来强制要求的状态接收列表的更新。每次更新包含”update.is",表示当前状态的资源“update.should" 表示被要求状态的资源。调用”set“方法将会确认更新列表中提到的资源将会在”update.should"中显示状态,产生一个对每个资源进行更改的列表。
With **ralsh**, the current state of the **root** user can be retrieved with the command **ralsh user root**; by default, the command produces human-readable output, reminiscent of Puppet, but **ralsh** also supports a **--json** flag to make it produce JSON output for consumption by scripts. The human-readable output is:
在 “ralsh”下利用“ralsh user root"能够重新获得“root”用户的当前状态;默认情况下这个命令会产生一个用户可读的输出就像木偶一样但是”ralsh“支持”--json“选项将利用脚本消耗产生 JSON 输出。用户可读输出是:
2017-05-26 09:38:38 +08:00
```
# ralsh user root
user::useradd { 'root':
ensure => 'present',
comment => 'root',
gid => '0',
groups => ['root'],
home => '/root',
shell => '/bin/bash',
uid => '0',
}
```
Similarly, the user can be changed with:
2017-07-15 16:44:29 +08:00
用户将被修改成类似于下面的形式:
2017-05-26 09:38:38 +08:00
```
# ralsh user root comment='The superuser'
user::useradd { 'root':
ensure => 'present',
comment => 'The superuser',
gid => '0',
groups => ['root'],
home => '/root',
shell => '/bin/bash',
uid => '0',
}
comment(root->The superuser)
```
The output of ralsh lists both the new state of the root user, with the changed comment attribute, and what changes were made (solely to the **comment** attribute in this case). Running the same command a second time will produce much the same output, but without any change indication, as none will be needed.
2017-07-15 16:44:29 +08:00
”ralsh“的输出列出了”root“用户两种新状态被改变的属性注释以及修改了什么内容在这种情形下单独的”注释”属性。运行相同的命令一秒钟的时间将产生同样的输出但是没有任何修改的迹象也没有需求。
2017-05-26 09:38:38 +08:00
### Writing providers
2017-07-15 16:44:29 +08:00
编写程序管理器
2017-05-26 09:38:38 +08:00
It is crucially important that writing new providers for ralsh is easy and requires a minimum amount of effort. For this reason, ralsh offers a number of calling conventions that make it possible to trade the complexity of implementing a provider against the power of what the provider can do. Providers can either be external scripts that adhere to a specific calling convention or be implemented in C++ and built into Libral. Currently, there are three calling conventions:
2017-07-15 16:44:29 +08:00
为“ralsh”编写新的管理器是很容易的也是花费不了多少努力但是这一步骤是至关重要的。正因为如此“ralsh”提供了大量的调用约定依靠其效能实现交换复杂的执行成为可能。管理器可以使用遵循特定调用约定的外部脚本也可以是执行 C++ 并构建Libral。到目前为止有三种调用约定
2017-05-26 09:38:38 +08:00
* The [simple][6] calling convention is geared towards writing shell scripts that serve as providers
2017-07-15 16:44:29 +08:00
[simple][16]调用约定是针对编写 shell 脚本服务于管理器。
2017-05-26 09:38:38 +08:00
* The [JSON][7] calling convention is meant for writing providers in scripting languages like Ruby or Python
2017-07-15 16:44:29 +08:00
[JSON][7]调用约定意味着可以利用 Ruby 或者 Python 脚本语言编写管理器。
2017-05-26 09:38:38 +08:00
* The [internal C++ API][8] can be used to implement providers natively
2017-07-15 16:44:29 +08:00
[internal C++ API[]8] 可以被用来执行本机的管理器。
2017-05-26 09:38:38 +08:00
It is highly recommended to start provider development using the **simple** or the **JSON** calling convention. The file [simple.prov][15] on GitHub contains a skeleton for a simple shell provider, and it should be easy to adapt it for one's own provider. The file [python.prov][16] contains the skeleton of a JSON provider written in Python.
2017-07-15 16:44:29 +08:00
强烈建议开始管理其开发使用“simple” 或者“JSON” 调用约定。[simple.prov][15]文件在GitHub上包含了一个简单的 shell 管理器框架,应该很容易的被自己的管理器兼容。[python.prov][16]文件包含了利用 Python编写的 JSON 管理器框架。
2017-05-26 09:38:38 +08:00
One problem with using higher-level scripting languages for providers is that the runtimes, including all supporting libraries, for these languages need to be present on the system on which Libral will run. In some cases, that is not an obstacle; for example, a provider that does package management based on **yum** can expect that Python is present on the system, as **yum** is written in it.
2017-07-15 16:44:29 +08:00
利用高版本脚本语言编写的管理器存在一个运行时间的问题,包含所有的支持库,这些脚本语言需要在当前的系统上运行 Libral。在某些情况下这不是一个障碍举例子来说基于“yum” 的包管理的管理器需要 Python 被安装在当前的系统上而“yum”是用 Python 开发的一样。
2017-05-26 09:38:38 +08:00
In many other cases though, there's no logical choice for a language beyond Bourne shell (or Bash) that can be expected to be installed on all managed systems. Often, provider writers need a more powerful scripting environment than just that. Unfortunately, bundling a full Ruby or Python interpreter with its runtime would increase Libral's size beyond what can reasonably be
used in resource-constrained environments. On the other hand, the canonical choices of Lua or Javascript as small embeddable scripting languages are not suitable for this context as they are both not familiar to most provider writers, and require quite a bit of work to expose commonly needed facilities for systems management.
2017-07-15 16:44:29 +08:00
然而在很多时候,无法选择一种超过 Bourne shell (或者 Bash的设计语言能够按照预期安装到所有的管理系统上。通常管理器的编写者需要一个更加强大的脚本编译环境是更实际一些的。然而事与愿违绑定一个完整的 Ruby 或 Python作为解释器来运行将会增加 Libral 的空间超出了实际使用环境对资源的限制。另一方面Lua 或者 JavaScript 可嵌入的脚本编辑语言的选择规范与其上下文是不匹配的,因为大多数的管理器的编写者不熟悉他们,通常情况下需要做大量的工作对需要生产环境系统管理工具进行发布。
2017-05-26 09:38:38 +08:00
Libral bundles a version of [mruby][17], a small, embeddable version of Ruby, to give provider writers a stable foundation, and a powerful programming language for their implementation. mruby is a full implementation of the Ruby language, albeit with a much reduced standard library. The mruby bundled with Libral contains the parts of Ruby's standard library most important for scripting management tasks, which will be enhanced further over time based on the needs of provider writers. Libral's mruby also bundles an API adpater that makes writing providers to the json convention more comfortable, as it contains simple utilities (like [Augeas][18] for modifying structured files) and conveniences around parsing and outputting JSON. The file [mruby.prov][19] contains a skeleton example of a json provider written in mruby.
2017-07-15 16:44:29 +08:00
Libral 绑定了一个[mruby][17]版本,一个小的,嵌入在 Ruby 的版本提供给管理器的编写者一个具有稳定的基础以及功能强大的可实现的程序设计语言。Mruby 就是一款可实现的 Ruby 语言,尽管减少了大量的标准库支持。绑定了 Libral 的 Mruby 包含了 Ruby 的标准库的大多数重要的脚本编辑管理任务随着时间的推移将来在管理器编写者基础性的需求上将得到加强。Libral 的 Mruby 绑定了 API 适配器使编写管理器更适合 JSON 约定,因为它包含了简单的工具(如编译修改结构体文件的[Augeas][18]和围绕语法和输出JSON的约定。[mruby.prov][19]文件包含了利用 Mruby 编写的 JSON 管理器框架实例。
2017-05-26 09:38:38 +08:00
### Future work
2017-07-15 16:44:29 +08:00
展望
2017-05-26 09:38:38 +08:00
The most important next steps for Libral are to make it more widely usable—the [precompiled tarball][20] is a great way to get started and sufficient to develop providers, but Libral also needs to be packaged and made available in mainstream distributions. In a similar vein, the utility of Libral strongly depends on the set of providers it ships with and those need to be expanded to cover a core set of management functionality. The Libral site contains [a todo list][21] showing the providers that are most urgently needed.
2017-07-15 16:44:29 +08:00
Libral 最关键的是下一步要使其增加广泛的可用性-从[precompiled tarball][20]开始并充分的开发管理器是一个极好的方法,但是 Libral 需要打包并且能够在主流的分布上提高可用性。同样的Libral 强大的功用取决于管理器的集合附带及需要被扩展覆盖的一组核心管理功能。Libral 的网站上包含了 [a todo list][21]并且列出了管理器的最迫切需求。
2017-05-26 09:38:38 +08:00
There are also several ways in which the availability of Libral for different uses can be improved: from writing bindings for additional languages, for example, Python or Go, to making the use of **ralsh** in shell scripts even easier by offering, besides the existing human-readable output and JSON output, an output format that is easy to process in shell scripts. Use of Libral for larger-scale management can also be improved by adding the remote API discussed above, and by better supporting bulk installation of Libral via transports like SSH—that mostly requires providing prebuilt tarballs for more architectures and scripts that can select the right one based on the discovered architecture of the target system.
2017-07-15 16:44:29 +08:00
现在有多种方法来让不同的用户能够提高 Libral的可用性编写绑定附加程序语言举例来说Python 或者 Go提供条件使“ralsh” 更容易在 shell 脚本中使用,除了现有的可读输出和 JSON 输出之外,可以很轻松的在 shell 脚本中格式化输出。Libral 运用大规模的管理能够在增加远程 API 协商而得到改良Libral 利用像 SSh 这样的传输工具实现了更好的支持批量安装,大多数情况下需要提供更多的框架和脚本的预先构建包才能选择一款基于创新的目标框架系统。
2017-05-26 09:38:38 +08:00
There are many more ways in which Libral, its API, and its capabilities could evolve; one intriguing possibility is adding notification capabilities to the API so that Libral can report changes to system resources as they happen outside of its purview. The challenge for Libral will be to continue to be a small, lightweight and well-defined tool while covering an ever increasing set of uses and management capabilities—a challenge and a journey that I encourage every reader to become a part of.
2017-07-15 16:44:29 +08:00
Libral 有很多方式方法,如 API ,它的性能在不断地进化发展;一个有趣的可能性是为 API 增加性能的显示这样做可以向系统报告资源在超出它的范围发生的变化。Libral 面临的挑战将一直持续下去的是小型化,轻量级和良好定义的工具,来替代曾经增加的使用和管理性能-我希望每一个读者都能成为这个挑战和旅行的一部分。
2017-05-26 09:38:38 +08:00
If any of this has made you curious, I would love to hear from you, be it in the form of a pull request, an enhancement request, or just a report of your experience trying out **ralsh**.
如果这让你很好奇我很想听听你的想法可以用推拉请求的方式可以是增强请求方式亦或者报告你对“ralsh”测试的经验体验。
2017-07-15 16:44:29 +08:00
(题图:[Internet Archive Book Images][10]修改Opensource.com. CC BY-SA 4.0
2017-05-26 09:38:38 +08:00
--------------------------------------------------------------------------------
作者简介:
David Lutterkort - David is a software engineer at Puppet, where hes worked on projects such as Direct Puppet and Razor, the best provisioning tool, ever. He was one of the earliest contributors to Puppet and is the main author of Augeas, a configuration editing tool.
2017-07-15 16:44:29 +08:00
David Lutterkort - 戴维是一个 Puppet 的软件工程师,他曾经参与的项目有 Direct Puppet 和 Razor最好的工具提供。他是 Puppet 最早的编著者之一,也是 Augeas 的主要作者,一个编辑工具配置专家。
2017-05-26 09:38:38 +08:00
------------------------
via: https://opensource.com/article/17/5/intro-libral-systems-management-library-linux
作者:[David Lutterkort][a]
2017-07-15 16:44:29 +08:00
译者:[译者stevenzdg988](https://github.com/stevenzdg988)
2017-05-26 09:38:38 +08:00
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://opensource.com/users/david-lutterkort
[1]:https://opensource.com/resources/what-is-linux?src=linux_resource_menu
[2]:https://opensource.com/resources/what-are-linux-containers?src=linux_resource_menu
[3]:https://developers.redhat.com/promotions/linux-cheatsheet/?intcmp=7016000000127cYAAQ
[4]:https://developers.redhat.com/cheat-sheet/advanced-linux-commands-cheatsheet?src=linux_resource_menu&intcmp=7016000000127cYAAQ
[5]:https://opensource.com/tags/linux?src=linux_resource_menu
[6]:https://github.com/puppetlabs/libral/blob/master/doc/invoke-simple.md
[7]:https://github.com/puppetlabs/libral/blob/master/doc/invoke-json.md
[8]:https://github.com/puppetlabs/libral/blob/master/doc/invoke-native.md
[9]:https://opensource.com/article/17/5/intro-libral-systems-management-library-linux?rate=PqOZGb7A0LUlHQRwkzl23iaJZ2ZUy6gKcc6HOzaRL58
[10]:https://www.flickr.com/photos/internetarchivebookimages/14803082483/in/photolist-oy6EG4-pZR3NZ-i6r3NW-e1tJSX-boBtf7-oeYc7U-o6jFKK-9jNtc3-idt2G9-i7NG1m-ouKjXe-owqviF-92xFBg-ow9e4s-gVVXJN-i1K8Pw-4jybMo-i1rsBr-ouo58Y-ouPRzz-8cGJHK-85Evdk-cru4Ly-rcDWiP-gnaC5B-pAFsuf-hRFPcZ-odvBMz-hRCE7b-mZN3Kt-odHU5a-73dpPp-hUaaAi-owvUMK-otbp7Q-ouySkB-hYAgmJ-owo4UZ-giHgqu-giHpNc-idd9uQ-osAhcf-7vxk63-7vwN65-fQejmk-pTcLgA-otZcmj-fj1aSX-hRzHQk-oyeZfR
[11]:https://github.com/puppetlabs/libral
[12]:https://github.com/puppetlabs/libral
[13]:https://github.com/puppetlabs/libral#building-and-installation
[14]:http://download.augeas.net/libral/ralsh-latest.tgz
[15]:https://github.com/puppetlabs/libral/blob/master/examples/providers/simple.prov
[16]:https://github.com/puppetlabs/libral/blob/master/examples/providers/python.prov
[17]:http://mruby.org/
[18]:http://augeas.net/
[19]:https://github.com/puppetlabs/libral/blob/master/examples/providers/mruby.prov
[20]:http://download.augeas.net/libral/ralsh-latest.tgz
[21]:https://github.com/puppetlabs/libral#todo-list
[22]:https://opensource.com/user/140051/feed
[23]:https://opensource.com/users/david-lutterkort