[ Cmii ] [ Octopus ] - real project modify to use cmii operator
This commit is contained in:
@@ -217,13 +217,13 @@ func RestartCmiiBackendDeployment(cmiiEnv string) {
|
||||
cmiiDeploymentInterfaces := CmiiOperator.DeploymentAllInterface(cmiiEnv)
|
||||
|
||||
for _, deploymentInterface := range cmiiDeploymentInterfaces {
|
||||
_, ok := CmiiBackendAppMap[deploymentInterface.Name]
|
||||
if ok {
|
||||
if AppNameBelongsToCmiiImage(deploymentInterface.Name) {
|
||||
if !CmiiOperator.DeploymentRestart(deploymentInterface.Namespace, deploymentInterface.Name) {
|
||||
log.ErrorF("[RestartCmiiBackendDeployment] - restart of [%s] [%s] failed !", deploymentInterface.Namespace, deploymentInterface.Name)
|
||||
} else {
|
||||
log.DebugF("[RestartCmiiBackendDeployment] - restart of [%s] [%s] success !", deploymentInterface.Namespace, deploymentInterface.Name)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"time"
|
||||
"wdd.io/agent-go/assert"
|
||||
"wdd.io/agent-go/utils"
|
||||
"wdd.io/cmii_operator/message_pusher"
|
||||
)
|
||||
|
||||
var CmiiDevNamespaceList = []string{
|
||||
@@ -227,15 +228,18 @@ func TestUpdateCmiiImageTagFromNameTagMap(t *testing.T) {
|
||||
|
||||
func TestUpdateCmiiDeploymentImageTag(t *testing.T) {
|
||||
|
||||
cmiiEnv := "test"
|
||||
appName := "cmii-suav-supervision"
|
||||
newTag := "5.2.0-011901"
|
||||
cmiiEnv := devFlight
|
||||
appName := "cmii-uav-device"
|
||||
newTag := "5.4.0-26906-01"
|
||||
|
||||
tag := UpdateCmiiDeploymentImageTag(cmiiEnv, appName, newTag)
|
||||
assert.Equal(t, tag, true, "update image tag failed !")
|
||||
utils.SplitLinePrint()
|
||||
|
||||
check := CmiiOperator.DeploymentStatusCheck(cmiiEnv, appName, 180)
|
||||
check := CmiiOperator.DeploymentStatusCheck(cmiiEnv, appName, 300)
|
||||
assert.Equal(t, check, true, "deployment run failed!")
|
||||
|
||||
// push message
|
||||
message_pusher.PushCmiiUpdateMessage(cmiiEnv, appName, newTag, check)
|
||||
|
||||
}
|
||||
|
||||
@@ -81,14 +81,8 @@ func (op *CmiiK8sOperator) changeOperatorEnv(cmiiEnv string) {
|
||||
|
||||
// ok
|
||||
op.checkAndBuildCmiiK8sOperator()
|
||||
|
||||
if strings.Contains(cmiiEnv, "dev") {
|
||||
op.CurrentClient = op.DevClient
|
||||
op.CurrentConfig = op.DevConfig
|
||||
} else {
|
||||
op.CurrentClient = op.CoreClient
|
||||
op.CurrentConfig = op.CoreConfig
|
||||
}
|
||||
// first key
|
||||
op.CurrentNamespace = ""
|
||||
|
||||
if strings.Contains(cmiiEnv, "dev") {
|
||||
if strings.Contains(cmiiEnv, "devf") {
|
||||
@@ -120,13 +114,38 @@ func (op *CmiiK8sOperator) changeOperatorEnv(cmiiEnv string) {
|
||||
op.CurrentNamespace = uavms
|
||||
}
|
||||
|
||||
// key feature
|
||||
if op.CurrentNamespace == "" {
|
||||
op.CurrentNamespace = dev
|
||||
op.CurrentNamespace = cmiiEnv
|
||||
} else {
|
||||
if strings.Contains(cmiiEnv, "dev") {
|
||||
op.CurrentClient = op.DevClient
|
||||
op.CurrentConfig = op.DevConfig
|
||||
} else {
|
||||
op.CurrentClient = op.CoreClient
|
||||
op.CurrentConfig = op.CoreConfig
|
||||
}
|
||||
}
|
||||
|
||||
log.InfoF("[k8s env] - current env is => %s", op.CurrentNamespace)
|
||||
}
|
||||
|
||||
func (op *CmiiK8sOperator) BuildCurrentClientFromConfig(realClientConfig string) {
|
||||
log.InfoF("[BuildCurrentClientFromConfig] - build real k8s operator client !")
|
||||
realEnvConfig, err := clientcmd.RESTConfigFromKubeConfig([]byte(realClientConfig))
|
||||
if err != nil {
|
||||
msg := "[BuildCurrentClientFromConfig] - build real k8s operator error !"
|
||||
log.Error(msg)
|
||||
panic(msg)
|
||||
}
|
||||
op.CurrentConfig = realEnvConfig
|
||||
op.CurrentClient, err = kubernetes.NewForConfig(realEnvConfig)
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (op *CmiiK8sOperator) DeploymentAll(cmiiEnv string) []v1.Deployment {
|
||||
|
||||
op.changeOperatorEnv(cmiiEnv)
|
||||
|
||||
42
cmii_operator/actual_project/cqga/operator.go
Normal file
42
cmii_operator/actual_project/cqga/operator.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"wdd.io/agent-go/utils"
|
||||
"wdd.io/cmii_operator"
|
||||
)
|
||||
|
||||
var realConfig = `apiVersion: v1
|
||||
clusters:
|
||||
- cluster:
|
||||
certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN5RENDQWJDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRJeE1ERXhPREEyTURZeU5Gb1hEVE14TURFeE5qQTJNRFl5TkZvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBS2ZNCjFjTjBNUnhUTkRGdEZxcnRIZ0RPM29SV0dicmVob3VFcDJ3VUVRbU8yRUFyZDdkMUFReTJsSm9WM0RUVmhXbUwKcUFUOFcxaWRaS0x0Wm5mNjEva3JPeDd0U2lJeU4xa1ErN3NYRUhnTjVMc01EOVlKcndpUFdFY2FXdU9HVmI1aApMWDZWOTRjN0U5UlFDOENtd09iSkRCNG45ZE8zcDVlTDJHaFRpMkNrRWt3ZkRPR0tEL1IxeUNaK0tFcDRWWlplCnpwcnUzRG5zOUNqZHVOT1VBWTZzUGxjazNvdEdIVnhnRC9IRlRjUEhNbGhvUVQ4dmNDOTZwc0FtYXZPR1BZQ0YKa3RtN0VWYkZDOHN5Q1BMT3AwWWhTWHRkbGtKaC9UWHBaM0hSUWJxSzVPNXR4K1dGL05qMGJVc202ZldSMzZWQgpKQVVscUJIeFhSTzhGTFNrVHkwQ0F3RUFBYU1qTUNFd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFKeWZ2T3hHVVYvT2wybGRQNnYxeWFSTkd5RVkKWkVxTmM2Y29LSklsd0VQNUxNYzdZNGFReWorZCtVTE4zYmIrOXZsZXdHamluTHRrUW5HZ1R3Q3pKTU5ZNlNJNQo2NzJGZEtQTE85Szdpalhway9qRE9FVHJWS25aMXJBTytOUVBmSVhpcXQ3Y1RyVHlaVzdKTVl3emZNa2VlTGErCnREdmY1Rm5vQTBLN2U3a0ZXNTBpN2pXcGh4RXRMNEJpNzAwNnU4NEpqTU5weVp1MzhKMjFXZkR1RjBoU0NQREgKS0x4cnZIZ0FOYzJWU1c2L3JPaVVCQjdiV0JkcWcyQUNVRWZwN0V3UGs2S1BsdGNiNTJtdFhCU2xiQ3pRWWw4UQpmNmVGRFIrbnRjeXNGbU1FMFI3M1lNSHJwR0dGdlduSDVaTmEyVEJYdHpwN2tNNkVPREE5a2R4WkI1dz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
|
||||
server: https://192.168.11.170:16443
|
||||
name: kubernetes
|
||||
contexts:
|
||||
- context:
|
||||
cluster: kubernetes
|
||||
user: kubernetes-admin
|
||||
name: kubernetes-admin@kubernetes
|
||||
current-context: kubernetes-admin@kubernetes
|
||||
kind: Config
|
||||
preferences: {}
|
||||
users:
|
||||
- name: kubernetes-admin
|
||||
user:
|
||||
client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUM4ekNDQWR1Z0F3SUJBZ0lKQU9SWThQZlhadWQyTUEwR0NTcUdTSWIzRFFFQkN3VUFNQlV4RXpBUkJnTlYKQkFNVENtdDFZbVZ5Ym1WMFpYTXdIaGNOTWpJd01URTRNRFl6TmpRMFdoY05Nekl3TVRFMk1EWXpOalEwV2pBMApNUmN3RlFZRFZRUUtEQTV6ZVhOMFpXMDZiV0Z6ZEdWeWN6RVpNQmNHQTFVRUF3d1FhM1ZpWlhKdVpYUmxjeTFoClpHMXBiakNDQVNJd0RRWUpLb1pJaHZjTkFRRUJCUUFEZ2dFUEFEQ0NBUW9DZ2dFQkFPNTZ0ZG51M24rWUsxM3oKZmNlTzNiSmhBL2J0SGpoQXpvRnNObmZjeEY3dlRTZGczSUxySmVNVkFGbG50MHpUL2xacFBlU0ZUN25iL1g1Ygo4RjErSHA2dVR0b0hRVGJHR2VzbEprdkpFMjB3OGJ0Z3VrdlNmTnROOS9NNlFTWWkvTGlHeTZpd2kveGdBVUtKClFtVW1vZmhZSHNKMllFbXJCcExOVFhtenl2a2lUTlJZVC9iNlJJRzNiT3lIVm1Lc1cwQkNQNVZTTFJsLzErZlMKM0dCUUZ2UTNXdTdmVWlzMW9DSXhsc1k5V2VJUmpGOWJDbWtKNnZsT3BWbGlsTlA0cEtSSnl4aXNBNzExNENNWAprRGJvRFBXb2lxMktubzYveXI2L0xwMktsVVVSa1JhQklodEl5eXV2TldPbjhiTW90SUpCNWNOems4UkxYTm5TCklPZEtMVDhDQXdFQUFhTW5NQ1V3RGdZRFZSMFBBUUgvQkFRREFnV2dNQk1HQTFVZEpRUU1NQW9HQ0NzR0FRVUYKQndNQ01BMEdDU3FHU0liM0RRRUJDd1VBQTRJQkFRQ1lwVk9NemlGRUFta1A4S3B2ZWttR3laVGV3dzQreVhyUwo3TEpoWTdTR2pGY210ZldMSW9PWEhmWmZlZWNsN3M5Snh1SytPZlhqU0d0UU9jWXk0WHo5OVFWY2FRandJMEg5Cnc3aWJiYUw3M093RGZrRDMrdlNhME9ZRWZKSFlsNXErQXBnQVpLVWRWazMvZHpJSmhRR0V6L0UxcjdYTlNabDUKL1hOT3pwbzl0VHV2dDAxRlllV0RMN01DeWZGRHFTelpQdnNyWW81bDFiTE5yeEZHb1dvSTdUMlJzR205VXJyYwoyTy84R2hMYTkwZ2tLeE9JTEpYdlJCY2RrOUN4N01ROGFGVHBuSmtPMXJzVzUxMTFoTG5hNm9WRHhISlVrbjRkCmNhODFDV3R1Yk44dkpSYlFwVmkySTJ5K3ljZ3lrNTMzR21GQXNVS3dkdm5rVjNqTVJVbFYKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
|
||||
client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcGdJQkFBS0NBUUVBN25xMTJlN2VmNWdyWGZOOXg0N2RzbUVEOXUwZU9FRE9nV3cyZDl6RVh1OU5KMkRjCmd1c2w0eFVBV1dlM1ROUCtWbWs5NUlWUHVkdjlmbHZ3WFg0ZW5xNU8yZ2RCTnNZWjZ5VW1TOGtUYlREeHUyQzYKUzlKODIwMzM4enBCSmlMOHVJYkxxTENML0dBQlFvbENaU2FoK0ZnZXduWmdTYXNHa3MxTmViUEsrU0pNMUZoUAo5dnBFZ2JkczdJZFdZcXhiUUVJL2xWSXRHWC9YNTlMY1lGQVc5RGRhN3Q5U0t6V2dJakdXeGoxWjRoR01YMXNLCmFRbnErVTZsV1dLVTAvaWtwRW5MR0t3RHZYWGdJeGVRTnVnTTlhaUtyWXFlanIvS3ZyOHVuWXFWUlJHUkZvRWkKRzBqTEs2ODFZNmZ4c3lpMGdrSGx3M09UeEV0YzJkSWc1MG90UHdJREFRQUJBb0lCQVFDdTE5YldGbFNZdGNjdAoxYVJsRi9DZ3BKSlVpcHA2WWNGRmtFSUs5UmdnQmxESnl6RkE1d2hiQ2YyOGp0Y01BKzFZQzBidWNYTDNjRHZWClZiRFB5dlRHSUVQOWhBNGpDM0RiUHR4cCtkMDlWQUlYQUI3MkVqZXFUZXE1TC8rdDV6N2tSeWV2NE9oeE95NFIKU3pNYm1BeHVXS1VNcTkrQ2cxcUpiTzRkaVYwSjg5cUtidExsclFCeDFxcHNnUjNES1VhVGVNKzVpeFYyQ1Y1bApSNDV4aU43NWRrSkpaZlY2UUV5K3V2UVd0VHk4NUN3R1U2T2hjOXA4d2s0MmFrQS9qM05FTUZiTjdDaDFKbi9RCjRhNUJpMituRUE4dGVvV2FRSzdoeU5CRENWbTFsamFjaFFveGRSNGhCWVUxdkhTbkt4a0c4bDA1K1BpRTZmZFkKaUtyemhGR0JBb0dCQVBwOStKTExzZXJ6dFQ4a2VLU2FSMXBMOHB5MTQ3cmdjdEVhckxJL2ZqY1VMU3c3OUk3UAovWWhIWnhmdm9TZEZ2QTZwNy81eHFCRitaNTM5L1NKNDlLeWFOdGNJbW01UTZKSW9aRGgzWmVVS3lMKzA1YTdRCkNqMU1wZ2hKMlZDT2VPamNxd0NVQkFhcjNWSjd0cXRxRVFCQk9jMnlWU3dzbU5wclMyYmU1S3RCQW9HQkFQTzUKSG9ZVTBMK2tzdzJKUVM5ODF1ZWtrbDMzR1ZWQ2dPUFdGWThhR3VGRGt3Sm84WGk2TmhtKzh2TjlNaGg3WkYzeQpTU3E1U2RJd01pR0IvKzVJaWp1V25DbWszY2RPdGU0VFBsZHFvdjc3Q1FUUmxPNWJCekR0L1VqYVBBam5GS0FpClg4K0V6NUVXOXFSclN2ZXplZHFDRVRBVDhRWThqNk1WY0VCRW96aC9Bb0dCQUphcVRHZ25RdVdhSHF0VENZbWcKRGtqZW81Zmt3NHcwMG5xNWU2UmZFbENZdnk3N0JQY2RYVmFwOC9WdXVkVEFXZ1BMN1VGekpXOFlROFRBNzQvYgpodmVHYm5QYWhlRFNvNEM5OE1JUjl1VFVIcmxJV2xwU1ljWkxJeGFiTEs0S2MrbEVTVXE0dk04eWNwWFpPWjlTCjFkVDhab00xdjRzcGErcjhYRWNNekNmQkFvR0JBSXVuaXI4SDFHbk1CVEYvY1pPMWRDczkyUVR3MzFwRWhqaUgKWnNrZUMwTURCb3o5OTBmWFk4S3k4T0htM2pxN0VkTG5UMWVrM3BFTFB0NkdjRkZvelpUQmczQTFZVU9nYlkwagpCN2p0aU1LVXRDRkh1cEF1SnR1NXMwWDRqeWdHeVlITTBKdkhuV3lrL09WUCthQWYvblhmeTl1QndiMXlIRmcxCm82R2Y4dXNmQW9HQkFKeGlQcGdDODJPckoxazE3V3dyOFI2ZXpxR2VYb0JPRzFlOEN6ZG1UbWFrN3prWDJJelEKSTVjT3dGaTlnREhTbUVMa0dYZnRHZ01EcXF1VHVLdS9OdW9DQS94Z2FrdTQvVHplNktqbzRjc0NDTmFza3VrRQozYnhwSnU5cElYRU5tMXVuNXBZRy90QTF0V1Rtc3dnRjY1anc2RFpTQUFUTFZMSXg3RVRDR0RlOQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo=`
|
||||
|
||||
func main() {
|
||||
k8sOperator := cmii_operator.CmiiK8sOperator{}
|
||||
k8sOperator.BuildCurrentClientFromConfig(realConfig)
|
||||
realNamespace := "ingress-nginx"
|
||||
|
||||
// get all pods
|
||||
allInterface := k8sOperator.PodAllInterface(realNamespace)
|
||||
|
||||
for _, deploymentInterface := range allInterface {
|
||||
utils.BeautifulPrint(deploymentInterface)
|
||||
}
|
||||
|
||||
// restart all backend
|
||||
|
||||
}
|
||||
@@ -24,3 +24,6 @@
|
||||
2024-01-16-14-51-05 uavcloud-test cmii-suav-supervision 5.2.0-011603 5.2.0-011604
|
||||
2024-01-17-16-13-39 uavcloud-test cmii-suav-supervision 5.2.0-011604 5.2.0-0117
|
||||
2024-01-19-14-17-03 uavcloud-test cmii-suav-supervision 5.2.0-0117 5.2.0-011901
|
||||
2024-02-23-09-31-21 uavcloud-demo cmii-uav-device 5.4.0 5.4.0-26906
|
||||
2024-02-23-10-55-14 uavcloud-demo cmii-uav-device 5.4.0-26906 5.4.0-26906-01
|
||||
2024-02-23-14-32-05 uavcloud-devflight cmii-uav-device 5.2.0-validation 5.4.0-26906-01
|
||||
|
||||
165
cmii_operator/message_pusher/client.go
Normal file
165
cmii_operator/message_pusher/client.go
Normal file
@@ -0,0 +1,165 @@
|
||||
package message_pusher
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
"wdd.io/agent-go/logger"
|
||||
)
|
||||
|
||||
var (
|
||||
topicRegex = regexp.MustCompile(`^[-_A-Za-z0-9]{1,64}$`) // Same as in server/server.go
|
||||
log = logger.Log
|
||||
)
|
||||
|
||||
const (
|
||||
maxResponseBytes = 4096
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
config *Config
|
||||
}
|
||||
|
||||
// Message is a struct that represents a ntfy message
|
||||
type Message struct { // TODO combine with server.message
|
||||
ID string
|
||||
Event string
|
||||
Time int64
|
||||
Topic string
|
||||
Message string
|
||||
Title string
|
||||
Priority int
|
||||
Tags []string
|
||||
Click string
|
||||
Icon string
|
||||
Attachment *Attachment
|
||||
|
||||
// Additional fields
|
||||
TopicURL string
|
||||
SubscriptionID string
|
||||
Raw string
|
||||
}
|
||||
|
||||
// Attachment represents a message attachment
|
||||
type Attachment struct {
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type,omitempty"`
|
||||
Size int64 `json:"size,omitempty"`
|
||||
Expires int64 `json:"expires,omitempty"`
|
||||
URL string `json:"url"`
|
||||
Owner string `json:"-"` // IP address of uploader, used for rate limiting
|
||||
}
|
||||
|
||||
// New creates a new Client using a given Config
|
||||
func New(config *Config) *Client {
|
||||
return &Client{
|
||||
config: config,
|
||||
}
|
||||
}
|
||||
|
||||
func NewDefaultClient() *Client {
|
||||
defaultConfig := NewDefaultConfig()
|
||||
return New(defaultConfig)
|
||||
}
|
||||
|
||||
func (c *Client) PublishDefault(message bytes.Buffer, options []PublishOption) (*Message, error) {
|
||||
if c.config.DefaultTopic == "" {
|
||||
return nil, errors.New("[PublishDefault] - topic empty")
|
||||
}
|
||||
// parse default
|
||||
options = c.parseConfigToOption(options)
|
||||
|
||||
return c.PublishReader(c.config.DefaultTopic, bytes.NewReader(message.Bytes()), options)
|
||||
}
|
||||
|
||||
// Publish sends a message to a specific topic, optionally using options.
|
||||
// See PublishReader for details.
|
||||
func (c *Client) Publish(topic, message string, options []PublishOption) (*Message, error) {
|
||||
return c.PublishReader(topic, strings.NewReader(message), options)
|
||||
}
|
||||
|
||||
// PublishReader sends a message to a specific topic, optionally using options.
|
||||
//
|
||||
// A topic can be either a full URL (e.g. https://myhost.lan/mytopic), a short URL which is then prepended https://
|
||||
// (e.g. myhost.lan -> https://myhost.lan), or a short name which is expanded using the default host in the
|
||||
// config (e.g. mytopic -> https://ntfy.sh/mytopic).
|
||||
//
|
||||
// To pass title, priority and tags, check out WithTitle, WithPriority, WithTagsList, WithDelay, WithNoCache,
|
||||
// WithNoFirebase, and the generic WithHeader.
|
||||
func (c *Client) PublishReader(topic string, body io.Reader, options []PublishOption) (*Message, error) {
|
||||
topicURL, err := c.expandTopicURL(topic)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req, err := http.NewRequest("POST", topicURL, body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, option := range options {
|
||||
if err := option(req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
log.DebugF("%s Publishing message with headers %s", topicURL, req.Header)
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
b, err := io.ReadAll(io.LimitReader(resp.Body, maxResponseBytes))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, errors.New(strings.TrimSpace(string(b)))
|
||||
}
|
||||
m, err := toMessage(string(b), topicURL, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (c *Client) expandTopicURL(topic string) (string, error) {
|
||||
if strings.HasPrefix(topic, "http://") || strings.HasPrefix(topic, "https://") {
|
||||
return topic, nil
|
||||
} else if strings.Contains(topic, "/") {
|
||||
return fmt.Sprintf("https://%s", topic), nil
|
||||
}
|
||||
if !topicRegex.MatchString(topic) {
|
||||
return "", fmt.Errorf("invalid topic name: %s", topic)
|
||||
}
|
||||
return fmt.Sprintf("%s/%s", c.config.DefaultHost, topic), nil
|
||||
}
|
||||
|
||||
func (c *Client) parseConfigToOption(options []PublishOption) []PublishOption {
|
||||
config := c.config
|
||||
|
||||
if config.DefaultToken != "" {
|
||||
options = append(options, WithBearerAuth(config.DefaultToken))
|
||||
} else if config.DefaultUser != "" {
|
||||
if *config.DefaultPassword != "" {
|
||||
options = append(options, WithBasicAuth(config.DefaultUser, *config.DefaultPassword))
|
||||
} else {
|
||||
log.ErrorF("[parseConfigToOption] - default password is empty!")
|
||||
}
|
||||
}
|
||||
|
||||
return options
|
||||
}
|
||||
|
||||
func toMessage(s, topicURL, subscriptionID string) (*Message, error) {
|
||||
var m *Message
|
||||
if err := json.NewDecoder(strings.NewReader(s)).Decode(&m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m.TopicURL = topicURL
|
||||
m.SubscriptionID = subscriptionID
|
||||
m.Raw = s
|
||||
return m, nil
|
||||
}
|
||||
34
cmii_operator/message_pusher/client_test.go
Normal file
34
cmii_operator/message_pusher/client_test.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package message_pusher
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"wdd.io/agent-go/utils"
|
||||
)
|
||||
|
||||
func TestClient_Publish(t *testing.T) {
|
||||
|
||||
client := NewDefaultClient()
|
||||
|
||||
optionList := []PublishOption{
|
||||
WithTitle("测试内容"),
|
||||
WithPriority("5"),
|
||||
WithMarkdown(),
|
||||
}
|
||||
|
||||
deployPush := DeployPush{
|
||||
Namespace: "uavcloud-dev",
|
||||
AppName: "cmii-uav-platform",
|
||||
Replicas: "1",
|
||||
DeployStatus: false,
|
||||
}
|
||||
|
||||
deployPush.ParseCmiiDeployTemplate()
|
||||
|
||||
message, err := client.PublishDefault(deployPush.ParseCmiiDeployTemplate(), optionList)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
utils.BeautifulPrint(message)
|
||||
|
||||
}
|
||||
62
cmii_operator/message_pusher/config.go
Normal file
62
cmii_operator/message_pusher/config.go
Normal file
@@ -0,0 +1,62 @@
|
||||
package message_pusher
|
||||
|
||||
import (
|
||||
"gopkg.in/yaml.v3"
|
||||
"os"
|
||||
)
|
||||
|
||||
const (
|
||||
// DefaultBaseURL is the base URL used to expand short topic names
|
||||
DefaultBaseURL = "https://push.107421.xyz"
|
||||
|
||||
DefaultBaseToken = "tk_zvdb67fwj1hrjivkq3ga9z7u63av5"
|
||||
|
||||
DefaultTopic = "cmii"
|
||||
)
|
||||
|
||||
// Config is the config struct for a Client
|
||||
type Config struct {
|
||||
DefaultHost string `yaml:"default-host"`
|
||||
DefaultUser string `yaml:"default-user"`
|
||||
DefaultPassword *string `yaml:"default-password"`
|
||||
DefaultToken string `yaml:"default-token"`
|
||||
DefaultCommand string `yaml:"default-command"`
|
||||
DefaultTopic string `yaml:"default-topic"`
|
||||
Subscribe []Subscribe `yaml:"subscribe"`
|
||||
}
|
||||
|
||||
// Subscribe is the struct for a Subscription within Config
|
||||
type Subscribe struct {
|
||||
Topic string `yaml:"topic"`
|
||||
User *string `yaml:"user"`
|
||||
Password *string `yaml:"password"`
|
||||
Token *string `yaml:"token"`
|
||||
Command string `yaml:"command"`
|
||||
If map[string]string `yaml:"if"`
|
||||
}
|
||||
|
||||
// NewDefaultConfig creates a new Config struct for a Client
|
||||
func NewDefaultConfig() *Config {
|
||||
return &Config{
|
||||
DefaultHost: DefaultBaseURL,
|
||||
DefaultUser: "",
|
||||
DefaultPassword: nil,
|
||||
DefaultToken: DefaultBaseToken,
|
||||
DefaultTopic: DefaultTopic,
|
||||
DefaultCommand: "",
|
||||
Subscribe: nil,
|
||||
}
|
||||
}
|
||||
|
||||
// LoadConfig loads the Client config from a yaml file
|
||||
func LoadConfig(filename string) (*Config, error) {
|
||||
b, err := os.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c := NewDefaultConfig()
|
||||
if err := yaml.Unmarshal(b, c); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
204
cmii_operator/message_pusher/options.go
Normal file
204
cmii_operator/message_pusher/options.go
Normal file
@@ -0,0 +1,204 @@
|
||||
package message_pusher
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// RequestOption is a generic request option that can be added to Client calls
|
||||
type RequestOption = func(r *http.Request) error
|
||||
|
||||
// PublishOption is an option that can be passed to the Client.Publish call
|
||||
type PublishOption = RequestOption
|
||||
|
||||
// SubscribeOption is an option that can be passed to a Client.Subscribe or Client.Poll call
|
||||
type SubscribeOption = RequestOption
|
||||
|
||||
// WithMessage sets the notification message. This is an alternative way to passing the message body.
|
||||
func WithMessage(message string) PublishOption {
|
||||
return WithHeader("X-Message", message)
|
||||
}
|
||||
|
||||
// WithTitle adds a title to a message
|
||||
func WithTitle(title string) PublishOption {
|
||||
return WithHeader("X-Title", title)
|
||||
}
|
||||
|
||||
// WithPriority adds a priority to a message. The priority can be either a number (1=min, 5=max),
|
||||
// or the corresponding names (see util.ParsePriority).
|
||||
func WithPriority(priority string) PublishOption {
|
||||
return WithHeader("X-Priority", priority)
|
||||
}
|
||||
|
||||
// WithTagsList adds a list of tags to a message. The tags parameter must be a comma-separated list
|
||||
// of tags. To use a slice, use WithTags instead
|
||||
func WithTagsList(tags string) PublishOption {
|
||||
return WithHeader("X-Tags", tags)
|
||||
}
|
||||
|
||||
// WithTags adds a list of a tags to a message
|
||||
func WithTags(tags []string) PublishOption {
|
||||
return WithTagsList(strings.Join(tags, ","))
|
||||
}
|
||||
|
||||
// WithDelay instructs the server to send the message at a later date. The delay parameter can be a
|
||||
// Unix timestamp, a duration string or a natural langage string. See https://ntfy.sh/docs/publish/#scheduled-delivery
|
||||
// for details.
|
||||
func WithDelay(delay string) PublishOption {
|
||||
return WithHeader("X-Delay", delay)
|
||||
}
|
||||
|
||||
// WithClick makes the notification action open the given URL as opposed to entering the detail view
|
||||
func WithClick(url string) PublishOption {
|
||||
return WithHeader("X-Click", url)
|
||||
}
|
||||
|
||||
// WithIcon makes the notification use the given URL as its icon
|
||||
func WithIcon(icon string) PublishOption {
|
||||
return WithHeader("X-Icon", icon)
|
||||
}
|
||||
|
||||
// WithActions adds custom user actions to the notification. The value can be either a JSON array or the
|
||||
// simple format definition. See https://ntfy.sh/docs/publish/#action-buttons for details.
|
||||
func WithActions(value string) PublishOption {
|
||||
return WithHeader("X-Actions", value)
|
||||
}
|
||||
|
||||
// WithAttach sets a URL that will be used by the client to download an attachment
|
||||
func WithAttach(attach string) PublishOption {
|
||||
return WithHeader("X-Attach", attach)
|
||||
}
|
||||
|
||||
// WithMarkdown instructs the server to interpret the message body as Markdown
|
||||
func WithMarkdown() PublishOption {
|
||||
return WithHeader("X-Markdown", "yes")
|
||||
}
|
||||
|
||||
// WithFilename sets a filename for the attachment, and/or forces the HTTP body to interpreted as an attachment
|
||||
func WithFilename(filename string) PublishOption {
|
||||
return WithHeader("X-Filename", filename)
|
||||
}
|
||||
|
||||
// WithEmail instructs the server to also send the message to the given e-mail address
|
||||
func WithEmail(email string) PublishOption {
|
||||
return WithHeader("X-Email", email)
|
||||
}
|
||||
|
||||
// WithBasicAuth adds the Authorization header for basic auth to the request
|
||||
func WithBasicAuth(user, pass string) PublishOption {
|
||||
return WithHeader("Authorization", fmt.Sprintf("Basic %s", base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", user, pass)))))
|
||||
}
|
||||
|
||||
// WithBearerAuth adds the Authorization header for Bearer auth to the request
|
||||
func WithBearerAuth(token string) PublishOption {
|
||||
return WithHeader("Authorization", fmt.Sprintf("Bearer %s", token))
|
||||
}
|
||||
|
||||
// WithEmptyAuth clears the Authorization header
|
||||
func WithEmptyAuth() PublishOption {
|
||||
return RemoveHeader("Authorization")
|
||||
}
|
||||
|
||||
// WithNoCache instructs the server not to cache the message server-side
|
||||
func WithNoCache() PublishOption {
|
||||
return WithHeader("X-Cache", "no")
|
||||
}
|
||||
|
||||
// WithNoFirebase instructs the server not to forward the message to Firebase
|
||||
func WithNoFirebase() PublishOption {
|
||||
return WithHeader("X-Firebase", "no")
|
||||
}
|
||||
|
||||
// WithSince limits the number of messages returned from the server. The parameter since can be a Unix
|
||||
// timestamp (see WithSinceUnixTime), a duration (WithSinceDuration) the word "all" (see WithSinceAll).
|
||||
func WithSince(since string) SubscribeOption {
|
||||
return WithQueryParam("since", since)
|
||||
}
|
||||
|
||||
// WithSinceAll instructs the server to return all messages for the given topic from the server
|
||||
func WithSinceAll() SubscribeOption {
|
||||
return WithSince("all")
|
||||
}
|
||||
|
||||
// WithSinceDuration instructs the server to return all messages since the given duration ago
|
||||
func WithSinceDuration(since time.Duration) SubscribeOption {
|
||||
return WithSinceUnixTime(time.Now().Add(-1 * since).Unix())
|
||||
}
|
||||
|
||||
// WithSinceUnixTime instructs the server to return only messages newer or equal to the given timestamp
|
||||
func WithSinceUnixTime(since int64) SubscribeOption {
|
||||
return WithSince(fmt.Sprintf("%d", since))
|
||||
}
|
||||
|
||||
// WithPoll instructs the server to close the connection after messages have been returned. Don't use this option
|
||||
// directly. Use Client.Poll instead.
|
||||
func WithPoll() SubscribeOption {
|
||||
return WithQueryParam("poll", "1")
|
||||
}
|
||||
|
||||
// WithScheduled instructs the server to also return messages that have not been sent yet, i.e. delayed/scheduled
|
||||
// messages (see WithDelay). The messages will have a future date.
|
||||
func WithScheduled() SubscribeOption {
|
||||
return WithQueryParam("scheduled", "1")
|
||||
}
|
||||
|
||||
// WithFilter is a generic subscribe option meant to be used to filter for certain messages only
|
||||
func WithFilter(param, value string) SubscribeOption {
|
||||
return WithQueryParam(param, value)
|
||||
}
|
||||
|
||||
// WithMessageFilter instructs the server to only return messages that match the exact message
|
||||
func WithMessageFilter(message string) SubscribeOption {
|
||||
return WithQueryParam("message", message)
|
||||
}
|
||||
|
||||
// WithTitleFilter instructs the server to only return messages with a title that match the exact string
|
||||
func WithTitleFilter(title string) SubscribeOption {
|
||||
return WithQueryParam("title", title)
|
||||
}
|
||||
|
||||
// WithPriorityFilter instructs the server to only return messages with the matching priority. Not that messages
|
||||
// without priority also implicitly match priority 3.
|
||||
func WithPriorityFilter(priority int) SubscribeOption {
|
||||
return WithQueryParam("priority", fmt.Sprintf("%d", priority))
|
||||
}
|
||||
|
||||
// WithTagsFilter instructs the server to only return messages that contain all of the given tags
|
||||
func WithTagsFilter(tags []string) SubscribeOption {
|
||||
return WithQueryParam("tags", strings.Join(tags, ","))
|
||||
}
|
||||
|
||||
// WithHeader is a generic option to add headers to a request
|
||||
func WithHeader(header, value string) RequestOption {
|
||||
return func(r *http.Request) error {
|
||||
if value != "" {
|
||||
r.Header.Set(header, value)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithQueryParam is a generic option to add query parameters to a request
|
||||
func WithQueryParam(param, value string) RequestOption {
|
||||
return func(r *http.Request) error {
|
||||
if value != "" {
|
||||
q := r.URL.Query()
|
||||
q.Add(param, value)
|
||||
r.URL.RawQuery = q.Encode()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// RemoveHeader is a generic option to remove a header from a request
|
||||
func RemoveHeader(header string) RequestOption {
|
||||
return func(r *http.Request) error {
|
||||
if header != "" {
|
||||
delete(r.Header, header)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
27
cmii_operator/message_pusher/publish.go
Normal file
27
cmii_operator/message_pusher/publish.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package message_pusher
|
||||
|
||||
var DefaultClientOp = NewDefaultClient()
|
||||
|
||||
var CmiiUpdatePushOptions = []PublishOption{
|
||||
WithTitle("更新应用"),
|
||||
WithPriority("3"),
|
||||
}
|
||||
|
||||
func PushCmiiUpdateMessage(cmiiEnv, appName, newTag string, updateStatus bool) {
|
||||
|
||||
deployPush := DeployPush{
|
||||
Namespace: cmiiEnv,
|
||||
AppName: appName,
|
||||
DeployStatus: updateStatus,
|
||||
ToTag: newTag,
|
||||
}
|
||||
|
||||
deployPush.ParseCmiiDeployTemplate()
|
||||
|
||||
_, err := DefaultClientOp.PublishDefault(deployPush.ParseCmiiDeployTemplate(), CmiiUpdatePushOptions)
|
||||
if err != nil {
|
||||
log.ErrorF("[PushCmiiUpdateMessage] - message push error ! %s", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
43
cmii_operator/message_pusher/push_template.go
Normal file
43
cmii_operator/message_pusher/push_template.go
Normal file
@@ -0,0 +1,43 @@
|
||||
package message_pusher
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
const cmiiDeployTemplate = `
|
||||
{{if .DeployStatus}}
|
||||
部署状态: 成功😍
|
||||
{{- else }}
|
||||
部署状态: 失败👿👿👿
|
||||
{{- end}}
|
||||
命名空间: {{.Namespace}}
|
||||
应用名称: {{.AppName}}
|
||||
副本数量: {{.Replicas}}
|
||||
目标版本: {{.ToTag}}
|
||||
`
|
||||
|
||||
type DeployPush struct {
|
||||
Namespace string
|
||||
AppName string
|
||||
Replicas string
|
||||
DeployStatus bool
|
||||
ToTag string
|
||||
}
|
||||
|
||||
func (d DeployPush) ParseCmiiDeployTemplate() bytes.Buffer {
|
||||
// 解析模板
|
||||
tmpl, err := template.New("cmiiDeployTemplate").Parse(cmiiDeployTemplate)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// 应用数据并打印结果
|
||||
var result bytes.Buffer
|
||||
err = tmpl.Execute(&result, d)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
20
cmii_operator/message_pusher/push_template_test.go
Normal file
20
cmii_operator/message_pusher/push_template_test.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package message_pusher
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDeployPush_ParseCmiiDeployTemplate(t *testing.T) {
|
||||
deployPush := DeployPush{
|
||||
Namespace: "casc",
|
||||
AppName: "sdasdas",
|
||||
Replicas: "dasdasd",
|
||||
DeployStatus: false,
|
||||
ToTag: "5.4.0",
|
||||
}
|
||||
|
||||
template := deployPush.ParseCmiiDeployTemplate()
|
||||
|
||||
fmt.Println(template.String())
|
||||
}
|
||||
Reference in New Issue
Block a user