本教程演示了Salt中可用的各种HTTP模块。 这些模块包装Python tornado
,urllib2
和requests
库,使用与Salt工作流更一致的方式扩展它们。
您也可以参考在Github上维护的这一份技术资料:HTTP Modules
文章目录
The salt.utils.http
Library
该库构成了HTTP模块的核心。 由于它被设计为在minion上用作执行模块,除了可以作为master的runner之外,还被抽象到该多用途库中。 希望利用其扩展功能的第三方程序也可以导入该库。
执行、状态和运行程序模块的核心功能是从该库派生的,因此此处介绍了它们之间的常见用法。 每个模块的特定文档如下所述。
该库可以通过以下方式导入:
import salt.utils.http
Configuring Libraries - 基础类库配置
该库可以使用Salt所需的tornado
,Python附带的urllib2
或可以单独安装的requests
。 默认情况下,将使用tornado
。 为了切换到urllib2
,需设置以下变量:
backend: urllib2
切换为使用 requests
, 则需要设置以下变量:
backend: requests
可以在master配置文件或minion配置文件中进行设置,也可以将其作为选项直接传递给任何http.query()
函数。
salt.utils.http.query()
该函数构成一个基本查询,但是有些组件在tornado、urllib2和requests库中不存在。 尚未添加这些库中当前可用的所有功能,但可以在将来的迭代中添加。
HTTPS Request Methods
可以通过一个URL调用此函数来执行基本查询:
salt.utils.http.query('http://example.com')
默认情况下,查询将使用GET
方法执行。 可以使用method
参数覆盖该方法:
salt.utils.http.query('http://example.com/delete/url', 'DELETE')
使用POST
方法(以及其他方法,例如PUT
)时,通常也会发送额外的数据。 该数据可以直接发送(必要时将进行URL编码),或以远程服务器要求的任何格式(XML,JSON,纯文本等)发送。
salt.utils.http.query(
'http://example.com/post/url',
method='POST',
data=json.dumps(mydict)
)
Data Formatting and Templating - 数据格式化与使用模板
请记住,数据必须预先格式化后再发送; 此功能函数不会为您格式化。 但是,可以将存储在本地系统上的模板化文件以及变量进行传递。
仅传递数据文件(非模板):
salt.utils.http.query(
'http://example.com/post/url',
method='POST',
data_file='/srv/salt/somefile.xml'
)
传递一个包含了 jinja + yaml 模板配置的数据文件 (这也是函数的默认设置):
salt.utils.http.query(
'http://example.com/post/url',
method='POST',
data_file='/srv/salt/somefile.jinja',
data_render=True,
template_dict={'key1': 'value1', 'key2': 'value2'}
)
传递一个包含 mako 模板配置的数据文件:
salt.utils.http.query(
'http://example.com/post/url',
method='POST',
data_file='/srv/salt/somefile.mako',
data_render=True,
data_renderer='mako',
template_dict={'key1': 'value1', 'key2': 'value2'}
)
由于此功能使用Salt自己的渲染系统,因此可以使用任何Salt渲染器。 因为Salt的渲染器需要设置__opts__
,所以应该传入opts
字典。如果未设置,则将使用节点类型(master节点或minion节点)的默认__opts__
值。 由于此库主要供minions使用,因此默认节点类型为minion
。 但是,如有必要,可以将其更改为master
。
salt.utils.http.query(
'http://example.com/post/url',
method='POST',
data_file='/srv/salt/somefile.jinja',
data_render=True,
template_dict={'key1': 'value1', 'key2': 'value2'},
opts=__opts__
)
salt.utils.http.query(
'http://example.com/post/url',
method='POST',
data_file='/srv/salt/somefile.jinja',
data_render=True,
template_dict={'key1': 'value1', 'key2': 'value2'},
node='master'
)
Headers
Headers也可以作为header_list
、header_dict
或header_file
传递。 与data_file
一样,header_file
也可以被模板化。 请注意,由于HTTP headers通常是语法正确的YAML,因此它们会自动作为Python字典导入。
salt.utils.http.query(
'http://example.com/delete/url',
method='POST',
header_file='/srv/salt/headers.jinja',
header_render=True,
header_renderer='jinja',
template_dict={'key1': 'value1', 'key2': 'value2'}
)
因为要在headers和数据之间模板化的许多数据可能是相同的,所以两者的template_dict是相同的。 纠正可能的变量名冲突由用户自行负责。
Authentication
query()
函数支持基本的HTTP身份验证。 用户名和密码可以分别作为username
和 password
传递。
salt.utils.http.query(
'http://example.com',
username='larry',
password=`5700g3543v4r`,
)
Cookies and Sessions
使用Python的内置cookielib
也支持使用cookie。 但是,它们默认情况下处于关闭状态。 要打开cookie,请将cookie
设置为True
。
salt.utils.http.query(
'http://example.com',
cookies=True
)
默认情况下,cookies作为名为cookies.txt
的文件存储在Salt的缓存目录中,通常为/var/cache/salt
。 但是,可以使用cookie_jar
参数更改此位置:
salt.utils.http.query(
'http://example.com',
cookies=True,
cookie_jar='/path/to/cookie_jar.txt'
)
默认情况下,cookie jar的格式为LWP(aka,lib-www-perl)。 选择该默认值是因为它是易于直接阅读的文本文件。 如果需要,可以将cookie jar的格式设置为Mozilla:
salt.utils.http.query(
'http://example.com',
cookies=True,
cookie_jar='/path/to/cookie_jar.txt',
cookie_format='mozilla'
)
因为Salt命令通常是一次性的命令,这些命令通过管道传递连接在一起,所以该库通常不能像普通浏览器那样运行,因为会话cookie会在多个HTTP请求中持续存在。 但是,可以将会话保留在单独的Cookie jar中。 在Salt的缓存目录中,此文件的默认文件名是cookies.session.p
。 这也可以更改。
salt.utils.http.query(
'http://example.com',
persist_session=True,
session_cookie_jar='/path/to/jar.p'
)
该文件的格式为msgpack,与Salt的其他大部分内部结构一致。 从历史上看,此文件的扩展名是.p
。 当前没有计划使它可配置。
Proxy
如果使用tornado
后端(默认值),则将使用__opts__
字典中proxy_host、proxy_port、proxy_username、proxy_password
和no_proxy
中配置的代理信息。 通常,这些是在minion配置文件中设置的。
proxy_host: proxy.my-domain
proxy_port: 31337
proxy_username: charon
proxy_password: obolus
no_proxy: ['127.0.0.1', 'localhost']
salt.utils.http.query(
'http://example.com',
opts=__opts__,
backend='tornado'
)
Return Data - 返回数据
注意:返回数据的编码设置
如果
decode
设置为True
,则query()
将尝试解码返回数据。decode_type
默认为auto
。 可以将其设置为特定的编码,例如xml
,以覆盖自动检测。
因为Salt的http库被设计为与REST接口一起使用,所以当decode
设置为True
时,query()
将尝试对从远程服务器接收的数据进行解码。 首先,它将检查Content-type
header以尝试查找对XML的引用。 如果找不到任何内容,它将查找对JSON的引用。 如果找不到,它将退回到纯文本格式,不会被解码。
使用Python的内置json
库将JSON数据转换为字典。 使用salt.utils.xml_util
转换XML,该脚本将使用Python的内置XML库来尝试将XML转换为dict。 为了强制进行JSON或XML解码,可以设置decode_type
:
salt.utils.http.query(
'http://example.com',
decode_type='xml'
)
经过数据格式转换后,query()
的返回字典将包含一个称为dict
的字典。
如果不使用以上这些方法之一转换数据,则可以关闭解码功能。
salt.utils.http.query(
'http://example.com',
decode=False
)
如果打开了解码功能,并且找不到对JSON或XML的引用,则此模块将默认为使用纯文本,并以文本形式返回未解码的数据(即使将text设置为False,请参见下文)。
query()
函数可以根据需要返回HTTP状态代码,headers和/或文本数据。 但是,需要每个功能控制项都必须单独打开。
salt.utils.http.query(
'http://example.com',
status=True,
headers=True,
text=True
)
这些返回的内容将在返回字典中分别以status
, headers
和 text
的形式显示。
WRITING RETURN DATA TO FILES - 将返回数据写入文件
一旦从服务器接收到响应,就可以将返回数据或headers写入文件,可以通过text_out
或headers_out
参数指定文件位置。 文本数据和headrs无需再返回给用户,直接写入指定的文件即可。
salt.utils.http.query(
'http://example.com',
text=False,
headers=False,
text_out='/path/to/url_download.txt',
headers_out='/path/to/headers_download.txt',
)
SSL Verification
默认情况下,此功能将验证SSL证书。 但是,出于测试或调试目的,可以关闭SSL验证。
salt.utils.http.query(
'https://example.com',
verify_ssl=False,
)
CA Bundles
requests
库具有自己的检测使用哪个CA(证书颁发机构)捆绑证书文件的方法。 通常,这是由打包程序针对您正在使用的特定操作系统发行版实现的。 但是,urllib2
需要做更多的工作。 默认情况下,Salt将尝试自动检测此文件的位置。 但是,如果它不在预期的位置,或者需要指定其他路径,则可以使用ca_bundle
变量来完成。
salt.utils.http.query(
'https://example.com',
ca_bundle='/path/to/ca_bundle.pem',
)
Updating CA Bundles
update_ca_bundle()
函数可用于在指定位置更新证书捆绑文件。 如果未指定目标位置,则它将尝试自动检测捆绑文件的位置。 如果不存在用于下载捆绑软件的URL,则将从cURL网站下载捆绑软件。
注意:应始终指定target和source! 未指定目标可能会导致文件写入本地系统上的错误位置。 不指定来源可能会导致上游URL接收到多余的不必要流量,并可能导致危险或不满足用户需求的文件下载。
salt.utils.http.update_ca_bundle(
target='/path/to/ca-bundle.crt',
source='https://example.com/path/to/ca-bundle.crt',
opts=__opts__,
)
还应该始终指定opts
参数。 如果是,则还有一种替代方法是target
和source
可以在相关的配置文件(master服务器或minion服务器)中分别指定为ca_bundle
和ca_bundle_url
。
ca_bundle: /path/to/ca-bundle.crt
ca_bundle_url: https://example.com/path/to/ca-bundle.crt
如果Salt无法自动检测CA证书捆绑包的位置,则会引发错误。
还可以向update_ca_bundle()
函数传递表示本地系统上文件的字符串或字符串列表,这些字符串或字符串列表应(按指定顺序)附加到CA bundle文件的末尾。 这在需要提供私有证书的环境中很有用,并且在其他情况下将其添加到捆绑文件中是不合理的。
salt.utils.http.update_ca_bundle(
opts=__opts__,
merge_files=[
'/etc/ssl/private_cert_1.pem',
'/etc/ssl/private_cert_2.pem',
'/etc/ssl/private_cert_3.pem',
]
)
Test Mode
此功能可以在测试模式下运行。此模式将执行所有工作,直到实际的HTTP请求为止。默认情况下,不执行请求,而是返回空dict。在TRACE
日志记录已打开的情况下使用此功能将显示标头的内容和要发送的POST数据。
可能会传入一个替代的test_url
,而不是返回一个空的dict。如果检测到此错误,则测试模式将用test_url
替换该url
,在返回数据中将test
设置为True
,并照常执行其余请求的操作。这允许在必要时使用自定义的非破坏性URL进行测试。
EXECUTION MODULE - 执行模块
http
执行模块是salt.utils.http
库的一个非常轻的包装。 opt
也可以传递使用,但如果未指定,则将在必要时使用默认选项。
因为从命令行传递完整的数据结构是比较棘手的,而在发生执行注入攻击方面也很危险,所以data_file
和header_file
在这里可能会得到更多使用。
该库的所有方法在执行模块中都可用,如kwargs。
salt myminion http.query http://example.com/restapi method=POST \
username='larry' password='5700g3543v4r' headers=True text=True \
status=True decode_type=xml data_render=True \
header_file=/tmp/headers.txt data_file=/tmp/data.txt \
header_render=True cookies=True persist_session=True
Runner Module - 运行器模块
类似于执行模块,http
runner程序模块也是salt.utils.http
库的一个非常轻的包装。 唯一的显著差异是,因为runners
是在master服务器上执行而不是在minions上执行,所以不需要目标参数,并且默认选项将从master配置而不是从Minion配置中派生。
该库的所有方法都可以在runner
程序模块中使用,如kwargs。
salt-run http.query http://example.com/restapi method=POST \
username='larry' password='5700g3543v4r' headers=True text=True \
status=True decode_type=xml data_render=True \
header_file=/tmp/headers.txt data_file=/tmp/data.txt \
header_render=True cookies=True persist_session=True
State Module - 状态模块
http
状态模块是runner
程序模块的一个包装器,该模块将状态逻辑应用于查询。 上面列出的所有kwargs
通常是在状态文件中指定,但是还有两个kwargs
可用于应用有状态逻辑。 必需的参数是match
,该参数指定要在返回文本中匹配查找的模式。 默认情况下,这将执行字符串比较,以在返回文本中符合匹配查找match
的值。 用Python 伪代码描述时看起来像这样:
if match in html_text:
return True
如果需要更复杂的模式匹配,则可以通过指定match_type
来使用正则表达式。 默认情况下,它设置为string
,但是可以手动将其设置为pcre
。 请注意,尽管名称相似,但它仍将使用Python的re.search()
而不是re.match()
。
因此,以下状态是有效的:
http://example.com/restapi:
http.query:
- match: 'SUCCESS'
- username: 'larry'
- password: '5700g3543v4r'
- data_render: True
- header_file: /tmp/headers.txt
- data_file: /tmp/data.txt
- header_render: True
- cookies: True
- persist_session: True
http://example.com/restapi:
http.query:
- match_type: pcre
- match: '(?i)succe[ss|ed]'
- username: 'larry'
- password: '5700g3543v4r'
- data_render: True
- header_file: /tmp/headers.txt
- data_file: /tmp/data.txt
- header_render: True
- cookies: True
- persist_session: True
除匹配模式外,还可以使用其它代替匹配模式,如检查URL的状态码。 这是使用status
参数完成的:
http://example.com/:
http.query:
- status: '200'
如果同时指定了两者,则将同时检查两者,但是如果只有一个值为True
,另一个为False
,则将返回False
。 在这种情况下,返回数据中的注释将包含故障排除信息。
因为这是一个服务监视的状态定义,所以它将额外的数据返回到期望它的代码中。 此数据将始终包含text
和status
。 可选地,还可以通过分别将headers
和decode
参数设置为True来请求headers
和dict
。