Update the webex notification provider and markdown
Signed-off-by: ahothan <ahothan@cisco.com>
This commit is contained in:
		
							parent
							
								
									5ed0f788c1
								
							
						
					
					
						commit
						4b694098db
					
				| 
						 | 
					@ -76,7 +76,7 @@ func (f Factory) Notifier(provider string) (Interface, error) {
 | 
				
			||||||
	case v1beta1.GoogleChatProvider:
 | 
						case v1beta1.GoogleChatProvider:
 | 
				
			||||||
		n, err = NewGoogleChat(f.URL, f.ProxyURL)
 | 
							n, err = NewGoogleChat(f.URL, f.ProxyURL)
 | 
				
			||||||
	case v1beta1.WebexProvider:
 | 
						case v1beta1.WebexProvider:
 | 
				
			||||||
		n, err = NewWebex(f.URL, f.ProxyURL, f.CertPool)
 | 
							n, err = NewWebex(f.URL, f.ProxyURL, f.CertPool, f.Channel, f.Token)
 | 
				
			||||||
	case v1beta1.SentryProvider:
 | 
						case v1beta1.SentryProvider:
 | 
				
			||||||
		n, err = NewSentry(f.CertPool, f.URL, f.Channel)
 | 
							n, err = NewSentry(f.CertPool, f.URL, f.Channel)
 | 
				
			||||||
	case v1beta1.AzureEventHubProvider:
 | 
						case v1beta1.AzureEventHubProvider:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,23 +23,70 @@ import (
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/fluxcd/pkg/runtime/events"
 | 
						"github.com/fluxcd/pkg/runtime/events"
 | 
				
			||||||
 | 
						"github.com/hashicorp/go-retryablehttp"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Example of provider manifest for webex:
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// apiVersion: notification.toolkit.fluxcd.io/v1beta1
 | 
				
			||||||
 | 
					// kind: Provider
 | 
				
			||||||
 | 
					// metadata:
 | 
				
			||||||
 | 
					//   name: webex
 | 
				
			||||||
 | 
					//   namespace: flux-system
 | 
				
			||||||
 | 
					// spec:
 | 
				
			||||||
 | 
					//   type: webex
 | 
				
			||||||
 | 
					//   address: https://webexapis.com/v1/messages
 | 
				
			||||||
 | 
					//   channel: <webexSpaceRoomID>
 | 
				
			||||||
 | 
					//  secretRef:
 | 
				
			||||||
 | 
					//    name: webex-bot-access-token
 | 
				
			||||||
 | 
					// ---
 | 
				
			||||||
 | 
					// apiVersion: v1
 | 
				
			||||||
 | 
					// kind: Secret
 | 
				
			||||||
 | 
					// metadata:
 | 
				
			||||||
 | 
					//   name: webex-bot-access-token
 | 
				
			||||||
 | 
					//   namespace: flux-system
 | 
				
			||||||
 | 
					// data:
 | 
				
			||||||
 | 
					//   # bot access token - must be base64 encoded
 | 
				
			||||||
 | 
					//   # echo -n <token> | base64
 | 
				
			||||||
 | 
					//   token: <webexBotAccessTokenBase64>
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// General steps on how to hook up Flux notifications to a Webex space:
 | 
				
			||||||
 | 
					// From the Webex App UI:
 | 
				
			||||||
 | 
					// - create a Webex space where you want notifications to be sent
 | 
				
			||||||
 | 
					// - add the bot email address to the Webex space (see next section)
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Register to https://developer.webex.com/, after signing in:
 | 
				
			||||||
 | 
					// - create a bot for forwarding FluxCD notifications to a Webex Space (User profile icon|MyWebexApps|Create a New App|Create a Bot)
 | 
				
			||||||
 | 
					// - make a note of the bot email address, this email needs to be added to the Webex space
 | 
				
			||||||
 | 
					// - generate a bot access token, this is the ID to use in the webex provider manifest token field
 | 
				
			||||||
 | 
					// - find the room ID associated to the webex space using https://developer.webex.com/docs/api/v1/rooms/list-rooms
 | 
				
			||||||
 | 
					// - this is the ID to use in the webex provider manifest channel field
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Webex holds the hook URL
 | 
					// Webex holds the hook URL
 | 
				
			||||||
type Webex struct {
 | 
					type Webex struct {
 | 
				
			||||||
 | 
						// mandatory: this should be set to the universal webex API server https://webexapis.com/v1/messages
 | 
				
			||||||
	URL      string
 | 
						URL      string
 | 
				
			||||||
 | 
						// mandatory: webex room ID, specifies on which webex space notifications must be sent
 | 
				
			||||||
 | 
						RoomId   string
 | 
				
			||||||
 | 
						// mandatory: webex bot access token, this access token must be generated after creating a webex bot
 | 
				
			||||||
 | 
						Token    string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// optional: use a proxy as needed
 | 
				
			||||||
	ProxyURL string
 | 
						ProxyURL string
 | 
				
			||||||
 | 
						// optional: x509 cert is no longer needed to post to a webex space
 | 
				
			||||||
	CertPool *x509.CertPool
 | 
						CertPool *x509.CertPool
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// WebexPayload holds the message text
 | 
					// WebexPayload holds the message text
 | 
				
			||||||
type WebexPayload struct {
 | 
					type WebexPayload struct {
 | 
				
			||||||
	Text     string `json:"text,omitempty"`
 | 
						RoomId   string `json:"roomId,omitempty"`
 | 
				
			||||||
	Markdown string `json:"markdown,omitempty"`
 | 
						Markdown string `json:"markdown,omitempty"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// NewWebex validates the Webex URL and returns a Webex object
 | 
					// NewWebex validates the Webex URL and returns a Webex object
 | 
				
			||||||
func NewWebex(hookURL, proxyURL string, certPool *x509.CertPool) (*Webex, error) {
 | 
					func NewWebex(hookURL, proxyURL string, certPool *x509.CertPool, channel string, token string) (*Webex, error) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	_, err := url.ParseRequestURI(hookURL)
 | 
						_, err := url.ParseRequestURI(hookURL)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, fmt.Errorf("invalid Webex hook URL %s", hookURL)
 | 
							return nil, fmt.Errorf("invalid Webex hook URL %s", hookURL)
 | 
				
			||||||
| 
						 | 
					@ -49,9 +96,27 @@ func NewWebex(hookURL, proxyURL string, certPool *x509.CertPool) (*Webex, error)
 | 
				
			||||||
		URL:      hookURL,
 | 
							URL:      hookURL,
 | 
				
			||||||
		ProxyURL: proxyURL,
 | 
							ProxyURL: proxyURL,
 | 
				
			||||||
		CertPool: certPool,
 | 
							CertPool: certPool,
 | 
				
			||||||
 | 
							RoomId: channel,
 | 
				
			||||||
 | 
							Token: token,
 | 
				
			||||||
	}, nil
 | 
						}, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (s *Webex) CreateMarkdown(event *events.Event) string {
 | 
				
			||||||
 | 
						var b strings.Builder
 | 
				
			||||||
 | 
						emoji := "✅"
 | 
				
			||||||
 | 
						if event.Severity == events.EventSeverityError {
 | 
				
			||||||
 | 
							emoji = "💣"
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						fmt.Fprintf(&b, "%s **%s/%s/%s**\n", emoji, event.InvolvedObject.Kind, event.InvolvedObject.Namespace, event.InvolvedObject.Name)
 | 
				
			||||||
 | 
						fmt.Fprintf(&b, "%s\n",	event.Message)
 | 
				
			||||||
 | 
						if len(event.Metadata) > 0 {
 | 
				
			||||||
 | 
							for k, v := range event.Metadata {
 | 
				
			||||||
 | 
								fmt.Fprintf(&b, ">**%s**: %s\n", k, v)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return b.String()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Post Webex message
 | 
					// Post Webex message
 | 
				
			||||||
func (s *Webex) Post(event events.Event) error {
 | 
					func (s *Webex) Post(event events.Event) error {
 | 
				
			||||||
	// Skip any update events
 | 
						// Skip any update events
 | 
				
			||||||
| 
						 | 
					@ -59,22 +124,14 @@ func (s *Webex) Post(event events.Event) error {
 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	objName := fmt.Sprintf("%s/%s.%s", strings.ToLower(event.InvolvedObject.Kind), event.InvolvedObject.Name, event.InvolvedObject.Namespace)
 | 
					 | 
				
			||||||
	markdown := fmt.Sprintf("> **NAME** = %s | **MESSAGE** = %s", objName, event.Message)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if len(event.Metadata) > 0 {
 | 
					 | 
				
			||||||
		markdown += " | **METADATA** ="
 | 
					 | 
				
			||||||
		for k, v := range event.Metadata {
 | 
					 | 
				
			||||||
			markdown += fmt.Sprintf(" **%s**: %s", k, v)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	payload := WebexPayload{
 | 
						payload := WebexPayload{
 | 
				
			||||||
		Text:     "",
 | 
							RoomId: s.RoomId,
 | 
				
			||||||
		Markdown: markdown,
 | 
							Markdown: s.CreateMarkdown(&event),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := postMessage(s.URL, s.ProxyURL, s.CertPool, payload); err != nil {
 | 
						if err := postMessage(s.URL, s.ProxyURL, s.CertPool, payload, func(request *retryablehttp.Request) {
 | 
				
			||||||
 | 
							request.Header.Add("Authorization", "Bearer "+ s.Token)
 | 
				
			||||||
 | 
						}); err != nil {
 | 
				
			||||||
		return fmt.Errorf("postMessage failed: %w", err)
 | 
							return fmt.Errorf("postMessage failed: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -34,12 +34,10 @@ func TestWebex_Post(t *testing.T) {
 | 
				
			||||||
		var payload = WebexPayload{}
 | 
							var payload = WebexPayload{}
 | 
				
			||||||
		err = json.Unmarshal(b, &payload)
 | 
							err = json.Unmarshal(b, &payload)
 | 
				
			||||||
		require.NoError(t, err)
 | 
							require.NoError(t, err)
 | 
				
			||||||
		require.Empty(t, payload.Text)
 | 
					 | 
				
			||||||
		require.Equal(t, "> **NAME** = gitrepository/webapp.gitops-system | **MESSAGE** = message | **METADATA** = **test**: metadata", payload.Markdown)
 | 
					 | 
				
			||||||
	}))
 | 
						}))
 | 
				
			||||||
	defer ts.Close()
 | 
						defer ts.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	webex, err := NewWebex(ts.URL, "", nil)
 | 
						webex, err := NewWebex(ts.URL, "", nil, "room", "token")
 | 
				
			||||||
	require.NoError(t, err)
 | 
						require.NoError(t, err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = webex.Post(testEvent())
 | 
						err = webex.Post(testEvent())
 | 
				
			||||||
| 
						 | 
					@ -47,7 +45,7 @@ func TestWebex_Post(t *testing.T) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestWebex_PostUpdate(t *testing.T) {
 | 
					func TestWebex_PostUpdate(t *testing.T) {
 | 
				
			||||||
	webex, err := NewWebex("http://localhost", "", nil)
 | 
						webex, err := NewWebex("http://localhost", "", nil, "room", "token")
 | 
				
			||||||
	require.NoError(t, err)
 | 
						require.NoError(t, err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	event := testEvent()
 | 
						event := testEvent()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue