diff --git a/Dockerfile b/Dockerfile index 2b58b35..a0ac7da 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,11 +1,17 @@ +FROM golang:1.22-bullseye AS Builder +ENV GOPROXY=https://goproxy.cn +ENV CGO_ENABLED=0 +WORKDIR /app +RUN apt-get update && \ + apt-get install -y git && \ + git clone https://github.com/soulteary/webhook.git && \ + cd webhook && \ + go mod download -x && \ + go build -ldflags "-w -s" -o webhook . + FROM debian:stable-slim WORKDIR /app -RUN apt-get update && apt-get install -y --no-install-recommends \ - ca-certificates \ - netbase \ - && rm -rf /var/lib/apt/lists/ \ - && apt-get autoremove -y && apt-get autoclean -y -ADD webhook . +COPY --from=Builder /app/webhook/webhook . -CMD ["./webhook"] \ No newline at end of file +CMD ["./webhook"] diff --git a/README.md b/README.md index 5c73f1a..8bfe337 100644 --- a/README.md +++ b/README.md @@ -28,5 +28,5 @@ curl "http://127.0.0.1:8002/hooks/suno_recharge?env=prod&&account=account_1&&amo 有消息通知时,会把消息中的message字段发送到飞书群中 #### hwtlsupdate -需要事先配置acme.sh,生成域名证书,然后配置到华为云-网络控制台-弹性负载均衡-证书管理中,并获取证书id +需要事先配置acme.sh,生成域名证书,然后后配置到华为云-网络控制台-弹性负载均衡-证书管理中,并获取证书id acme.sh自动更新证书时,会请求相应webhook地址,更新华为云中配置的证书。 diff --git a/config/hooks.yaml b/config/hooks.yaml index 31cdaf9..68fccc4 100644 --- a/config/hooks.yaml +++ b/config/hooks.yaml @@ -13,7 +13,7 @@ name: -a - source: url name: account - +# 华为消息通知 - id: hwsmn execute-command: "/etc/webhook/scripts/hwsmn/hwsmn" http-methods: @@ -24,8 +24,9 @@ - source: payload name: message +# 华为tls更新(自建证书) - id: hwtlsupdate - execute-command: "/etc/webhook/scripts/tlsupdatev1/tlsupdate" + execute-command: "/etc/webhook/scripts/tlsupdate/tlsupdate" pass-arguments-to-command: - source: string name: -a @@ -35,3 +36,27 @@ name: -i - source: url name: id +- id: jenkins_notify + execute-command: "/etc/webhook/scripts/notify/notify" + http-methods: + - "POST " + pass-arguments-to-command: + - source: string + name: -m + - source: payload + name: message + - source: string + name: -t + - source: payload + name: title + pass-file-to-command: + - source: payload + name: message + envname: MSG + - source: payload + name: title + envname: TITLE + - source: payload + envname: FILE + name: file + base64decode: true \ No newline at end of file diff --git a/scripts/notify/Readme.md b/scripts/notify/Readme.md new file mode 100644 index 0000000..e46055b --- /dev/null +++ b/scripts/notify/Readme.md @@ -0,0 +1,13 @@ +## 目的 +jenkins通知 + +## 使用方法 +```shell +## post可以是json格式字符串,也可以是某个json文件(如: test.json)。 +# 但必须包含title和message字段,file字段可选(带有file字段时,会发送一个带有url的富文本到飞书机器人,提供下载或在线查看 ,文件会推送到cf的r2) +# 举例如下: +# json 格式 +curl -XPOST -H "Content-Type: application/json" -d "{\"title\": \"测试环境\",\"message\": \"xxx更新完成\"}" https://webhook-ops.shasoapp.com/hooks/jenkins_notify +# json文件 +curl -XPOST -H "Content-Type: application/json" -d "@test.json" https://webhook-ops.shasoapp.com/hooks/jenkins_notify +``` \ No newline at end of file diff --git a/scripts/notify/config.yaml b/scripts/notify/config.yaml new file mode 100644 index 0000000..71d2af9 --- /dev/null +++ b/scripts/notify/config.yaml @@ -0,0 +1,10 @@ +notify: https://open.feishu.cn/open-apis/bot/v2/hook/051679ae-0bef-4a21-9ff7-25fd76cd73ee +s3: + ak: e56bc411d8236f9544fd25b64ab35a1d + sk: 4b635dea4d61a6285f1c435a0b8fb3d82ef6584c0d76470f56f10463f26ee4cc + endpoint: https://cb4d11ce7f16246f032ec12655e49b77.r2.cloudflarestorage.com + bucket: turingsyn-autotest + path: jenkins/autotest + public_url: https://autotest.turingsynimages.work + +type: html \ No newline at end of file diff --git a/scripts/notify/consts.go b/scripts/notify/consts.go new file mode 100644 index 0000000..5681655 --- /dev/null +++ b/scripts/notify/consts.go @@ -0,0 +1,38 @@ +package main + +type FeishuPostMessage struct { + MsgType string `json:"msg_type"` + Content PostContent `json:"content"` +} + +type PostContent struct { + Post Post `json:"post"` +} + +type Post struct { + ZhCn Message `json:"zh_cn"` +} + +type Message struct { + Title string `json:"title"` + Content [][]ContentItem `json:"content"` +} + +type ContentItem struct { + Tag string `json:"tag"` + Text string `json:"text,omitempty"` + Unescape bool `json:"un_escape,omitempty"` + Href string `json:"href,omitempty"` + UserID string `json:"user_id,omitempty"` + UserName *string `json:"user_name,omitempty"` + ImageKey string `json:"image_key,omitempty"` +} + +type FeishuTextMessage struct { + MsgType string `json:"msg_type"` + Content TextContent `json:"content"` +} + +type TextContent struct { + Text string `json:"text"` +} diff --git a/scripts/notify/go.mod b/scripts/notify/go.mod new file mode 100644 index 0000000..ae1df07 --- /dev/null +++ b/scripts/notify/go.mod @@ -0,0 +1,48 @@ +module notify + +go 1.21.1 + +require ( + github.com/aws/aws-sdk-go-v2 v1.30.3 + github.com/aws/aws-sdk-go-v2/config v1.27.27 + github.com/aws/aws-sdk-go-v2/credentials v1.17.27 + github.com/aws/aws-sdk-go-v2/service/s3 v1.58.3 + github.com/spf13/cobra v1.8.1 + github.com/spf13/viper v1.19.0 +) + +require ( + github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect + github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.15 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.17 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.15 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.22.4 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.30.3 // indirect + github.com/aws/smithy-go v1.20.4 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/magiconair/properties v1.8.7 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/pelletier/go-toml/v2 v2.2.2 // indirect + github.com/sagikazarmark/locafero v0.6.0 // indirect + github.com/sagikazarmark/slog-shim v0.1.0 // indirect + github.com/sourcegraph/conc v0.3.0 // indirect + github.com/spf13/afero v1.11.0 // indirect + github.com/spf13/cast v1.7.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/subosito/gotenv v1.6.0 // indirect + go.uber.org/multierr v1.11.0 // indirect + golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa // indirect + golang.org/x/sys v0.24.0 // indirect + golang.org/x/text v0.17.0 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/scripts/notify/go.sum b/scripts/notify/go.sum new file mode 100644 index 0000000..7bd55db --- /dev/null +++ b/scripts/notify/go.sum @@ -0,0 +1,110 @@ +github.com/aws/aws-sdk-go-v2 v1.30.3 h1:jUeBtG0Ih+ZIFH0F4UkmL9w3cSpaMv9tYYDbzILP8dY= +github.com/aws/aws-sdk-go-v2 v1.30.3/go.mod h1:nIQjQVp5sfpQcTc9mPSr1B0PaWK5ByX9MOoDadSN4lc= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3 h1:tW1/Rkad38LA15X4UQtjXZXNKsCgkshC3EbmcUmghTg= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3/go.mod h1:UbnqO+zjqk3uIt9yCACHJ9IVNhyhOCnYk8yA19SAWrM= +github.com/aws/aws-sdk-go-v2/config v1.27.27 h1:HdqgGt1OAP0HkEDDShEl0oSYa9ZZBSOmKpdpsDMdO90= +github.com/aws/aws-sdk-go-v2/config v1.27.27/go.mod h1:MVYamCg76dFNINkZFu4n4RjDixhVr51HLj4ErWzrVwg= +github.com/aws/aws-sdk-go-v2/credentials v1.17.27 h1:2raNba6gr2IfA0eqqiP2XiQ0UVOpGPgDSi0I9iAP+UI= +github.com/aws/aws-sdk-go-v2/credentials v1.17.27/go.mod h1:gniiwbGahQByxan6YjQUMcW4Aov6bLC3m+evgcoN4r4= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11 h1:KreluoV8FZDEtI6Co2xuNk/UqI9iwMrOx/87PBNIKqw= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11/go.mod h1:SeSUYBLsMYFoRvHE0Tjvn7kbxaUhl75CJi1sbfhMxkU= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15 h1:SoNJ4RlFEQEbtDcCEt+QG56MY4fm4W8rYirAmq+/DdU= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15/go.mod h1:U9ke74k1n2bf+RIgoX1SXFed1HLs51OgUSs+Ph0KJP8= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15 h1:C6WHdGnTDIYETAm5iErQUiVNsclNx9qbJVPIt03B6bI= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15/go.mod h1:ZQLZqhcu+JhSrA9/NXRm8SkDvsycE+JkV3WGY41e+IM= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.15 h1:Z5r7SycxmSllHYmaAZPpmN8GviDrSGhMS6bldqtXZPw= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.15/go.mod h1:CetW7bDE00QoGEmPUoZuRog07SGVAUVW6LFpNP0YfIg= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3 h1:dT3MqvGhSoaIhRseqw2I0yH81l7wiR2vjs57O51EAm8= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3/go.mod h1:GlAeCkHwugxdHaueRr4nhPuY+WW+gR8UjlcqzPr1SPI= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.17 h1:YPYe6ZmvUfDDDELqEKtAd6bo8zxhkm+XEFEzQisqUIE= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.17/go.mod h1:oBtcnYua/CgzCWYN7NZ5j7PotFDaFSUjCYVTtfyn7vw= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17 h1:HGErhhrxZlQ044RiM+WdoZxp0p+EGM62y3L6pwA4olE= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17/go.mod h1:RkZEx4l0EHYDJpWppMJ3nD9wZJAa8/0lq9aVC+r2UII= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.15 h1:246A4lSTXWJw/rmlQI+TT2OcqeDMKBdyjEQrafMaQdA= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.15/go.mod h1:haVfg3761/WF7YPuJOER2MP0k4UAXyHaLclKXB6usDg= +github.com/aws/aws-sdk-go-v2/service/s3 v1.58.3 h1:hT8ZAZRIfqBqHbzKTII+CIiY8G2oC9OpLedkZ51DWl8= +github.com/aws/aws-sdk-go-v2/service/s3 v1.58.3/go.mod h1:Lcxzg5rojyVPU/0eFwLtcyTaek/6Mtic5B1gJo7e/zE= +github.com/aws/aws-sdk-go-v2/service/sso v1.22.4 h1:BXx0ZIxvrJdSgSvKTZ+yRBeSqqgPM89VPlulEcl37tM= +github.com/aws/aws-sdk-go-v2/service/sso v1.22.4/go.mod h1:ooyCOXjvJEsUw7x+ZDHeISPMhtwI3ZCB7ggFMcFfWLU= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4 h1:yiwVzJW2ZxZTurVbYWA7QOrAaCYQR72t0wrSBfoesUE= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4/go.mod h1:0oxfLkpz3rQ/CHlx5hB7H69YUpFiI1tql6Q6Ne+1bCw= +github.com/aws/aws-sdk-go-v2/service/sts v1.30.3 h1:ZsDKRLXGWHk8WdtyYMoGNO7bTudrvuKpDKgMVRlepGE= +github.com/aws/aws-sdk-go-v2/service/sts v1.30.3/go.mod h1:zwySh8fpFyXp9yOr/KVzxOl8SRqgf/IDw5aUt9UKFcQ= +github.com/aws/smithy-go v1.20.4 h1:2HK1zBdPgRbjFOHlfeQZfpC4r72MOb9bZkiFwggKO+4= +github.com/aws/smithy-go v1.20.4/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= +github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sagikazarmark/locafero v0.6.0 h1:ON7AQg37yzcRPU69mt7gwhFEBwxI6P9T4Qu3N51bwOk= +github.com/sagikazarmark/locafero v0.6.0/go.mod h1:77OmuIc6VTraTXKXIs/uvUxKGUXjE1GbemJYHqdNjX0= +github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= +github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= +github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= +github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= +github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w= +github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= +github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= +github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa h1:ELnwvuAXPNtPk1TJRuGkI9fDTwym6AYBu0qzT8AcHdI= +golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ= +golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= +golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= +golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/scripts/notify/main.go b/scripts/notify/main.go new file mode 100644 index 0000000..19b9d0b --- /dev/null +++ b/scripts/notify/main.go @@ -0,0 +1,241 @@ +package main + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "net/http" + "os" + "path/filepath" + "strings" + "time" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/credentials" + "github.com/aws/aws-sdk-go-v2/service/s3" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +var ( + cfgFile string + title string + msg string + file string + notice bool = false +) + +var rootCmd = &cobra.Command{ + Use: "notify", + Short: "notify by jenkins", + Run: func(cmd *cobra.Command, args []string) { + // 如果配置文件存在,则读取配置文件 + if cfgFile != "" { + viper.SetConfigFile(cfgFile) + if err := viper.ReadInConfig(); err != nil { + fmt.Println("Error reading config file:", err) + os.Exit(1) + } + } + + // 获取配置 + ak := viper.GetString("s3.ak") + sk := viper.GetString("s3.sk") + notify := viper.GetString("notify") + s3_endpoint := viper.GetString("s3.endpoint") + s3_bucket := viper.GetString("s3.bucket") + s3_path := viper.GetString("s3.path") + s3_public_url := viper.GetString("s3.public_url") + + file_type := viper.GetString("type") + + FILE := os.Getenv("FILE") + flist := strings.Split(FILE, "/") + f := fmt.Sprintf("%s.%s", flist[len(flist)-1], file_type) + + if title == "" { + if os.Getenv("TITLE") != "" { + title, _ = readFile(os.Getenv("TITLE")) + } else { + title = "获取不到title或环境变量TITLE" + } + } + if msg == "" { + if os.Getenv("MSG") != "" { + msg, _ = readFile(os.Getenv("MSG")) + } else { + msg = "获取不到msg或环境变量MSG" + } + } + + // 如果配置文件中提供飞书链接,则通知用户 + if notify != "" { + // 是否通知 + notice = true + } + //发送用户格式,默认是text文本 + post := false + // 富文本中的链接 + postUrl := "" + + if FILE != "" { + post = true + input_key := fmt.Sprintf("%s/%s/%s", s3_path, time.Now().Format("201601021504"), f) + objectUrl, err := s3PutObject(ak, sk, s3_endpoint, s3_bucket, input_key, FILE, s3_public_url) + if err != nil { + fmt.Println("Error sending message:", err) + os.Exit(1) + } + postUrl = objectUrl + } + + if notice { + var data interface{} + if post { + data = genPostAMsg(title, msg, "查看", postUrl) + + } else { + data = FeishuTextMessage{ + MsgType: "text", + Content: TextContent{ + Text: fmt.Sprintf("%s\n%s", title, msg), + }, + } + + } + if err := postRequest(notify, data); err != nil { + fmt.Println("Error sending message:", err) + os.Exit(1) + } + + } + + }, +} + +func main() { + cobra.OnInitialize(initConfig) + rootCmd.Flags().StringVarP(&cfgFile, "config", "c", "", "Config file (default is $HOME/config.yaml and ./config.yaml)") + rootCmd.Flags().StringVarP(&title, "title", "t", "", "title") + rootCmd.Flags().StringVarP(&msg, "msg", "m", "", "message") + rootCmd.Flags().StringVarP(&file, "file", "f", "", "file") + + if err := rootCmd.Execute(); err != nil { + fmt.Println(err) + os.Exit(1) + } +} + +func initConfig() { + if cfgFile != "" { + viper.SetConfigFile(cfgFile) + } else { + home, err := os.UserHomeDir() + if err != nil { + fmt.Println(err) + os.Exit(1) + } + exec, err := os.Executable() + if err != nil { + fmt.Println(err) + os.Exit(1) + } + exPath := filepath.Dir(exec) + viper.AddConfigPath(".") + viper.AddConfigPath(home) + viper.AddConfigPath(exPath) + viper.SetConfigName("config") + } + + viper.AutomaticEnv() // 从环境变量中读取配置 + if err := viper.ReadInConfig(); err == nil { + fmt.Println("Using config file:", viper.ConfigFileUsed()) + } +} + +func postRequest(url string, data interface{}) error { + jsonData, err := json.Marshal(data) + if err != nil { + return err + } + fmt.Printf("post data: %s\n", string(jsonData)) + resp, err := http.Post(url, "application/json", bytes.NewBuffer(jsonData)) + if err != nil { + return err + } + defer resp.Body.Close() + + fmt.Printf("Response status: %d\n", resp.StatusCode) + + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("HTTP status code: %d", resp.StatusCode) + } + return nil +} + +func genPostAMsg(title, message, text, url string) *FeishuPostMessage { + return &FeishuPostMessage{ + MsgType: "post", + Content: PostContent{ + Post: Post{ + ZhCn: Message{ + Title: title, + Content: [][]ContentItem{ + { + { + Tag: "text", + Text: message, + }, + { + Tag: "a", + Text: text, + Href: url, + }, + }, + }, + }, + }, + }, + } +} + +func s3PutObject(ak, sk, endpoint, bucket, inputKey, filePath, url string) (string, error) { + cfg, err := config.LoadDefaultConfig(context.TODO(), + + config.WithCredentialsProvider(credentials.NewStaticCredentialsProvider(ak, sk, "")), + config.WithRegion("auto"), + ) + if err != nil { + return "", err + } + client := s3.NewFromConfig(cfg, func(o *s3.Options) { + o.BaseEndpoint = aws.String(endpoint) + }) + + fd, err := os.Open(filePath) + if err != nil { + return "", err + } + defer fd.Close() + + _, err = client.PutObject(context.TODO(), &s3.PutObjectInput{ + Bucket: aws.String(bucket), + Key: aws.String(inputKey), + Body: fd, + ContentType: aws.String("text/html; charset=utf-8"), + }) + if err == nil { + return fmt.Sprintf("%s/%s", url, inputKey), err + } + return "", err +} + +func readFile(path string) (string, error) { + data, err := os.ReadFile(path) + if err != nil { + return "", err + } + return string(data), nil +} diff --git a/scripts/tlsupdate/Readme.md b/scripts/tlsupdate/Readme.md index 7f3ce11..5560beb 100644 --- a/scripts/tlsupdate/Readme.md +++ b/scripts/tlsupdate/Readme.md @@ -1,3 +1,4 @@ +# 更新或安装证书 ## 安装acme.sh,并使用dns方式生成证书 ```shell # 安装acme.sh @@ -21,3 +22,9 @@ acme.sh --install-cert -d turingsynergy.com \ --fullchain-file /opt/webhook/scripts/tlsupdatev1/ssl//turingsynergy.com.pem \ --reloadcmd "curl 'https//webhook-ops.shasoapp.com/hooks/tlsupdate?action=upadte&&id=[华为云中配置的证书id]'" ``` + +# 查看证书状态 +```shell +# 如果证书有效期小于一周,推送通知到飞书,点击链接即可更新证书(前提是本地证书已更新) +curl 'https//webhook-ops.shasoapp.com/hooks/tlsupdate?action=status&&id=[华为云中配置的证书id]' +``` diff --git a/scripts/tlsupdate/config.yaml b/scripts/tlsupdate/config.yaml index 54dd9cf..4029b99 100644 --- a/scripts/tlsupdate/config.yaml +++ b/scripts/tlsupdate/config.yaml @@ -1,14 +1,14 @@ huawei: - ak: DSL6JB41TJ1SSUYQOKBB - sk: oQEJ00xSxPHpw4Xt5MhiqAz7KI04CNnZOBGCNEaQ + ak: xxx + sk: xxx -region:: cn-east-3 tls: - id: 86756ef7524a49ef8c8f00d2f6690866 region: cn-east-3 - private_key: /etc/webhook/scripts/tlsupdatev1/ssl/turingsynergy.com.key - certificate: /etc/webhook/scripts/tlsupdatev1/ssl/turingsynergy.com.pem + private_key: /etc/webhook/scripts/tlsupdate/ssl/turingsynergy.com.key + certificate: /etc/webhook/scripts/tlsupdate/ssl/turingsynergy.com.pem -notify: https://open.feishu.cn/open-apis/bot/v2/hook/986a905f-c8e0-4528-bbae-1fc5ea5a4be6 +#notify: https://open.feishu.cn/open-apis/bot/v2/hook/986a905f-c8e0-4528-bbae-1fc5ea5a4be6 +notify: https://open.feishu.cn/open-apis/bot/v2/hook/051679ae-0bef-4a21-9ff7-25fd76cd73ee -webhook: http://webhook-ops.shasoapp.com/hooks/hwtlsupdate \ No newline at end of file +webhook: http://webhook-ops.shasoapp.com/hooks/hwtlsupdate diff --git a/scripts/tlsupdate/consts.go b/scripts/tlsupdate/consts.go index f57d121..5681655 100644 --- a/scripts/tlsupdate/consts.go +++ b/scripts/tlsupdate/consts.go @@ -6,11 +6,11 @@ type FeishuPostMessage struct { } type PostContent struct { - Post *Post `json:"post"` + Post Post `json:"post"` } type Post struct { - ZhCn *Message `json:"zh_cn"` + ZhCn Message `json:"zh_cn"` } type Message struct { @@ -19,33 +19,20 @@ type Message struct { } type ContentItem struct { - Tag string `json:"tag"` - *TextContent - *AContent - *AtContent - *ImageContent -} - -type TextContent struct { - Text string `json:"text"` - Unescape *bool `json:"un_escape"` -} - -type AContent struct { - Text string `json:"text"` - Href string `json:"href"` -} - -type AtContent struct { - UserID string `json:"user_id"` - Username *string `json:"username"` -} - -type ImageContent struct { - ImageKey string `json:"image_key"` + Tag string `json:"tag"` + Text string `json:"text,omitempty"` + Unescape bool `json:"un_escape,omitempty"` + Href string `json:"href,omitempty"` + UserID string `json:"user_id,omitempty"` + UserName *string `json:"user_name,omitempty"` + ImageKey string `json:"image_key,omitempty"` } type FeishuTextMessage struct { MsgType string `json:"msg_type"` Content TextContent `json:"content"` } + +type TextContent struct { + Text string `json:"text"` +} diff --git a/scripts/tlsupdate/main.go b/scripts/tlsupdate/main.go index ee7cba3..39d6fa7 100644 --- a/scripts/tlsupdate/main.go +++ b/scripts/tlsupdate/main.go @@ -113,6 +113,10 @@ var rootCmd = &cobra.Command{ if action == "update" { msg = genUpdateMsg(region, ak, sk, id, key, cert) } + postUrl = generateUrl(webhook, "", map[string]interface{}{ + "action": "update", + "id": id, + }) } } @@ -120,54 +124,23 @@ var rootCmd = &cobra.Command{ if notice { // 如果有通知信息,则发送通知 if msg != "" { + var data interface{} // 如果post为true,即发送飞书富文本信息 if post { // 构造富文本信息 - postData := FeishuPostMessage{ - MsgType: "post", - Content: PostContent{ - Post: &Post{ - ZhCn: &Message{ - Title: "华为云TLS", - Content: [][]ContentItem{ - { - { - Tag: "text", - TextContent: &TextContent{ - Text: msg, - }, - }, - { - Tag: "a", - AContent: &AContent{ - Text: "点击续签TLS证书", - Href: postUrl, - }, - }, - }, - }, - }, - }, + data = genPostAMsg("华为云TLS", msg, "点击续签TLS证书", postUrl) + } else { + // 发送text文本信息 + // 构造文本信息 + data = FeishuTextMessage{ + MsgType: "text", + Content: TextContent{ + Text: msg, }, } - - // 发送通知富文本信息 - if err := postRequest(notify, postData); err != nil { - fmt.Println("Error sending message:", err) - os.Exit(1) - } - } - - // 发送text文本信息 - // 构造文本信息 - textData := FeishuTextMessage{ - MsgType: "text", - Content: TextContent{ - Text: msg, - }, } // 发送通知 - if err := postRequest(notify, textData); err != nil { + if err := postRequest(notify, data); err != nil { fmt.Println("Error sending message:", err) os.Exit(1) } @@ -198,15 +171,15 @@ func initConfig() { fmt.Println(err) os.Exit(1) } - bin, err := os.Executable() + exec, err := os.Executable() if err != nil { fmt.Println(err) os.Exit(1) } - binPath := filepath.Dir(bin) + exPath := filepath.Dir(exec) viper.AddConfigPath(".") viper.AddConfigPath(home) - viper.AddConfigPath(binPath) + viper.AddConfigPath(exPath) viper.SetConfigName("config") } @@ -314,7 +287,7 @@ func timeDiff(expire string) (bool, error) { duration := now.Sub(t) // 检查时间差是否小于1天 - if duration > -24*time.Hour { + if duration > -7*24*time.Hour { return true, nil } return false, nil @@ -358,7 +331,7 @@ func genStatusMsg(region, ak, sk, id string) (bool, string) { } if diff { - message = fmt.Sprintf("域名:%v\n\n证书有效期不足一天,请及时更新:", domain) + message = fmt.Sprintf("域名:%v\n\n证书有效期不足一周,请及时更新:", domain) return true, message } return false, message @@ -375,3 +348,29 @@ func genUpdateMsg(region, ak, sk, id, key, cert string) string { message = fmt.Sprintf("域名:%v\nhttps证书更新成功", domain) return message } + +func genPostAMsg(title, message, text, url string) *FeishuPostMessage { + return &FeishuPostMessage{ + MsgType: "post", + Content: PostContent{ + Post: Post{ + ZhCn: Message{ + Title: title, + Content: [][]ContentItem{ + { + { + Tag: "text", + Text: message, + }, + { + Tag: "a", + Text: text, + Href: url, + }, + }, + }, + }, + }, + }, + } +}