PowerShell DSC SendReport
背景
PowerShell DSC Pull Server因为证书过期挂了一个月,重新好了,会收到所有已经注册的server(称之为Node,或者Agent)这段时间积累的请求。为啥?问就是By design。
Nginx
然后Nginx 502错误
-
upstream timed out
加大nginx读取updtream的时间
proxy_read_timeout 3600; -
no live upstreams while connecting to upstream
这个本质问题是#1引发的 -
worker_connections are not enough while connecting to upstream
加大worker_connections
events {
worker_connections 20000;
} -
WSARecv() failed (10054: An existing connection was forcibly closed by the remote host) while reading response header from upstream
加大keepalive_requests和对应的keepalive_timeout
keepalive_requests 500;
keepalive_timeout 120s;
格式 和 作用,见:https://nginx.org/en/docs/ (别找错模块了)
逐个修复后,请求还是不断,查看Access log
Nginx Access log
可以看到2个请求每10分钟重试一直发,说明Report是失败了。
模拟Send Report
DSC web services没有开源,不清楚如何访问,只知道HTTP差不多可以访问
这个老哥说想要API
ref:https://github.com/dsccommunity/xPSDesiredStateConfiguration/issues/443
那就看看吧。
Specifies the Desired State Configuration Pull Model Protocol, which is used to get a client's configuration and modules from the server and to report the client's status back to the server. The protocol depends on HTTP for the transfer of all protocol messages.
ref: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-dscpm/ea744c01-51a2-4000-9ef2-312711dcc8c9?redirectedfrom=MSDN
看到没,这是基于HTTP发明个了协议啊, Desired State Configuration Pull Model Protocol。
很快,我们就找到了SendReport的介绍:https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-dscpm/9484a812-d90e-42a8-b4f4-392f2ae1076c
文档写的很好,Demo很到位呀,来,copy...
等等,是不是编码乱了,这特么是啥乱七八糟的...
明察秋毫,下载文档协议文档读读...
打开文档
这个有用的信息,说的描述用的是ABNF语法,看这里:https://tools.ietf.org/search/rfc4234
可以可以,很规范。
高超的英语水平发挥了巨大的作用,终于可以读懂了:
//等号理解为组成
DSC-SendReport-Request = DSC-SendReport-Req-Line DSC-SendReportSetReq-Headers DSC-SendReportReq-Body
//SP 就是空格的意思
DSC-SendReport-Req-Line = "POST" SP Request-URI SP HTTP-Version CRLF
Request-URI = Request-URI-Start DSC-SendReportRequest-URI-End
DSC-SendReportRequest-URI-End = "Node(AgentId=" SQUOTE AgentID SQUOTE RBRACKET FSLASH "SendReport"
//分号就是注释的意思
SQUOTE = %x27 ; ' (Single Quote)
RBRACKET = %x29 ; ) (Closing Bracket)
FSLASH = %x2F ; / (Forward Slash)
AgentID = UUID ; as specified in [RFC4122]
//星号就是一个或多个的意思
//斜杠就是或者的意思
DSC-SendReportSetReq-Headers = *( DSC-SendReportSetReq-Header-REQ
/ DSC-SendReportSetReq-Header-OPT )
DSC-SendReportSetReq-Header-REQ = Host ; section 14.23 of [RFC2616]
/ Accept ; section 14.1 of [RFC2616]
/ ContentType ; section 2.2.2.1.2
/ Content-Length ; section 14.13 of [RFC2616]
DSC-SendReportSetReq-Header-OPT = Connection ; section 14.10 of [RFC2616]
/ Expect ; section 14.20 of [RFC2616]
DSC-SendReportReq-Body = ReportRequest ; section 3.10.5.1.1.1
RequestBody也找到了JSON描述
{
"title": "SendReport request schema",
"type": "object",
"properties": {
"JobId": {
"type": [ "string", "null" ],
"required": "true"
},
"OperationType": {
"type": [ "string", "null" ]
},
"RefreshMode": {
"enum": [ "Push", "Pull" ]
},
"Status": {
"type": [ "string", "null" ]
},
"LCMVersion": {
"type": [ "string", "null" ]
},
"ReportFormatVersion": {
"type": [ "string", "null" ]
},
"ConfigurationVersion": {
"type": [ "string", "null" ]
},
"NodeName": {
"type": [ "string", "null" ]
},
"IpAddress": {
"type": [ "string", "null" ]
},
"StartTime": {
"type": [ "string", "null" ]
},
"EndTime": {
"type": [ "string", "null" ]
},
"RebootRequested": {
"enum": [ "True", "False" ]
},
"Errors": {
"type": [ "string", "null" ]
},
"StatusData": {
"type": [ "string", "null" ]
},
"AdditionalData": {
"type": "array",
"required": false,
"items": [
{
"type": "object",
"required": true,
"properties": {
"Key": {
"type": "string",
"required": true
},
"Value": {
"type": "string",
"required": true
}
}
}
]
}
}
}
好的,有了以上的铺垫,我们就开始发个普通的HTTP请求吧。
按照上面的JSON描述,JobId是必须的,其他字段可以不传入或者为NULL的,可以我只传入JobId的时候,数据库并没有插入任何数据,但是却响应HTTP 200, 还是提示SavedReport。(这不是坑爹呢么?!)
经过我的验证,NodeName设置上之后,就可以成功入库了。
写入成功,读取当然可以直接读数据库,或者写脚本:https://docs.microsoft.com/en-us/powershell/dsc/pull-server/reportserver?view=dsc-1.1#getting-report-data
但凡认真看下这个,GET请求这么发送,POST还要那么复杂的去读协议?