3 个版本
0.16.3 | 2022年6月7日 |
---|---|
0.16.1 | 2022年4月12日 |
0.16.0 | 2022年4月12日 |
#635 in 操作系统
575KB
14K SLoC
目录
- 关于
- 安装方法
- 使用方法
- 可用的 *.pp 检查
- ArgumentLooksSensitive
- ArgumentTyped
- ConstantExpressionInCondition
- DefaultCaseIsNotLast
- DoNotUseUnless
- DoubleNegation
- EmptyCasesList
- EnsureAttributeIsNotTheFirst
- ErbReferencesToUnknownVariable
- ExecAttributes
- ExpressionInSingleQuotes
- FileModeAttributeIsString
- InvalidResourceCollectionInvocation
- InvalidResourceSetInvocation
- InvalidStringEscape
- InvalidVariableAssignment
- LowerCaseArgumentName
- LowerCaseVariable
- MultipleDefaultCase
- MultipleResourcesWithoutDefault
- NegationOfEquation
- NoDefaultCase
- OptionalArgumentsGoesFirst
- PerExpressionResourceDefaults
- ReadableArgumentsName
- ReferenceToUndefinedValue
- RelationToTheLeft
- SelectorInAttributeValue
- SensitiveArgumentWithDefault
- StatementWithNoEffect
- UnconditionalExec
- UniqueArgumentsNames
- UniqueAttributeName
- UnusedVariables
- UpperCaseName
- UselessDoubleQuotes
- UselessParens
- YAML 文件检查器
- Hiera YAML 文件检查器
关于
Shadowplay 是一个检查 puppet 语法、puppet 清单代码检查器、美化打印器以及 Hiera 探索工具的程序。
安装方法
通过 deb/rpm
最新版本可以在此下载:https://github.com/mailru/shadowplay/releases
MaOS 二进制文件
最新 macOS 二进制文件可以在此下载:https://github.com/mailru/shadowplay/releases
通过 cargo
cargo install shadowplay
Guix 清单
Guix 清单尚未合并到主仓库。可以从 Shadowplay 仓库中使用 etc/guix.scm。所有缺失的依赖也包含在清单文件中。
使用方法
YAML 文件的正确性
shadowplay check yaml hieradata/default.yaml [hieradata/another.yaml] ...
除了语法正确性外,还会检查映射中键的唯一性以及链接(锚点)的正确性。
Hiera YAML 文件的有效性
shadowplay check hiera hieradata/default.yaml ...
对于指定的文件,将检查YAML的正确性,以及Puppet类和类参数引用的正确性。例如,如果使用了未知的类参数,将生成错误。
作为副作用,它还会检查Hiera中引用的puppet manifest语法的正确性。
Puppet 清单文件检查器
shadowplay --repo-path ./ check pp modules/hammer/manifests/config.pp ...
指定的文件将由解析器处理,然后应用linter检查(如果解析成功的话)。
美化打印清单文件
shadowplay pretty-print-pp < /path/to/file.pp
配置文件生成器
可能需要禁用一些linter或进行自定义。它可以通过以下命令生成默认配置并在以后进行编辑
shadowplay generate-config >/etc/shadowplay.yaml
Hiera 探索器
Hiera是yaml文件的层次结构。在大型配置中,可能很难确定某些主机特定键的值。Shadowplay提供了一个简单的解决方案。
shadowplay get host123 sshd::install::version
命令尽可能打印出更多信息
Value: "present"
Found in "./hieradata/default_CentOS7.yaml" at lines 63:63
Value lookup path was: network/host123.yaml -> host123.yaml -> host.yaml -> default_CentOS7.yaml
===================================
Git information:
deadbeef1234 (Evgenii Lepikhin 2022-03-29 15:06:51 +0300 63) sshd::install::version: 'present'
*.pp AST 导出器
shadowplay dump modules/sshd/manifests/install.pp
以JSON格式输出AST。主要用于内部目的。
可用的 *.pp 检查
ArgumentLooksSensitive
如果参数名称看起来很敏感,但参数没有用类型Sensitive进行标记,则发出警告
不好
class some::class (
$secret_token,
) { }
好
class some::class (
Sensitive $secret_token,
) { }
ArgumentTyped
如果参数未标记,则发出警告
不好
class some::class (
$config_path,
) { }
好
class some::class (
Stdlib::Absolutepath $config_path,
) { }
ConstantExpressionInCondition
如果条件中使用常量表达式,则发出警告
不好
if 1 == 2 - 1 { notify('1=2-1') }
这种类型的条件总是评估为常量false或true,因此可以安全地删除。好
notify('1=2-1')
DefaultCaseIsNotLast
如果'default'情况不是最后一个,则发出警告
不好
case $value {
'a': { }
default: { }
'b': { }
}
好
case $value {
'a': { }
'b': { }
default: { }
}
DoNotUseUnless
如果使用'unless'条件语句,则发出警告
不好
unless $value { }
好
if !$value { }
DoubleNegation
如果使用双重否定,则发出警告
不好
if !(!$value) { }
if !($value != 1) { }
好
if $value { }
if $value == 1 { }
EmptyCasesList
如果case { … }没有cases,则发出警告
不好
case $value { }
EnsureAttributeIsNotTheFirst
如果资源参数的'ensure'不是第一个,则发出警告
不好
file { '/etc/passwd':
user => root,
ensure => file,
}
好
file { '/etc/passwd':
ensure => file,
user => root,
}
ErbReferencesToUnknownVariable
检查template()中指定的ERB模板中的未定义变量
不好
class some::class () {
# here template_file.erb contains: <% @some_undefined_variable %>
$value = template('some/template_file.erb')
}
ExecAttributes
检查exec { …} 参数
不好
# implicit 'command' attribute
exec { 'echo Hello' : }
exec {
unknown_attribute => 1,
}
# invalid provider
exec {
provider => 'unknown provider value'
}
# 'path' is not set, 'provider' is not 'shell', thus 'command' attribute of exec {} must start with absolute path
exec {
command => 'echo Hello'
}
ExpressionInSingleQuotes
如果找到单引号字符串的插值表达式,则发出警告
不好
$value = 'Hello $world'
$value = '2 + 2 = ${2+2}'
FileModeAttributeIsString
如果'file'资源参数的'mode'不是4位字符串形式,则发出警告
不好
file { '/some/file':
mode => '644',
}
file { '/some/file':
mode => 644,
}
好
file { '/some/file':
mode => '0644',
}
InvalidResourceCollectionInvocation
检查是否使用了现有的资源集,并且在该类中所有参数都是已知的
不好
# relation to unknown resource
Class['unknown_class'] -> Class['known_class']
InvalidResourceSetInvocation
检查是否使用了现有的资源,并且在该类中所有参数都是已知的
不好
class class1 (
$known_arg,
) { }
class class2 {
# Call to unknown class
class { 'unknown_class': }
# Call to known class with invalid argument
class { 'class1':
unknown_arg => 1
}
# Call to known class with invalid argument
class1 { 'title':
unknown_arg => 1,
}
# Call to internal resource with invalid argument
file { '/some/file':
uknown_arg => 1,
}
}
InvalidStringEscape
检查字符串中是否只使用了允许的转义字符
不好
$value = '\s*\.'
$value = "\s*\."
好
$value = '\\s*\\.'
$value = "\\s*\\."
InvalidVariableAssignment
如果赋值号左侧不是变量或变量的数组,则发出警告
不好
lookup('some::value') = 1
LowerCaseArgumentName
如果参数名称不是小写,则根据Puppet的风格指南发出警告
不好
class some::class (
$ArgumentInCamelCase
) {}
LowerCaseVariable
如果变量名称不是小写,则发出警告
不好
class some::class () {
$VariableIsNOTInLowercase = 1
MultipleDefaultCase
如果case语句有多个'default'情况,则发出警告
不好
case $val {
1: {}
default: {}
default: {}
}
MultipleResourcesWithoutDefault
如果资源集包含多个资源且未指定默认值,则发出警告
不好
file {
'/etc/passwd':
ensure => file,
user => root,
'/etc/group':
ensure => file,
user => root,
group => wheel,
}
好
file {
default:
ensure => file,
user => root,
'/etc/passwd':
'/etc/group':
group => wheel,
}
NegationOfEquation
如果否定方程式,则发出警告
不好
if !($a == 1) { }
if !($a =~ /./) { }
好
if $a != 1 { }
if $a !~ /./ { }
NoDefaultCase
如果case语句没有默认情况,则发出警告
不好
case $val {
1, 2: { }
3: { }
}
好
case $val {
1, 2: { }
3: { }
default: { }
}
OptionalArgumentsGoesFirst
如果将可选参数指定在必需参数之前,则发出警告
class some::class (
$optional_arg = 1,
$required_arg,
) { }
好
class some::class (
$required_arg,
$optional_arg = 1,
) { }
PerExpressionResourceDefaults
如果使用局部资源默认值,则发出警告
不好
Exec {
provider => shell,
}
exec { 'run command':
command => 'echo Hello',
}
ReadableArgumentsName
如果参数名称不够可读,则发出警告
不好
class some::class (
String $c = '/etc/config',
) { }
好
class some::class (
String $config = '/etc/config',
) { }
ReferenceToUndefinedValue
如果变量在当前上下文中未定义,则发出警告
不好
if $some_undefined_variable { }
RelationToTheLeft
检查左向关系
不好
Class['c'] <- Class['b'] <~ Class['a']
好
Class['a'] ~> Class['b'] -> Class['c']
SelectorInAttributeValue
如果资源属性中使用选择器(… ? … : …),则发出警告
不好
file { '/etc/shadow':
mode => $is_secure ? '0600' : '0644',
}
好
$file_mode = $is_secure ? '0600' : '0644'
file { '/etc/shadow':
mode => $file_mode,
}
SensitiveArgumentWithDefault
如果使用类型Sensitive标记的参数包含默认值,则发出警告
不好
class some::class (
Sensitive $password = 'admin',
)
敏感数据的公共可用默认值是没有意义的。好
class some::class (
Sensitive $password,
)
StatementWithNoEffect
检查无副作用的语句
不好
if $a {
if $b {
2 + 2
}
}
UnconditionalExec
如果没有指定unless、onlyif、creates或refreshonly属性,则发出警告exec { … }
不好
exec { 'run command':
command => '/bin/rm -rf /var/cache/myapp',
}
好
exec { 'run command':
command => '/bin/rm -rf /var/cache/myapp',
onlyif => 'test -e /var/cache/myapp',
}
UniqueArgumentsNames
检查类/定义/计划参数的唯一性
不好
class some::class (
$arg,
$arg,
$arg,
) { }
UniqueAttributeName
资源属性必须是唯一的
不好
service { 'sshd':
ensure => running,
ensure => stopped,
}
UnusedVariables
检查未使用的变量。实验性lint假阳性是可能的。
不好
class some::class (
$unused_argument,
) {
service { 'sshd':
ensure => running,
}
}
UpperCaseName
如果使用大写字母使用资源集,则发出警告
不好
Service { 'sshd':
ensure => running,
}
好
service { 'sshd':
ensure => running,
}
UselessDoubleQuotes
如果双引号字符串没有插值表达式和转义的单引号,则发出警告
不好
$var = "simple literal"
好
$var = 'simple literal'
UselessParens
检查多余的括号
不好
if (($var1) or ($var2)) { }
好
if $var1 or $var2 { }
YAML 文件检查器
实现了一些基本的检查
- 文件不可执行
- 文件为空(没有根值可用)
- 文件解析没有语法错误
- 映射不包含重复的键
- 尝试合并类型不是数组或映射的锚点
Hiera YAML 文件检查器
所有YAML文件的lints加上
有语法错误的模块引用
如果某些class无法解析,linter将失败
some_class::argument: 1
未在 modules/ 中找到的类引用
如果modules/someclass/init.pp不存在,linter将失败
some_class::argument: 1
未定义类参数中的引用
如果某些class不接受参数$argumentname,linter将失败
some_class::argument_name: 1
根映射键名的单列
Linter可以防止像
some_class:argument_name: 1
依赖项
~7–17MB
~215K SLoC