mirror of
https://github.com/gravitational/teleport.git
synced 2026-09-01 16:03:55 +08:00
Convert integrations to use slog (#50921)
This commit is contained in:
@@ -33,6 +33,7 @@ import (
|
||||
"github.com/gravitational/teleport/integrations/lib"
|
||||
"github.com/gravitational/teleport/integrations/lib/logger"
|
||||
pd "github.com/gravitational/teleport/integrations/lib/plugindata"
|
||||
logutils "github.com/gravitational/teleport/lib/utils/log"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -118,7 +119,7 @@ func (a *App) run(ctx context.Context) error {
|
||||
|
||||
log := logger.Get(ctx)
|
||||
|
||||
log.Info("Access list monitor is running")
|
||||
log.InfoContext(ctx, "Access list monitor is running")
|
||||
|
||||
a.job.SetReady(true)
|
||||
|
||||
@@ -134,7 +135,7 @@ func (a *App) run(ctx context.Context) error {
|
||||
}
|
||||
timer.Reset(jitter(reminderInterval))
|
||||
case <-ctx.Done():
|
||||
log.Info("Access list monitor is finished")
|
||||
log.InfoContext(ctx, "Access list monitor is finished")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@@ -146,7 +147,7 @@ func (a *App) run(ctx context.Context) error {
|
||||
func (a *App) remindIfNecessary(ctx context.Context) error {
|
||||
log := logger.Get(ctx)
|
||||
|
||||
log.Info("Looking for Access List Review reminders")
|
||||
log.InfoContext(ctx, "Looking for Access List Review reminders")
|
||||
|
||||
var nextToken string
|
||||
var err error
|
||||
@@ -156,13 +157,14 @@ func (a *App) remindIfNecessary(ctx context.Context) error {
|
||||
accessLists, nextToken, err = a.apiClient.ListAccessLists(ctx, 0 /* default page size */, nextToken)
|
||||
if err != nil {
|
||||
if trace.IsNotImplemented(err) {
|
||||
log.Errorf("access list endpoint is not implemented on this auth server, so the access list app is ceasing to run.")
|
||||
log.ErrorContext(ctx, "access list endpoint is not implemented on this auth server, so the access list app is ceasing to run")
|
||||
return trace.Wrap(err)
|
||||
} else if trace.IsAccessDenied(err) {
|
||||
log.Warnf("Slack bot does not have permissions to list access lists. Please add access_list read and list permissions " +
|
||||
"to the role associated with the Slack bot.")
|
||||
const msg = "Slack bot does not have permissions to list access lists. Please add access_list read and list permissions " +
|
||||
"to the role associated with the Slack bot."
|
||||
log.WarnContext(ctx, msg)
|
||||
} else {
|
||||
log.Errorf("error listing access lists: %v", err)
|
||||
log.ErrorContext(ctx, "error listing access lists", "error", err)
|
||||
}
|
||||
break
|
||||
}
|
||||
@@ -170,7 +172,10 @@ func (a *App) remindIfNecessary(ctx context.Context) error {
|
||||
for _, accessList := range accessLists {
|
||||
recipients, err := a.getRecipientsRequiringReminders(ctx, accessList)
|
||||
if err != nil {
|
||||
log.WithError(err).Warnf("Error getting recipients to notify for review due for access list %q", accessList.Spec.Title)
|
||||
log.WarnContext(ctx, "Error getting recipients to notify for review due for access list",
|
||||
"error", err,
|
||||
"access_list", accessList.Spec.Title,
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -195,7 +200,7 @@ func (a *App) remindIfNecessary(ctx context.Context) error {
|
||||
}
|
||||
|
||||
if len(errs) > 0 {
|
||||
log.WithError(trace.NewAggregate(errs...)).Warn("Error notifying for access list reviews")
|
||||
log.WarnContext(ctx, "Error notifying for access list reviews", "error", trace.NewAggregate(errs...))
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -213,7 +218,10 @@ func (a *App) getRecipientsRequiringReminders(ctx context.Context, accessList *a
|
||||
|
||||
// If the current time before the notification start time, skip notifications.
|
||||
if now.Before(notificationStart) {
|
||||
log.Debugf("Access list %s is not ready for notifications, notifications start at %s", accessList.GetName(), notificationStart.Format(time.RFC3339))
|
||||
log.DebugContext(ctx, "Access list is not ready for notifications",
|
||||
"access_list", accessList.GetName(),
|
||||
"notification_start_time", notificationStart.Format(time.RFC3339),
|
||||
)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -255,12 +263,17 @@ func (a *App) fetchRecipients(ctx context.Context, accessList *accesslist.Access
|
||||
if err != nil {
|
||||
// TODO(kiosion): Remove in v18; protecting against server not having `GetAccessListOwners` func.
|
||||
if trace.IsNotImplemented(err) {
|
||||
log.WithError(err).Warnf("Error getting nested owners for access list '%v', continuing with only explicit owners", accessList.GetName())
|
||||
log.WarnContext(ctx, "Error getting nested owners for access list, continuing with only explicit owners",
|
||||
"error", err,
|
||||
"access_list", accessList.GetName(),
|
||||
)
|
||||
for _, owner := range accessList.Spec.Owners {
|
||||
allOwners = append(allOwners, &owner)
|
||||
}
|
||||
} else {
|
||||
log.WithError(err).Errorf("Error getting owners for access list '%v'", accessList.GetName())
|
||||
log.ErrorContext(ctx, "Error getting owners for access list",
|
||||
"error", err,
|
||||
"access_list", accessList.GetName())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,7 +283,7 @@ func (a *App) fetchRecipients(ctx context.Context, accessList *accesslist.Access
|
||||
for _, owner := range allOwners {
|
||||
recipient, err := a.bot.FetchRecipient(ctx, owner.Name)
|
||||
if err != nil {
|
||||
log.Debugf("error getting recipient %s", owner.Name)
|
||||
log.DebugContext(ctx, "error getting recipient", "recipient", owner.Name)
|
||||
continue
|
||||
}
|
||||
allRecipients[owner.Name] = *recipient
|
||||
@@ -293,7 +306,10 @@ func (a *App) updatePluginDataAndGetRecipientsRequiringReminders(ctx context.Con
|
||||
// Calculate days from start.
|
||||
daysFromStart := now.Sub(notificationStart) / oneDay
|
||||
windowStart = notificationStart.Add(daysFromStart * oneDay)
|
||||
log.Infof("windowStart: %s, now: %s", windowStart.String(), now.String())
|
||||
log.InfoContext(ctx, "calculating window start",
|
||||
"window_start", logutils.StringerAttr(windowStart),
|
||||
"now", logutils.StringerAttr(now),
|
||||
)
|
||||
}
|
||||
|
||||
recipients := []common.Recipient{}
|
||||
@@ -304,7 +320,10 @@ func (a *App) updatePluginDataAndGetRecipientsRequiringReminders(ctx context.Con
|
||||
|
||||
// If the notification window is before the last notification date, then this user doesn't need a notification.
|
||||
if !windowStart.After(lastNotification) {
|
||||
log.Debugf("User %s has already been notified for access list %s", recipient.Name, accessList.GetName())
|
||||
log.DebugContext(ctx, "User has already been notified for access list",
|
||||
"user", recipient.Name,
|
||||
"access_list", accessList.GetName(),
|
||||
)
|
||||
userNotifications[recipient.Name] = lastNotification
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -151,8 +151,10 @@ func (amrh *RuleHandler) RecipientsFromAccessMonitoringRules(ctx context.Context
|
||||
for _, rule := range amrh.getAccessMonitoringRules() {
|
||||
match, err := MatchAccessRequest(rule.Spec.Condition, req)
|
||||
if err != nil {
|
||||
log.WithError(err).WithField("rule", rule.Metadata.Name).
|
||||
Warn("Failed to parse access monitoring notification rule")
|
||||
log.WarnContext(ctx, "Failed to parse access monitoring notification rule",
|
||||
"error", err,
|
||||
"rule", rule.Metadata.Name,
|
||||
)
|
||||
}
|
||||
if !match {
|
||||
continue
|
||||
@@ -160,7 +162,7 @@ func (amrh *RuleHandler) RecipientsFromAccessMonitoringRules(ctx context.Context
|
||||
for _, recipient := range rule.Spec.Notification.Recipients {
|
||||
rec, err := amrh.fetchRecipientCallback(ctx, recipient)
|
||||
if err != nil {
|
||||
log.WithError(err).Warn("Failed to fetch plugin recipients based on Access monitoring rule recipients")
|
||||
log.WarnContext(ctx, "Failed to fetch plugin recipients based on Access monitoring rule recipients", "error", err)
|
||||
continue
|
||||
}
|
||||
recipientSet.Add(*rec)
|
||||
@@ -176,8 +178,10 @@ func (amrh *RuleHandler) RawRecipientsFromAccessMonitoringRules(ctx context.Cont
|
||||
for _, rule := range amrh.getAccessMonitoringRules() {
|
||||
match, err := MatchAccessRequest(rule.Spec.Condition, req)
|
||||
if err != nil {
|
||||
log.WithError(err).WithField("rule", rule.Metadata.Name).
|
||||
Warn("Failed to parse access monitoring notification rule")
|
||||
log.WarnContext(ctx, "Failed to parse access monitoring notification rule",
|
||||
"error", err,
|
||||
"rule", rule.Metadata.Name,
|
||||
)
|
||||
}
|
||||
if !match {
|
||||
continue
|
||||
|
||||
@@ -21,6 +21,7 @@ package accessrequest
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"slices"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -36,6 +37,7 @@ import (
|
||||
"github.com/gravitational/teleport/integrations/lib/logger"
|
||||
pd "github.com/gravitational/teleport/integrations/lib/plugindata"
|
||||
"github.com/gravitational/teleport/integrations/lib/watcherjob"
|
||||
logutils "github.com/gravitational/teleport/lib/utils/log"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -189,16 +191,16 @@ func (a *App) onWatcherEvent(ctx context.Context, event types.Event) error {
|
||||
func (a *App) handleAccessRequest(ctx context.Context, event types.Event) error {
|
||||
op := event.Type
|
||||
reqID := event.Resource.GetName()
|
||||
ctx, _ = logger.WithField(ctx, "request_id", reqID)
|
||||
ctx, _ = logger.With(ctx, "request_id", reqID)
|
||||
|
||||
switch op {
|
||||
case types.OpPut:
|
||||
ctx, _ = logger.WithField(ctx, "request_op", "put")
|
||||
ctx, _ = logger.With(ctx, "request_op", "put")
|
||||
req, ok := event.Resource.(types.AccessRequest)
|
||||
if !ok {
|
||||
return trace.BadParameter("unexpected resource type %T", event.Resource)
|
||||
}
|
||||
ctx, log := logger.WithField(ctx, "request_state", req.GetState().String())
|
||||
ctx, log := logger.With(ctx, "request_state", req.GetState().String())
|
||||
|
||||
var err error
|
||||
switch {
|
||||
@@ -207,21 +209,29 @@ func (a *App) handleAccessRequest(ctx context.Context, event types.Event) error
|
||||
case req.GetState().IsResolved():
|
||||
err = a.onResolvedRequest(ctx, req)
|
||||
default:
|
||||
log.WithField("event", event).Warn("Unknown request state")
|
||||
log.WarnContext(ctx, "Unknown request state",
|
||||
slog.Group("event",
|
||||
slog.Any("type", logutils.StringerAttr(event.Type)),
|
||||
slog.Group("resource",
|
||||
"kind", event.Resource.GetKind(),
|
||||
"name", event.Resource.GetName(),
|
||||
),
|
||||
),
|
||||
)
|
||||
return nil
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.WithError(err).Errorf("Failed to process request")
|
||||
log.ErrorContext(ctx, "Failed to process request", "error", err)
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
case types.OpDelete:
|
||||
ctx, log := logger.WithField(ctx, "request_op", "delete")
|
||||
ctx, log := logger.With(ctx, "request_op", "delete")
|
||||
|
||||
if err := a.onDeletedRequest(ctx, reqID); err != nil {
|
||||
log.WithError(err).Errorf("Failed to process deleted request")
|
||||
log.ErrorContext(ctx, "Failed to process deleted request", "error", err)
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
return nil
|
||||
@@ -242,7 +252,7 @@ func (a *App) onPendingRequest(ctx context.Context, req types.AccessRequest) err
|
||||
|
||||
loginsByRole, err := a.getLoginsByRole(ctx, req)
|
||||
if trace.IsAccessDenied(err) {
|
||||
log.Warnf("Missing permissions to get logins by role. Please add role.read to the associated role. error: %s", err)
|
||||
log.WarnContext(ctx, "Missing permissions to get logins by role, please add role.read to the associated role", "error", err)
|
||||
} else if err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
@@ -265,12 +275,12 @@ func (a *App) onPendingRequest(ctx context.Context, req types.AccessRequest) err
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
} else {
|
||||
log.Warning("No channel to post")
|
||||
log.WarnContext(ctx, "No channel to post")
|
||||
}
|
||||
|
||||
// Try to approve the request if user is currently on-call.
|
||||
if err := a.tryApproveRequest(ctx, reqID, req); err != nil {
|
||||
log.Warningf("Failed to auto approve request: %v", err)
|
||||
log.WarnContext(ctx, "Failed to auto approve request", "error", err)
|
||||
}
|
||||
case trace.IsAlreadyExists(err):
|
||||
// The messages were already sent, nothing to do, we can update the reviews
|
||||
@@ -311,7 +321,7 @@ func (a *App) onResolvedRequest(ctx context.Context, req types.AccessRequest) er
|
||||
case types.RequestState_PROMOTED:
|
||||
tag = pd.ResolvedPromoted
|
||||
default:
|
||||
logger.Get(ctx).Warningf("Unknown state %v (%s)", state, state.String())
|
||||
logger.Get(ctx).WarnContext(ctx, "Unknown state", "state", logutils.StringerAttr(state))
|
||||
return replyErr
|
||||
}
|
||||
err := trace.Wrap(a.updateMessages(ctx, req.GetName(), tag, reason, req.GetReviews()))
|
||||
@@ -330,13 +340,13 @@ func (a *App) broadcastAccessRequestMessages(ctx context.Context, recipients []c
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
for _, data := range sentMessages {
|
||||
logger.Get(ctx).WithFields(logger.Fields{
|
||||
"channel_id": data.ChannelID,
|
||||
"message_id": data.MessageID,
|
||||
}).Info("Successfully posted messages")
|
||||
logger.Get(ctx).InfoContext(ctx, "Successfully posted messages",
|
||||
"channel_id", data.ChannelID,
|
||||
"message_id", data.MessageID,
|
||||
)
|
||||
}
|
||||
if err != nil {
|
||||
logger.Get(ctx).WithError(err).Error("Failed to post one or more messages")
|
||||
logger.Get(ctx).ErrorContext(ctx, "Failed to post one or more messages", "error", err)
|
||||
}
|
||||
|
||||
_, err = a.pluginData.Update(ctx, reqID, func(existing PluginData) (PluginData, error) {
|
||||
@@ -369,7 +379,7 @@ func (a *App) postReviewReplies(ctx context.Context, reqID string, reqReviews []
|
||||
return existing, nil
|
||||
})
|
||||
if trace.IsAlreadyExists(err) {
|
||||
logger.Get(ctx).Debug("Failed to post reply: replies are already sent")
|
||||
logger.Get(ctx).DebugContext(ctx, "Failed to post reply: replies are already sent")
|
||||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
@@ -383,7 +393,7 @@ func (a *App) postReviewReplies(ctx context.Context, reqID string, reqReviews []
|
||||
|
||||
errors := make([]error, 0, len(slice))
|
||||
for _, data := range pd.SentMessages {
|
||||
ctx, _ = logger.WithFields(ctx, logger.Fields{"channel_id": data.ChannelID, "message_id": data.MessageID})
|
||||
ctx, _ = logger.With(ctx, "channel_id", data.ChannelID, "message_id", data.MessageID)
|
||||
for _, review := range slice {
|
||||
if err := a.bot.PostReviewReply(ctx, data.ChannelID, data.MessageID, review); err != nil {
|
||||
errors = append(errors, err)
|
||||
@@ -425,7 +435,7 @@ func (a *App) getMessageRecipients(ctx context.Context, req types.AccessRequest)
|
||||
for _, recipient := range recipients {
|
||||
rec, err := a.bot.FetchRecipient(ctx, recipient)
|
||||
if err != nil {
|
||||
log.Warningf("Failed to fetch Opsgenie recipient: %v", err)
|
||||
log.WarnContext(ctx, "Failed to fetch Opsgenie recipient", "error", err)
|
||||
continue
|
||||
}
|
||||
recipientSet.Add(*rec)
|
||||
@@ -436,7 +446,7 @@ func (a *App) getMessageRecipients(ctx context.Context, req types.AccessRequest)
|
||||
validEmailSuggReviewers := []string{}
|
||||
for _, reviewer := range req.GetSuggestedReviewers() {
|
||||
if !lib.IsEmail(reviewer) {
|
||||
log.Warningf("Failed to notify a suggested reviewer: %q does not look like a valid email", reviewer)
|
||||
log.WarnContext(ctx, "Failed to notify a suggested reviewer with an invalid email address", "reviewer", reviewer)
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -446,7 +456,7 @@ func (a *App) getMessageRecipients(ctx context.Context, req types.AccessRequest)
|
||||
for _, rawRecipient := range rawRecipients {
|
||||
recipient, err := a.bot.FetchRecipient(ctx, rawRecipient)
|
||||
if err != nil {
|
||||
log.WithError(err).Warn("Failure when fetching recipient, continuing anyway")
|
||||
log.WarnContext(ctx, "Failure when fetching recipient, continuing anyway", "error", err)
|
||||
} else {
|
||||
recipientSet.Add(*recipient)
|
||||
}
|
||||
@@ -476,7 +486,7 @@ func (a *App) updateMessages(ctx context.Context, reqID string, tag pd.Resolutio
|
||||
return existing, nil
|
||||
})
|
||||
if trace.IsNotFound(err) {
|
||||
log.Debug("Failed to update messages: plugin data is missing")
|
||||
log.DebugContext(ctx, "Failed to update messages: plugin data is missing")
|
||||
return nil
|
||||
}
|
||||
if trace.IsAlreadyExists(err) {
|
||||
@@ -485,7 +495,7 @@ func (a *App) updateMessages(ctx context.Context, reqID string, tag pd.Resolutio
|
||||
"cannot change the resolution tag of an already resolved request, existing: %s, event: %s",
|
||||
pluginData.ResolutionTag, tag)
|
||||
}
|
||||
log.Debug("Request is already resolved, ignoring event")
|
||||
log.DebugContext(ctx, "Request is already resolved, ignoring event")
|
||||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
@@ -496,13 +506,17 @@ func (a *App) updateMessages(ctx context.Context, reqID string, tag pd.Resolutio
|
||||
if err := a.bot.UpdateMessages(ctx, reqID, reqData, sentMessages, reviews); err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
log.Infof("Successfully marked request as %s in all messages", tag)
|
||||
|
||||
log.InfoContext(ctx, "Marked request with resolution and sent emails!", "resolution", tag)
|
||||
|
||||
if err := a.bot.NotifyUser(ctx, reqID, reqData); err != nil && !trace.IsNotImplemented(err) {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
log.Infof("Successfully notified user %s request marked as %s", reqData.User, tag)
|
||||
log.InfoContext(ctx, "Successfully notified user",
|
||||
"user", reqData.User,
|
||||
"resolution", tag,
|
||||
)
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -545,13 +559,11 @@ func (a *App) getResourceNames(ctx context.Context, req types.AccessRequest) ([]
|
||||
// tryApproveRequest attempts to automatically approve the access request if the
|
||||
// user is on call for the configured service/team.
|
||||
func (a *App) tryApproveRequest(ctx context.Context, reqID string, req types.AccessRequest) error {
|
||||
log := logger.Get(ctx).
|
||||
WithField("req_id", reqID).
|
||||
WithField("user", req.GetUser())
|
||||
log := logger.Get(ctx).With("req_id", reqID, "user", req.GetUser())
|
||||
|
||||
oncallUsers, err := a.bot.FetchOncallUsers(ctx, req)
|
||||
if trace.IsNotImplemented(err) {
|
||||
log.Debugf("Skipping auto-approval because %q bot does not support automatic approvals.", a.pluginName)
|
||||
log.DebugContext(ctx, "Skipping auto-approval because bot does not support automatic approvals", "bot", a.pluginName)
|
||||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
@@ -559,7 +571,7 @@ func (a *App) tryApproveRequest(ctx context.Context, reqID string, req types.Acc
|
||||
}
|
||||
|
||||
if !slices.Contains(oncallUsers, req.GetUser()) {
|
||||
log.Debug("Skipping approval because user is not on-call.")
|
||||
log.DebugContext(ctx, "Skipping approval because user is not on-call")
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -573,12 +585,12 @@ func (a *App) tryApproveRequest(ctx context.Context, reqID string, req types.Acc
|
||||
},
|
||||
}); err != nil {
|
||||
if strings.HasSuffix(err.Error(), "has already reviewed this request") {
|
||||
log.Debug("Request has already been reviewed.")
|
||||
log.DebugContext(ctx, "Request has already been reviewed")
|
||||
return nil
|
||||
}
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
log.Info("Successfully submitted a request approval.")
|
||||
log.InfoContext(ctx, "Successfully submitted a request approval")
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ func (a *BaseApp) WaitReady(ctx context.Context) (bool, error) {
|
||||
|
||||
func (a *BaseApp) checkTeleportVersion(ctx context.Context) (proto.PingResponse, error) {
|
||||
log := logger.Get(ctx)
|
||||
log.Debug("Checking Teleport server version")
|
||||
log.DebugContext(ctx, "Checking Teleport server version")
|
||||
|
||||
pong, err := a.APIClient.Ping(ctx)
|
||||
if err != nil {
|
||||
@@ -156,9 +156,9 @@ func (a *BaseApp) run(ctx context.Context) error {
|
||||
|
||||
a.mainJob.SetReady(allOK)
|
||||
if allOK {
|
||||
log.Info("Plugin is ready")
|
||||
log.InfoContext(ctx, "Plugin is ready")
|
||||
} else {
|
||||
log.Error("Plugin is not ready")
|
||||
log.ErrorContext(ctx, "Plugin is not ready")
|
||||
}
|
||||
|
||||
for _, app := range a.apps {
|
||||
@@ -203,11 +203,11 @@ func (a *BaseApp) init(ctx context.Context) error {
|
||||
}
|
||||
}
|
||||
|
||||
log.Debug("Starting API health check...")
|
||||
log.DebugContext(ctx, "Starting API health check")
|
||||
if err = a.Bot.CheckHealth(ctx); err != nil {
|
||||
return trace.Wrap(err, "API health check failed")
|
||||
}
|
||||
|
||||
log.Debug("API health check finished ok")
|
||||
log.DebugContext(ctx, "API health check finished ok")
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -20,12 +20,12 @@ package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/gravitational/trace"
|
||||
"github.com/jonboulle/clockwork"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/gravitational/teleport/integrations/access/common/auth/oauth"
|
||||
"github.com/gravitational/teleport/integrations/access/common/auth/storage"
|
||||
@@ -65,7 +65,7 @@ type RotatedAccessTokenProviderConfig struct {
|
||||
Refresher oauth.Refresher
|
||||
Clock clockwork.Clock
|
||||
|
||||
Log *logrus.Entry
|
||||
Log *slog.Logger
|
||||
}
|
||||
|
||||
// CheckAndSetDefaults validates a configuration and sets default values
|
||||
@@ -87,7 +87,7 @@ func (c *RotatedAccessTokenProviderConfig) CheckAndSetDefaults() error {
|
||||
c.Clock = clockwork.NewRealClock()
|
||||
}
|
||||
if c.Log == nil {
|
||||
c.Log = logrus.NewEntry(logrus.StandardLogger())
|
||||
c.Log = slog.Default()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -104,7 +104,7 @@ type RotatedAccessTokenProvider struct {
|
||||
refresher oauth.Refresher
|
||||
clock clockwork.Clock
|
||||
|
||||
log logrus.FieldLogger
|
||||
log *slog.Logger
|
||||
|
||||
lock sync.RWMutex // protects the below fields
|
||||
creds *storage.Credentials
|
||||
@@ -153,12 +153,12 @@ func (r *RotatedAccessTokenProvider) RefreshLoop(ctx context.Context) {
|
||||
|
||||
timer := r.clock.NewTimer(interval)
|
||||
defer timer.Stop()
|
||||
r.log.Infof("Will attempt token refresh in: %s", interval)
|
||||
r.log.InfoContext(ctx, "Starting token refresh loop", "next_refresh", interval)
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
r.log.Info("Shutting down")
|
||||
r.log.InfoContext(ctx, "Shutting down")
|
||||
return
|
||||
case <-timer.Chan():
|
||||
creds, _ := r.store.GetCredentials(ctx)
|
||||
@@ -174,18 +174,21 @@ func (r *RotatedAccessTokenProvider) RefreshLoop(ctx context.Context) {
|
||||
|
||||
interval := r.getRefreshInterval(creds)
|
||||
timer.Reset(interval)
|
||||
r.log.Infof("Next refresh in: %s", interval)
|
||||
r.log.InfoContext(ctx, "Refreshed token", "next_refresh", interval)
|
||||
continue
|
||||
}
|
||||
|
||||
creds, err := r.refresh(ctx)
|
||||
if err != nil {
|
||||
r.log.Errorf("Error while refreshing: %s. Will retry after: %s", err, r.retryInterval)
|
||||
r.log.ErrorContext(ctx, "Error while refreshing token",
|
||||
"error", err,
|
||||
"retry_interval", r.retryInterval,
|
||||
)
|
||||
timer.Reset(r.retryInterval)
|
||||
} else {
|
||||
err := r.store.PutCredentials(ctx, creds)
|
||||
if err != nil {
|
||||
r.log.Errorf("Error while storing the refreshed credentials: %s", err)
|
||||
r.log.ErrorContext(ctx, "Error while storing the refreshed credentials", "error", err)
|
||||
timer.Reset(r.retryInterval)
|
||||
continue
|
||||
}
|
||||
@@ -196,7 +199,7 @@ func (r *RotatedAccessTokenProvider) RefreshLoop(ctx context.Context) {
|
||||
|
||||
interval := r.getRefreshInterval(creds)
|
||||
timer.Reset(interval)
|
||||
r.log.Infof("Successfully refreshed credentials. Next refresh in: %s", interval)
|
||||
r.log.InfoContext(ctx, "Successfully refreshed credentials", "next_refresh", interval)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,12 +20,12 @@ package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gravitational/trace"
|
||||
"github.com/jonboulle/clockwork"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/gravitational/teleport/integrations/access/common/auth/oauth"
|
||||
@@ -57,9 +57,6 @@ func (s *mockStore) PutCredentials(ctx context.Context, creds *storage.Credentia
|
||||
}
|
||||
|
||||
func TestRotatedAccessTokenProvider(t *testing.T) {
|
||||
log := logrus.New()
|
||||
log.Level = logrus.DebugLevel
|
||||
|
||||
newProvider := func(ctx context.Context, store storage.Store, refresher oauth.Refresher, clock clockwork.Clock, initialCreds *storage.Credentials) *RotatedAccessTokenProvider {
|
||||
return &RotatedAccessTokenProvider{
|
||||
store: store,
|
||||
@@ -70,7 +67,7 @@ func TestRotatedAccessTokenProvider(t *testing.T) {
|
||||
tokenBufferInterval: 1 * time.Hour,
|
||||
|
||||
creds: initialCreds,
|
||||
log: log,
|
||||
log: slog.Default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -162,7 +162,7 @@ func (b Bot) FetchOncallUsers(ctx context.Context, req types.AccessRequest) ([]s
|
||||
annotationKey := types.TeleportNamespace + types.ReqAnnotationApproveSchedulesLabel
|
||||
teamNames, err := common.GetNamesFromAnnotations(req, annotationKey)
|
||||
if err != nil {
|
||||
log.Debug("Automatic approvals annotation is empty or unspecified.")
|
||||
log.DebugContext(ctx, "Automatic approvals annotation is empty or unspecified")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -126,7 +126,7 @@ func onAfterDatadogResponse(sink common.StatusSink) resty.ResponseMiddleware {
|
||||
defer cancel()
|
||||
|
||||
if err := sink.Emit(ctx, status); err != nil {
|
||||
log.WithError(err).Errorf("Error while emitting Datadog Incident Management plugin status: %v", err)
|
||||
log.ErrorContext(ctx, "Error while emitting Datadog Incident Management plugin status", "error", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"context"
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
|
||||
"github.com/alecthomas/kingpin/v2"
|
||||
@@ -67,12 +68,13 @@ func main() {
|
||||
if err := run(*path, *debug); err != nil {
|
||||
lib.Bail(err)
|
||||
} else {
|
||||
logger.Standard().Info("Successfully shut down")
|
||||
slog.InfoContext(context.Background(), "Successfully shut down")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func run(configPath string, debug bool) error {
|
||||
ctx := context.Background()
|
||||
conf, err := datadog.LoadConfig(configPath)
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
@@ -86,14 +88,15 @@ func run(configPath string, debug bool) error {
|
||||
return err
|
||||
}
|
||||
if debug {
|
||||
logger.Standard().Debugf("DEBUG logging enabled")
|
||||
slog.DebugContext(ctx, "DEBUG logging enabled")
|
||||
}
|
||||
|
||||
app := datadog.NewDatadogApp(conf)
|
||||
go lib.ServeSignals(app, common.PluginShutdownTimeout)
|
||||
|
||||
logger.Standard().Infof("Starting Teleport Access Datadog Incident Management Plugin %s:%s", teleport.Version, teleport.Gitref)
|
||||
return trace.Wrap(
|
||||
app.Run(context.Background()),
|
||||
slog.InfoContext(ctx, "Starting Teleport Access Datadog Incident Management Plugin",
|
||||
"version", teleport.Version,
|
||||
"git_ref", teleport.Gitref,
|
||||
)
|
||||
return trace.Wrap(app.Run(ctx))
|
||||
}
|
||||
|
||||
@@ -32,7 +32,6 @@ import (
|
||||
|
||||
"github.com/gravitational/trace"
|
||||
"github.com/julienschmidt/httprouter"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/gravitational/teleport/integrations/access/datadog"
|
||||
)
|
||||
@@ -281,6 +280,6 @@ func (d *FakeDatadog) GetOncallTeams() (map[string][]string, bool) {
|
||||
|
||||
func panicIf(err error) {
|
||||
if err != nil {
|
||||
log.Panicf("%v at %v", err, string(debug.Stack()))
|
||||
panic(fmt.Sprintf("%v at %v", err, string(debug.Stack())))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,8 +94,7 @@ func emitStatusUpdate(resp *resty.Response, statusSink common.StatusSink) {
|
||||
|
||||
if err := statusSink.Emit(ctx, status); err != nil {
|
||||
logger.Get(resp.Request.Context()).
|
||||
WithError(err).
|
||||
Errorf("Error while emitting Discord plugin status: %v", err)
|
||||
ErrorContext(ctx, "Error while emitting Discord plugin status", "error", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
"context"
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
|
||||
"github.com/alecthomas/kingpin/v2"
|
||||
@@ -65,12 +66,13 @@ func main() {
|
||||
if err := run(*path, *debug); err != nil {
|
||||
lib.Bail(err)
|
||||
} else {
|
||||
logger.Standard().Info("Successfully shut down")
|
||||
slog.InfoContext(context.Background(), "Successfully shut down")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func run(configPath string, debug bool) error {
|
||||
ctx := context.Background()
|
||||
conf, err := discord.LoadDiscordConfig(configPath)
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
@@ -84,14 +86,15 @@ func run(configPath string, debug bool) error {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
if debug {
|
||||
logger.Standard().Debugf("DEBUG logging enabled")
|
||||
slog.DebugContext(ctx, "DEBUG logging enabled")
|
||||
}
|
||||
|
||||
app := discord.NewApp(conf)
|
||||
go lib.ServeSignals(app, common.PluginShutdownTimeout)
|
||||
|
||||
logger.Standard().Infof("Starting Teleport Access Discord Plugin %s:%s", teleport.Version, teleport.Gitref)
|
||||
return trace.Wrap(
|
||||
app.Run(context.Background()),
|
||||
slog.InfoContext(ctx, "Starting Teleport Access Discord Plugin",
|
||||
"version", teleport.Version,
|
||||
"git_ref", teleport.Gitref,
|
||||
)
|
||||
return trace.Wrap(app.Run(ctx))
|
||||
}
|
||||
|
||||
@@ -32,7 +32,6 @@ import (
|
||||
|
||||
"github.com/gravitational/trace"
|
||||
"github.com/julienschmidt/httprouter"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/gravitational/teleport/integrations/access/discord"
|
||||
)
|
||||
@@ -188,6 +187,6 @@ func (s *FakeDiscord) CheckMessageUpdateByResponding(ctx context.Context) (disco
|
||||
|
||||
func panicIf(err error) {
|
||||
if err != nil {
|
||||
log.Panicf("%v at %v", err, string(debug.Stack()))
|
||||
panic(fmt.Sprintf("%v at %v", err, string(debug.Stack())))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package email
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
"slices"
|
||||
"time"
|
||||
|
||||
@@ -32,6 +33,7 @@ import (
|
||||
"github.com/gravitational/teleport/integrations/lib/logger"
|
||||
"github.com/gravitational/teleport/integrations/lib/watcherjob"
|
||||
"github.com/gravitational/teleport/lib/utils"
|
||||
logutils "github.com/gravitational/teleport/lib/utils/log"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -90,7 +92,6 @@ func (a *App) run(ctx context.Context) error {
|
||||
var err error
|
||||
|
||||
log := logger.Get(ctx)
|
||||
log.Infof("Starting Teleport Access Email Plugin")
|
||||
|
||||
if err = a.init(ctx); err != nil {
|
||||
return trace.Wrap(err)
|
||||
@@ -137,9 +138,9 @@ func (a *App) run(ctx context.Context) error {
|
||||
|
||||
a.mainJob.SetReady(ok)
|
||||
if ok {
|
||||
log.Info("Plugin is ready")
|
||||
log.InfoContext(ctx, "Plugin is ready")
|
||||
} else {
|
||||
log.Error("Plugin is not ready")
|
||||
log.ErrorContext(ctx, "Plugin is not ready")
|
||||
}
|
||||
|
||||
<-watcherJob.Done()
|
||||
@@ -186,24 +187,24 @@ func (a *App) init(ctx context.Context) error {
|
||||
},
|
||||
})
|
||||
|
||||
log.Debug("Starting client connection health check...")
|
||||
log.DebugContext(ctx, "Starting client connection health check")
|
||||
if err = a.client.CheckHealth(ctx); err != nil {
|
||||
return trace.Wrap(err, "client connection health check failed")
|
||||
}
|
||||
log.Debug("Client connection health check finished ok")
|
||||
log.DebugContext(ctx, "Client connection health check finished ok")
|
||||
return nil
|
||||
}
|
||||
|
||||
// checkTeleportVersion checks that Teleport version is not lower than required
|
||||
func (a *App) checkTeleportVersion(ctx context.Context) (proto.PingResponse, error) {
|
||||
log := logger.Get(ctx)
|
||||
log.Debug("Checking Teleport server version")
|
||||
log.DebugContext(ctx, "Checking Teleport server version")
|
||||
pong, err := a.apiClient.Ping(ctx)
|
||||
if err != nil {
|
||||
if trace.IsNotImplemented(err) {
|
||||
return pong, trace.Wrap(err, "server version must be at least %s", minServerVersion)
|
||||
}
|
||||
log.Error("Unable to get Teleport server version")
|
||||
log.ErrorContext(ctx, "Unable to get Teleport server version")
|
||||
return pong, trace.Wrap(err)
|
||||
}
|
||||
err = utils.CheckMinVersion(pong.ServerVersion, minServerVersion)
|
||||
@@ -229,16 +230,16 @@ func (a *App) handleAccessRequest(ctx context.Context, event types.Event) error
|
||||
}
|
||||
op := event.Type
|
||||
reqID := event.Resource.GetName()
|
||||
ctx, _ = logger.WithField(ctx, "request_id", reqID)
|
||||
ctx, _ = logger.With(ctx, "request_id", reqID)
|
||||
|
||||
switch op {
|
||||
case types.OpPut:
|
||||
ctx, _ = logger.WithField(ctx, "request_op", "put")
|
||||
ctx, _ = logger.With(ctx, "request_op", "put")
|
||||
req, ok := event.Resource.(types.AccessRequest)
|
||||
if !ok {
|
||||
return trace.Errorf("unexpected resource type %T", event.Resource)
|
||||
}
|
||||
ctx, log := logger.WithField(ctx, "request_state", req.GetState().String())
|
||||
ctx, log := logger.With(ctx, "request_state", req.GetState().String())
|
||||
|
||||
var err error
|
||||
switch {
|
||||
@@ -249,21 +250,31 @@ func (a *App) handleAccessRequest(ctx context.Context, event types.Event) error
|
||||
case req.GetState().IsDenied():
|
||||
err = a.onResolvedRequest(ctx, req)
|
||||
default:
|
||||
log.WithField("event", event).Warn("Unknown request state")
|
||||
log.WarnContext(ctx, "Unknown request state",
|
||||
slog.Group("event",
|
||||
slog.Any("type", logutils.StringerAttr(event.Type)),
|
||||
slog.Group("resource",
|
||||
"kind", event.Resource.GetKind(),
|
||||
"name", event.Resource.GetName(),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
log.With("event", event).WarnContext(ctx, "Unknown request state")
|
||||
return nil
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.WithError(err).Errorf("Failed to process request")
|
||||
log.ErrorContext(ctx, "Failed to process request", "error", err)
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
case types.OpDelete:
|
||||
ctx, log := logger.WithField(ctx, "request_op", "delete")
|
||||
ctx, log := logger.With(ctx, "request_op", "delete")
|
||||
|
||||
if err := a.onDeletedRequest(ctx, reqID); err != nil {
|
||||
log.WithError(err).Errorf("Failed to process deleted request")
|
||||
log.ErrorContext(ctx, "Failed to process deleted request", "error", err)
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
return nil
|
||||
@@ -292,7 +303,7 @@ func (a *App) onPendingRequest(ctx context.Context, req types.AccessRequest) err
|
||||
if isNew {
|
||||
recipients := a.getRecipients(ctx, req)
|
||||
if len(recipients) == 0 {
|
||||
log.Warning("No recipients to send")
|
||||
log.WarnContext(ctx, "No recipients to send")
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -329,7 +340,7 @@ func (a *App) onResolvedRequest(ctx context.Context, req types.AccessRequest) er
|
||||
case types.RequestState_DENIED:
|
||||
resolution.Tag = ResolvedDenied
|
||||
default:
|
||||
logger.Get(ctx).Warningf("Unknown state %v (%s)", state, state.String())
|
||||
logger.Get(ctx).WarnContext(ctx, "Unknown state", "state", logutils.StringerAttr(state))
|
||||
return replyErr
|
||||
}
|
||||
err := trace.Wrap(a.sendResolution(ctx, req.GetName(), resolution))
|
||||
@@ -359,7 +370,7 @@ func (a *App) getRecipients(ctx context.Context, req types.AccessRequest) []comm
|
||||
rawRecipients := a.conf.RoleToRecipients.GetRawRecipientsFor(req.GetRoles(), req.GetSuggestedReviewers())
|
||||
for _, rawRecipient := range rawRecipients {
|
||||
if !lib.IsEmail(rawRecipient) {
|
||||
log.Warningf("Failed to notify a reviewer: %q does not look like a valid email", rawRecipient)
|
||||
log.WarnContext(ctx, "Failed to notify a suggested reviewer with an invalid email address", "reviewer", rawRecipient)
|
||||
continue
|
||||
}
|
||||
recipientSet.Add(common.Recipient{
|
||||
@@ -382,7 +393,7 @@ func (a *App) sendNewThreads(ctx context.Context, recipients []common.Recipient,
|
||||
logSentThreads(ctx, threadsSent, "new threads")
|
||||
|
||||
if err != nil {
|
||||
logger.Get(ctx).WithError(err).Error("Failed send one or more messages")
|
||||
logger.Get(ctx).ErrorContext(ctx, "Failed send one or more messages", "error", err)
|
||||
}
|
||||
|
||||
_, err = a.modifyPluginData(ctx, reqID, func(existing *PluginData) (PluginData, bool) {
|
||||
@@ -425,7 +436,7 @@ func (a *App) sendReviews(ctx context.Context, reqID string, reqData RequestData
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
if !ok {
|
||||
logger.Get(ctx).Debug("Failed to post reply: plugin data is missing")
|
||||
logger.Get(ctx).DebugContext(ctx, "Failed to post reply: plugin data is missing")
|
||||
return nil
|
||||
}
|
||||
reviews := reqReviews[oldCount:]
|
||||
@@ -439,7 +450,11 @@ func (a *App) sendReviews(ctx context.Context, reqID string, reqData RequestData
|
||||
if err != nil {
|
||||
errors = append(errors, err)
|
||||
}
|
||||
logger.Get(ctx).Infof("New review for request %v by %v is %v", reqID, review.Author, review.ProposedState.String())
|
||||
logger.Get(ctx).InfoContext(ctx, "New review for request",
|
||||
"request_id", reqID,
|
||||
"author", review.Author,
|
||||
"state", logutils.StringerAttr(review.ProposedState),
|
||||
)
|
||||
logSentThreads(ctx, threadsSent, "new review")
|
||||
}
|
||||
|
||||
@@ -473,7 +488,7 @@ func (a *App) sendResolution(ctx context.Context, reqID string, resolution Resol
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
if !ok {
|
||||
log.Debug("Failed to update messages: plugin data is missing")
|
||||
log.DebugContext(ctx, "Failed to update messages: plugin data is missing")
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -482,7 +497,7 @@ func (a *App) sendResolution(ctx context.Context, reqID string, resolution Resol
|
||||
threadsSent, err := a.client.SendResolution(ctx, threads, reqID, reqData)
|
||||
logSentThreads(ctx, threadsSent, "request resolved")
|
||||
|
||||
log.Infof("Marked request as %s and sent emails!", resolution.Tag)
|
||||
log.InfoContext(ctx, "Marked request with resolution and sent emails", "resolution", resolution.Tag)
|
||||
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
@@ -567,10 +582,11 @@ func (a *App) updatePluginData(ctx context.Context, reqID string, data PluginDat
|
||||
// logSentThreads logs successfully sent emails
|
||||
func logSentThreads(ctx context.Context, threads []EmailThread, kind string) {
|
||||
for _, thread := range threads {
|
||||
logger.Get(ctx).WithFields(logger.Fields{
|
||||
"email": thread.Email,
|
||||
"timestamp": thread.Timestamp,
|
||||
"message_id": thread.MessageID,
|
||||
}).Infof("Successfully sent %v!", kind)
|
||||
logger.Get(ctx).InfoContext(ctx, "Successfully sent",
|
||||
"email", thread.Email,
|
||||
"timestamp", thread.Timestamp,
|
||||
"message_id", thread.MessageID,
|
||||
"kind", kind,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,16 +61,16 @@ func NewClient(ctx context.Context, conf Config, clusterName, webProxyAddr strin
|
||||
|
||||
if conf.Mailgun != nil {
|
||||
mailer = NewMailgunMailer(*conf.Mailgun, conf.StatusSink, conf.Delivery.Sender, clusterName, conf.RoleToRecipients[types.Wildcard])
|
||||
logger.Get(ctx).WithField("domain", conf.Mailgun.Domain).Info("Using Mailgun as email transport")
|
||||
logger.Get(ctx).InfoContext(ctx, "Using Mailgun as email transport", "domain", conf.Mailgun.Domain)
|
||||
}
|
||||
|
||||
if conf.SMTP != nil {
|
||||
mailer = NewSMTPMailer(*conf.SMTP, conf.StatusSink, conf.Delivery.Sender, clusterName)
|
||||
logger.Get(ctx).WithFields(logger.Fields{
|
||||
"host": conf.SMTP.Host,
|
||||
"port": conf.SMTP.Port,
|
||||
"username": conf.SMTP.Username,
|
||||
}).Info("Using SMTP as email transport")
|
||||
logger.Get(ctx).InfoContext(ctx, "Using SMTP as email transport",
|
||||
"host", conf.SMTP.Host,
|
||||
"port", conf.SMTP.Port,
|
||||
"username", conf.SMTP.Username,
|
||||
)
|
||||
}
|
||||
|
||||
return Client{
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
"context"
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
|
||||
"github.com/alecthomas/kingpin/v2"
|
||||
@@ -65,12 +66,13 @@ func main() {
|
||||
if err := run(*path, *debug); err != nil {
|
||||
lib.Bail(err)
|
||||
} else {
|
||||
logger.Standard().Info("Successfully shut down")
|
||||
slog.InfoContext(context.Background(), "Successfully shut down")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func run(configPath string, debug bool) error {
|
||||
ctx := context.Background()
|
||||
conf, err := email.LoadConfig(configPath)
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
@@ -84,11 +86,11 @@ func run(configPath string, debug bool) error {
|
||||
return err
|
||||
}
|
||||
if debug {
|
||||
logger.Standard().Debugf("DEBUG logging enabled")
|
||||
slog.DebugContext(ctx, "DEBUG logging enabled")
|
||||
}
|
||||
|
||||
if conf.Delivery.Recipients != nil {
|
||||
logger.Standard().Warn("The delivery.recipients config option is deprecated, set role_to_recipients[\"*\"] instead for the same functionality")
|
||||
slog.WarnContext(ctx, "The delivery.recipients config option is deprecated, set role_to_recipients[\"*\"] instead for the same functionality")
|
||||
}
|
||||
|
||||
app, err := email.NewApp(*conf)
|
||||
@@ -98,8 +100,9 @@ func run(configPath string, debug bool) error {
|
||||
|
||||
go lib.ServeSignals(app, common.PluginShutdownTimeout)
|
||||
|
||||
logger.Standard().Infof("Starting Teleport Access Email Plugin %s:%s", teleport.Version, teleport.Gitref)
|
||||
return trace.Wrap(
|
||||
app.Run(context.Background()),
|
||||
slog.InfoContext(ctx, "Starting Teleport Access Email Plugin",
|
||||
"version", teleport.Version,
|
||||
"git_ref", teleport.Gitref,
|
||||
)
|
||||
return trace.Wrap(app.Run(ctx))
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ func (m *SMTPMailer) CheckHealth(ctx context.Context) error {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
if err := client.Close(); err != nil {
|
||||
log.Debug("Failed to close client connection after health check")
|
||||
log.DebugContext(ctx, "Failed to close client connection after health check")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -191,7 +191,7 @@ func (m *SMTPMailer) emitStatus(ctx context.Context, statusErr error) {
|
||||
code = http.StatusInternalServerError
|
||||
}
|
||||
if err := m.sink.Emit(ctx, common.StatusFromStatusCode(code)); err != nil {
|
||||
log.WithError(err).Error("Error while emitting Email plugin status")
|
||||
log.ErrorContext(ctx, "Error while emitting Email plugin status", "error", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -252,7 +252,7 @@ func (t *statusSinkTransport) RoundTrip(req *http.Request) (*http.Response, erro
|
||||
|
||||
status := common.StatusFromStatusCode(resp.StatusCode)
|
||||
if err := t.sink.Emit(ctx, status); err != nil {
|
||||
log.WithError(err).Error("Error while emitting Email plugin status")
|
||||
log.ErrorContext(ctx, "Error while emitting Email plugin status", "error", err)
|
||||
}
|
||||
}
|
||||
return resp, nil
|
||||
|
||||
@@ -24,7 +24,6 @@ import (
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/gravitational/trace"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -58,7 +57,8 @@ func newMockMailgunServer(concurrency int) *mockMailgunServer {
|
||||
s := httptest.NewUnstartedServer(func(mg *mockMailgunServer) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
if err := r.ParseMultipartForm(multipartFormBufSize); err != nil {
|
||||
log.Error(err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
id := uuid.New().String()
|
||||
|
||||
@@ -21,6 +21,7 @@ package jira
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
@@ -40,6 +41,7 @@ import (
|
||||
"github.com/gravitational/teleport/integrations/lib/logger"
|
||||
"github.com/gravitational/teleport/integrations/lib/watcherjob"
|
||||
"github.com/gravitational/teleport/lib/utils"
|
||||
logutils "github.com/gravitational/teleport/lib/utils/log"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -125,7 +127,6 @@ func (a *App) run(ctx context.Context) error {
|
||||
var err error
|
||||
|
||||
log := logger.Get(ctx)
|
||||
log.Infof("Starting Teleport Jira Plugin")
|
||||
|
||||
if err = a.init(ctx); err != nil {
|
||||
return trace.Wrap(err)
|
||||
@@ -164,9 +165,9 @@ func (a *App) run(ctx context.Context) error {
|
||||
ok := (a.webhookSrv == nil || httpOk) && watcherOk
|
||||
a.mainJob.SetReady(ok)
|
||||
if ok {
|
||||
log.Info("Plugin is ready")
|
||||
log.InfoContext(ctx, "Plugin is ready")
|
||||
} else {
|
||||
log.Error("Plugin is not ready")
|
||||
log.ErrorContext(ctx, "Plugin is not ready")
|
||||
}
|
||||
|
||||
if httpJob != nil {
|
||||
@@ -205,11 +206,11 @@ func (a *App) init(ctx context.Context) error {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
log.Debug("Starting Jira API health check...")
|
||||
log.DebugContext(ctx, "Starting Jira API health check")
|
||||
if err = a.jira.HealthCheck(ctx); err != nil {
|
||||
return trace.Wrap(err, "api health check failed")
|
||||
}
|
||||
log.Debug("Jira API health check finished ok")
|
||||
log.DebugContext(ctx, "Jira API health check finished ok")
|
||||
|
||||
if !a.conf.DisableWebhook {
|
||||
webhookSrv, err := NewWebhookServer(a.conf.HTTP, a.onJiraWebhook)
|
||||
@@ -227,13 +228,13 @@ func (a *App) init(ctx context.Context) error {
|
||||
|
||||
func (a *App) checkTeleportVersion(ctx context.Context) (proto.PingResponse, error) {
|
||||
log := logger.Get(ctx)
|
||||
log.Debug("Checking Teleport server version")
|
||||
log.DebugContext(ctx, "Checking Teleport server version")
|
||||
pong, err := a.teleport.Ping(ctx)
|
||||
if err != nil {
|
||||
if trace.IsNotImplemented(err) {
|
||||
return pong, trace.Wrap(err, "server version must be at least %s", minServerVersion)
|
||||
}
|
||||
log.Error("Unable to get Teleport server version")
|
||||
log.ErrorContext(ctx, "Unable to get Teleport server version")
|
||||
return pong, trace.Wrap(err)
|
||||
}
|
||||
err = utils.CheckMinVersion(pong.ServerVersion, minServerVersion)
|
||||
@@ -246,17 +247,17 @@ func (a *App) onWatcherEvent(ctx context.Context, event types.Event) error {
|
||||
}
|
||||
op := event.Type
|
||||
reqID := event.Resource.GetName()
|
||||
ctx, _ = logger.WithField(ctx, "request_id", reqID)
|
||||
ctx, _ = logger.With(ctx, "request_id", reqID)
|
||||
|
||||
switch op {
|
||||
case types.OpPut:
|
||||
ctx, _ = logger.WithField(ctx, "request_op", "put")
|
||||
ctx, _ = logger.With(ctx, "request_op", "put")
|
||||
req, ok := event.Resource.(types.AccessRequest)
|
||||
if !ok {
|
||||
return trace.Errorf("unexpected resource type %T", event.Resource)
|
||||
}
|
||||
ctx, log := logger.WithField(ctx, "request_state", req.GetState().String())
|
||||
log.Debug("Processing watcher event")
|
||||
ctx, log := logger.With(ctx, "request_state", req.GetState().String())
|
||||
log.DebugContext(ctx, "Processing watcher event")
|
||||
|
||||
var err error
|
||||
switch {
|
||||
@@ -265,21 +266,29 @@ func (a *App) onWatcherEvent(ctx context.Context, event types.Event) error {
|
||||
case req.GetState().IsResolved():
|
||||
err = a.onResolvedRequest(ctx, req)
|
||||
default:
|
||||
log.WithField("event", event).Warn("Unknown request state")
|
||||
log.WarnContext(ctx, "Unknown request state",
|
||||
slog.Group("event",
|
||||
slog.Any("type", logutils.StringerAttr(event.Type)),
|
||||
slog.Group("resource",
|
||||
"kind", event.Resource.GetKind(),
|
||||
"name", event.Resource.GetName(),
|
||||
),
|
||||
),
|
||||
)
|
||||
return nil
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to process request")
|
||||
log.ErrorContext(ctx, "Failed to process request", "error", err)
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
case types.OpDelete:
|
||||
ctx, log := logger.WithField(ctx, "request_op", "delete")
|
||||
ctx, log := logger.With(ctx, "request_op", "delete")
|
||||
|
||||
if err := a.onDeletedRequest(ctx, reqID); err != nil {
|
||||
log.WithError(err).Errorf("Failed to process deleted request")
|
||||
log.ErrorContext(ctx, "Failed to process deleted request", "error", err)
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
return nil
|
||||
@@ -299,10 +308,11 @@ func (a *App) onJiraWebhook(_ context.Context, webhook Webhook) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
ctx, log := logger.WithFields(ctx, logger.Fields{
|
||||
"jira_issue_id": webhook.Issue.ID,
|
||||
})
|
||||
log.Debugf("Processing incoming webhook event %q with type %q", webhookEvent, issueEventTypeName)
|
||||
ctx, log := logger.With(ctx, "jira_issue_id", webhook.Issue.ID)
|
||||
log.DebugContext(ctx, "Processing incoming webhook event",
|
||||
"event", webhookEvent,
|
||||
"event_type", issueEventTypeName,
|
||||
)
|
||||
|
||||
if webhook.Issue == nil {
|
||||
return trace.Errorf("got webhook without issue info")
|
||||
@@ -333,20 +343,20 @@ func (a *App) onJiraWebhook(_ context.Context, webhook Webhook) error {
|
||||
if statusName == "" {
|
||||
return trace.Errorf("getting Jira issue status: %w", err)
|
||||
}
|
||||
log.Warnf("Using most recent successful getIssue response: %v", err)
|
||||
log.WarnContext(ctx, "Using most recent successful getIssue response", "error", err)
|
||||
}
|
||||
|
||||
ctx, log = logger.WithFields(ctx, logger.Fields{
|
||||
"jira_issue_id": issue.ID,
|
||||
"jira_issue_key": issue.Key,
|
||||
})
|
||||
ctx, log = logger.With(ctx,
|
||||
"jira_issue_id", issue.ID,
|
||||
"jira_issue_key", issue.Key,
|
||||
)
|
||||
|
||||
switch {
|
||||
case statusName == "pending":
|
||||
log.Debug("Issue has pending status, ignoring it")
|
||||
log.DebugContext(ctx, "Issue has pending status, ignoring it")
|
||||
return nil
|
||||
case statusName == "expired":
|
||||
log.Debug("Issue has expired status, ignoring it")
|
||||
log.DebugContext(ctx, "Issue has expired status, ignoring it")
|
||||
return nil
|
||||
case statusName != "approved" && statusName != "denied":
|
||||
return trace.BadParameter("unknown Jira status %s", statusName)
|
||||
@@ -357,11 +367,11 @@ func (a *App) onJiraWebhook(_ context.Context, webhook Webhook) error {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
if reqID == "" {
|
||||
log.Debugf("Missing %q issue property", RequestIDPropertyKey)
|
||||
log.DebugContext(ctx, "Missing teleportAccessRequestId issue property")
|
||||
return nil
|
||||
}
|
||||
|
||||
ctx, log = logger.WithField(ctx, "request_id", reqID)
|
||||
ctx, log = logger.With(ctx, "request_id", reqID)
|
||||
|
||||
reqs, err := a.teleport.GetAccessRequests(ctx, types.AccessRequestFilter{ID: reqID})
|
||||
if err != nil {
|
||||
@@ -382,8 +392,9 @@ func (a *App) onJiraWebhook(_ context.Context, webhook Webhook) error {
|
||||
return trace.Errorf("plugin data is blank")
|
||||
}
|
||||
if pluginData.IssueID != issue.ID {
|
||||
log.WithField("plugin_data_issue_id", pluginData.IssueID).
|
||||
Debug("plugin_data.issue_id does not match issue.id")
|
||||
log.DebugContext(ctx, "plugin_data.issue_id does not match issue.id",
|
||||
"plugin_data_issue_id", pluginData.IssueID,
|
||||
)
|
||||
return trace.Errorf("issue_id from request's plugin_data does not match")
|
||||
}
|
||||
|
||||
@@ -406,17 +417,17 @@ func (a *App) onJiraWebhook(_ context.Context, webhook Webhook) error {
|
||||
|
||||
author, reason, err := a.loadResolutionInfo(ctx, issue, statusName)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to load resolution info from the issue history")
|
||||
log.ErrorContext(ctx, "Failed to load resolution info from the issue history", "error", err)
|
||||
}
|
||||
resolution.Reason = reason
|
||||
|
||||
ctx, _ = logger.WithFields(ctx, logger.Fields{
|
||||
"jira_user_email": author.EmailAddress,
|
||||
"jira_user_name": author.DisplayName,
|
||||
"request_user": req.GetUser(),
|
||||
"request_roles": req.GetRoles(),
|
||||
"reason": reason,
|
||||
})
|
||||
ctx, _ = logger.With(ctx,
|
||||
"jira_user_email", author.EmailAddress,
|
||||
"jira_user_name", author.DisplayName,
|
||||
"request_user", req.GetUser(),
|
||||
"request_roles", req.GetRoles(),
|
||||
"reason", reason,
|
||||
)
|
||||
if err := a.resolveRequest(ctx, reqID, author.EmailAddress, resolution); err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
@@ -498,11 +509,11 @@ func (a *App) createIssue(ctx context.Context, reqID string, reqData RequestData
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
ctx, log := logger.WithFields(ctx, logger.Fields{
|
||||
"jira_issue_id": data.IssueID,
|
||||
"jira_issue_key": data.IssueKey,
|
||||
})
|
||||
log.Info("Jira Issue created")
|
||||
ctx, log := logger.With(ctx,
|
||||
"jira_issue_id", data.IssueID,
|
||||
"jira_issue_key", data.IssueKey,
|
||||
)
|
||||
log.InfoContext(ctx, "Jira Issue created")
|
||||
|
||||
// Save jira issue info in plugin data.
|
||||
_, err = a.modifyPluginData(ctx, reqID, func(existing *PluginData) (PluginData, bool) {
|
||||
@@ -551,11 +562,11 @@ func (a *App) addReviewComments(ctx context.Context, reqID string, reqReviews []
|
||||
}
|
||||
if !ok {
|
||||
if issueID == "" {
|
||||
logger.Get(ctx).Debug("Failed to add the comment: plugin data is blank")
|
||||
logger.Get(ctx).DebugContext(ctx, "Failed to add the comment: plugin data is blank")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
ctx, _ = logger.WithField(ctx, "jira_issue_id", issueID)
|
||||
ctx, _ = logger.With(ctx, "jira_issue_id", issueID)
|
||||
|
||||
slice := reqReviews[oldCount:]
|
||||
if len(slice) == 0 {
|
||||
@@ -621,7 +632,7 @@ func (a *App) resolveRequest(ctx context.Context, reqID string, userEmail string
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
logger.Get(ctx).Infof("Jira user %s the request", resolution.Tag)
|
||||
logger.Get(ctx).InfoContext(ctx, "Jira user processed the request", "resolution", resolution.Tag)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -658,18 +669,18 @@ func (a *App) resolveIssue(ctx context.Context, reqID string, resolution Resolut
|
||||
}
|
||||
if !ok {
|
||||
if issueID == "" {
|
||||
logger.Get(ctx).Debug("Failed to resolve the issue: plugin data is blank")
|
||||
logger.Get(ctx).DebugContext(ctx, "Failed to resolve the issue: plugin data is blank")
|
||||
}
|
||||
|
||||
// Either plugin data is missing or issue is already resolved by us, just quit.
|
||||
return nil
|
||||
}
|
||||
|
||||
ctx, log := logger.WithField(ctx, "jira_issue_id", issueID)
|
||||
ctx, log := logger.With(ctx, "jira_issue_id", issueID)
|
||||
if err := a.jira.ResolveIssue(ctx, issueID, resolution); err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
log.Info("Successfully resolved the issue")
|
||||
log.InfoContext(ctx, "Successfully resolved the issue")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -125,7 +125,7 @@ func NewJiraClient(conf JiraConfig, clusterName, teleportProxyAddr string, statu
|
||||
defer cancel()
|
||||
|
||||
if err := statusSink.Emit(ctx, status); err != nil {
|
||||
log.WithError(err).Errorf("Error while emitting Jira plugin status: %v", err)
|
||||
log.ErrorContext(ctx, "Error while emitting Jira plugin status", "error", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,7 +199,7 @@ func (j *Jira) HealthCheck(ctx context.Context) error {
|
||||
}
|
||||
}
|
||||
|
||||
log.Debug("Checking out Jira project...")
|
||||
log.DebugContext(ctx, "Checking out Jira project")
|
||||
var project Project
|
||||
_, err = j.client.NewRequest().
|
||||
SetContext(ctx).
|
||||
@@ -209,9 +209,12 @@ func (j *Jira) HealthCheck(ctx context.Context) error {
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
log.Debugf("Found project %q named %q", project.Key, project.Name)
|
||||
log.DebugContext(ctx, "Found Jira project",
|
||||
"project", project.Key,
|
||||
"project_name", project.Name,
|
||||
)
|
||||
|
||||
log.Debug("Checking out Jira project permissions...")
|
||||
log.DebugContext(ctx, "Checking out Jira project permissions")
|
||||
queryOptions, err := query.Values(GetMyPermissionsQueryOptions{
|
||||
ProjectKey: j.project,
|
||||
Permissions: jiraRequiredPermissions,
|
||||
@@ -433,7 +436,7 @@ func (j *Jira) ResolveIssue(ctx context.Context, issueID string, resolution Reso
|
||||
if err2 := trace.Wrap(j.TransitionIssue(ctx, issue.ID, transition.ID)); err2 != nil {
|
||||
return trace.NewAggregate(err1, err2)
|
||||
}
|
||||
logger.Get(ctx).Debugf("Successfully moved the issue to the status %q", toStatus)
|
||||
logger.Get(ctx).DebugContext(ctx, "Successfully moved the issue to the target status", "target_status", toStatus)
|
||||
|
||||
return trace.Wrap(err1)
|
||||
}
|
||||
@@ -457,7 +460,7 @@ func (j *Jira) AddResolutionComment(ctx context.Context, id string, resolution R
|
||||
SetBody(CommentInput{Body: builder.String()}).
|
||||
Post("rest/api/2/issue/{issueID}/comment")
|
||||
if err == nil {
|
||||
logger.Get(ctx).Debug("Successfully added a resolution comment to the issue")
|
||||
logger.Get(ctx).DebugContext(ctx, "Successfully added a resolution comment to the issue")
|
||||
}
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
"context"
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
|
||||
"github.com/alecthomas/kingpin/v2"
|
||||
@@ -72,12 +73,13 @@ func main() {
|
||||
if err := run(*path, *insecure, *debug); err != nil {
|
||||
lib.Bail(err)
|
||||
} else {
|
||||
logger.Standard().Info("Successfully shut down")
|
||||
slog.InfoContext(context.Background(), "Successfully shut down")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func run(configPath string, insecure bool, debug bool) error {
|
||||
ctx := context.Background()
|
||||
conf, err := jira.LoadConfig(configPath)
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
@@ -91,7 +93,7 @@ func run(configPath string, insecure bool, debug bool) error {
|
||||
return err
|
||||
}
|
||||
if debug {
|
||||
logger.Standard().Debugf("DEBUG logging enabled")
|
||||
slog.DebugContext(ctx, "DEBUG logging enabled")
|
||||
}
|
||||
|
||||
conf.HTTP.Insecure = insecure
|
||||
@@ -102,8 +104,9 @@ func run(configPath string, insecure bool, debug bool) error {
|
||||
|
||||
go lib.ServeSignals(app, common.PluginShutdownTimeout)
|
||||
|
||||
logger.Standard().Infof("Starting Teleport Access Jira Plugin %s:%s", teleport.Version, teleport.Gitref)
|
||||
return trace.Wrap(
|
||||
app.Run(context.Background()),
|
||||
slog.InfoContext(ctx, "Starting Teleport Access Jira Plugin",
|
||||
"version", teleport.Version,
|
||||
"git_ref", teleport.Gitref,
|
||||
)
|
||||
return trace.Wrap(app.Run(ctx))
|
||||
}
|
||||
|
||||
@@ -30,7 +30,6 @@ import (
|
||||
|
||||
"github.com/gravitational/trace"
|
||||
"github.com/julienschmidt/httprouter"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/gravitational/teleport/integrations/access/jira"
|
||||
)
|
||||
@@ -304,6 +303,6 @@ func (s *FakeJira) CheckIssueTransition(ctx context.Context) (jira.Issue, error)
|
||||
|
||||
func panicIf(err error) {
|
||||
if err != nil {
|
||||
log.Panicf("%v at %v", err, string(debug.Stack()))
|
||||
panic(fmt.Sprintf("%v at %v", err, string(debug.Stack())))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -721,7 +721,7 @@ func (s *JiraSuiteOSS) TestRace() {
|
||||
defer cancel()
|
||||
var lastErr error
|
||||
for {
|
||||
logger.Get(ctx).Infof("Trying to approve issue %q", issue.Key)
|
||||
logger.Get(ctx).InfoContext(ctx, "Trying to approve issue", "issue_key", issue.Key)
|
||||
resp, err := s.postWebhook(ctx, s.webhookURL.String(), issue.ID, "Approved")
|
||||
if err != nil {
|
||||
if lib.IsDeadline(err) {
|
||||
|
||||
@@ -105,29 +105,31 @@ func (s *WebhookServer) processWebhook(rw http.ResponseWriter, r *http.Request,
|
||||
defer cancel()
|
||||
|
||||
httpRequestID := fmt.Sprintf("%v-%v", time.Now().Unix(), atomic.AddUint64(&s.counter, 1))
|
||||
ctx, log := logger.WithField(ctx, "jira_http_id", httpRequestID)
|
||||
ctx, log := logger.With(ctx, "jira_http_id", httpRequestID)
|
||||
|
||||
var webhook Webhook
|
||||
|
||||
body, err := io.ReadAll(io.LimitReader(r.Body, jiraWebhookPayloadLimit+1))
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to read webhook payload")
|
||||
log.ErrorContext(ctx, "Failed to read webhook payload", "error", err)
|
||||
http.Error(rw, "", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if len(body) > jiraWebhookPayloadLimit {
|
||||
log.Error("Received a webhook larger than %d bytes", jiraWebhookPayloadLimit)
|
||||
log.ErrorContext(ctx, "Received a webhook with a payload that exceeded the limit",
|
||||
"payload_size", len(body),
|
||||
"payload_size_limit", jiraWebhookPayloadLimit,
|
||||
)
|
||||
http.Error(rw, "", http.StatusRequestEntityTooLarge)
|
||||
}
|
||||
if err = json.Unmarshal(body, &webhook); err != nil {
|
||||
log.WithError(err).Error("Failed to parse webhook payload")
|
||||
log.ErrorContext(ctx, "Failed to parse webhook payload", "error", err)
|
||||
http.Error(rw, "", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if err = s.onWebhook(ctx, webhook); err != nil {
|
||||
log.WithError(err).Error("Failed to process webhook")
|
||||
log.Debugf("%v", trace.DebugReport(err))
|
||||
log.ErrorContext(ctx, "Failed to process webhook", "error", err)
|
||||
var code int
|
||||
switch {
|
||||
case lib.IsCanceled(err) || lib.IsDeadline(err):
|
||||
|
||||
@@ -150,7 +150,7 @@ func NewBot(conf Config, clusterName, webProxyAddr string) (Bot, error) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), mmStatusEmitTimeout)
|
||||
defer cancel()
|
||||
if err := sink.Emit(ctx, status); err != nil {
|
||||
log.Errorf("Error while emitting plugin status: %v", err)
|
||||
log.ErrorContext(ctx, "Error while emitting plugin status", "error", err)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -463,14 +463,14 @@ func (b Bot) buildPostText(reqID string, reqData pd.AccessRequestData) (string,
|
||||
}
|
||||
|
||||
func (b Bot) tryLookupDirectChannel(ctx context.Context, userEmail string) string {
|
||||
log := logger.Get(ctx).WithField("mm_user_email", userEmail)
|
||||
log := logger.Get(ctx).With("mm_user_email", userEmail)
|
||||
channel, err := b.LookupDirectChannel(ctx, userEmail)
|
||||
if err != nil {
|
||||
var errResult *ErrorResult
|
||||
if errors.As(trace.Unwrap(err), &errResult) {
|
||||
log.Warningf("Failed to lookup direct channel info: %q", errResult.Message)
|
||||
log.WarnContext(ctx, "Failed to lookup direct channel info", "error", errResult.Message)
|
||||
} else {
|
||||
log.WithError(err).Error("Failed to lookup direct channel info")
|
||||
log.ErrorContext(ctx, "Failed to lookup direct channel info", "error", err)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@@ -478,17 +478,17 @@ func (b Bot) tryLookupDirectChannel(ctx context.Context, userEmail string) strin
|
||||
}
|
||||
|
||||
func (b Bot) tryLookupChannel(ctx context.Context, team, name string) string {
|
||||
log := logger.Get(ctx).WithFields(logger.Fields{
|
||||
"mm_team": team,
|
||||
"mm_channel": name,
|
||||
})
|
||||
log := logger.Get(ctx).With(
|
||||
"mm_team", team,
|
||||
"mm_channel", name,
|
||||
)
|
||||
channel, err := b.LookupChannel(ctx, team, name)
|
||||
if err != nil {
|
||||
var errResult *ErrorResult
|
||||
if errors.As(trace.Unwrap(err), &errResult) {
|
||||
log.Warningf("Failed to lookup channel info: %q", errResult.Message)
|
||||
log.WarnContext(ctx, "Failed to lookup channel info", "error", errResult.Message)
|
||||
} else {
|
||||
log.WithError(err).Error("Failed to lookup channel info")
|
||||
log.ErrorContext(ctx, "Failed to lookup channel info", "error", err)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
"context"
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
|
||||
"github.com/alecthomas/kingpin/v2"
|
||||
@@ -65,12 +66,13 @@ func main() {
|
||||
if err := run(*path, *debug); err != nil {
|
||||
lib.Bail(err)
|
||||
} else {
|
||||
logger.Standard().Info("Successfully shut down")
|
||||
slog.InfoContext(context.Background(), "Successfully shut down")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func run(configPath string, debug bool) error {
|
||||
ctx := context.Background()
|
||||
conf, err := mattermost.LoadConfig(configPath)
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
@@ -84,14 +86,15 @@ func run(configPath string, debug bool) error {
|
||||
return err
|
||||
}
|
||||
if debug {
|
||||
logger.Standard().Debugf("DEBUG logging enabled")
|
||||
slog.DebugContext(ctx, "DEBUG logging enabled")
|
||||
}
|
||||
|
||||
app := mattermost.NewMattermostApp(conf)
|
||||
go lib.ServeSignals(app, common.PluginShutdownTimeout)
|
||||
|
||||
logger.Standard().Infof("Starting Teleport Access Mattermost Plugin %s:%s", teleport.Version, teleport.Gitref)
|
||||
return trace.Wrap(
|
||||
app.Run(context.Background()),
|
||||
slog.InfoContext(ctx, "Starting Teleport Access Mattermost Plugin",
|
||||
"version", teleport.Version,
|
||||
"git_ref", teleport.Gitref,
|
||||
)
|
||||
return trace.Wrap(app.Run(ctx))
|
||||
}
|
||||
|
||||
@@ -31,7 +31,6 @@ import (
|
||||
|
||||
"github.com/gravitational/trace"
|
||||
"github.com/julienschmidt/httprouter"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/gravitational/teleport/integrations/access/mattermost"
|
||||
)
|
||||
@@ -387,6 +386,6 @@ func (s *FakeMattermost) CheckPostUpdate(ctx context.Context) (mattermost.Post,
|
||||
|
||||
func panicIf(err error) {
|
||||
if err != nil {
|
||||
log.Panicf("%v at %v", err, string(debug.Stack()))
|
||||
panic(fmt.Sprintf("%v at %v", err, string(debug.Stack())))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,14 +62,9 @@ type App struct {
|
||||
|
||||
// NewApp initializes a new teleport-msteams app and returns it.
|
||||
func NewApp(conf Config) (*App, error) {
|
||||
log, err := conf.Log.NewSLogLogger()
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
app := &App{
|
||||
conf: conf,
|
||||
log: log.With("plugin", pluginName),
|
||||
log: slog.With("plugin", pluginName),
|
||||
}
|
||||
|
||||
app.mainJob = lib.NewServiceJob(app.run)
|
||||
|
||||
@@ -30,7 +30,6 @@ import (
|
||||
"github.com/gravitational/teleport/integrations/access/common"
|
||||
"github.com/gravitational/teleport/integrations/access/msteams/msapi"
|
||||
"github.com/gravitational/teleport/integrations/lib"
|
||||
"github.com/gravitational/teleport/integrations/lib/logger"
|
||||
"github.com/gravitational/teleport/integrations/lib/plugindata"
|
||||
)
|
||||
|
||||
@@ -469,7 +468,7 @@ func (b *Bot) CheckHealth(ctx context.Context) error {
|
||||
Code: status,
|
||||
ErrorMessage: message,
|
||||
}); err != nil {
|
||||
logger.Get(ctx).Errorf("Error while emitting ms teams plugin status: %v", err)
|
||||
b.log.ErrorContext(ctx, "Error while emitting ms teams plugin status", "error", err)
|
||||
}
|
||||
}
|
||||
return trace.Wrap(err)
|
||||
|
||||
@@ -16,6 +16,7 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
@@ -99,7 +100,7 @@ func main() {
|
||||
if err := run(*startConfigPath, *debug); err != nil {
|
||||
lib.Bail(err)
|
||||
} else {
|
||||
logger.Standard().Info("Successfully shut down")
|
||||
slog.InfoContext(context.Background(), "Successfully shut down")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,6 @@ import (
|
||||
"github.com/google/uuid"
|
||||
"github.com/gravitational/trace"
|
||||
"github.com/julienschmidt/httprouter"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/gravitational/teleport/integrations/access/msteams/msapi"
|
||||
)
|
||||
@@ -326,6 +325,6 @@ func (s *FakeTeams) CheckMessageUpdate(ctx context.Context) (Msg, error) {
|
||||
|
||||
func panicIf(err error) {
|
||||
if err != nil {
|
||||
log.Panicf("%v at %v", err, string(debug.Stack()))
|
||||
panic(fmt.Sprintf("%v at %v", err, string(debug.Stack())))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,8 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/gravitational/trace"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/gravitational/teleport/integrations/lib/logger"
|
||||
)
|
||||
|
||||
func Uninstall(ctx context.Context, configPath string) error {
|
||||
@@ -26,11 +27,13 @@ func Uninstall(ctx context.Context, configPath string) error {
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
err = checkApp(ctx, b)
|
||||
if err != nil {
|
||||
|
||||
if err := checkApp(ctx, b); err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
log := logger.Get(ctx)
|
||||
|
||||
var errs []error
|
||||
for _, recipient := range c.Recipients.GetAllRawRecipients() {
|
||||
_, isChannel := b.checkChannelURL(recipient)
|
||||
@@ -38,11 +41,11 @@ func Uninstall(ctx context.Context, configPath string) error {
|
||||
errs = append(errs, b.UninstallAppForUser(ctx, recipient))
|
||||
}
|
||||
}
|
||||
err = trace.NewAggregate(errs...)
|
||||
if err != nil {
|
||||
log.Errorln("The following error(s) happened when uninstalling the Teams App:")
|
||||
|
||||
if trace.NewAggregate(errs...) != nil {
|
||||
log.ErrorContext(ctx, "Encountered error(s) when uninstalling the Teams App", "error", err)
|
||||
return err
|
||||
}
|
||||
log.Info("Successfully uninstalled app for all recipients")
|
||||
log.InfoContext(ctx, "Successfully uninstalled app for all recipients")
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ package msteams
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"time"
|
||||
|
||||
cards "github.com/DanielTitkov/go-adaptive-cards"
|
||||
@@ -142,11 +143,7 @@ func loadConfig(configPath string) (*Bot, *Config, error) {
|
||||
|
||||
fmt.Printf(" - Checking application %v status...\n", c.MSAPI.TeamsAppID)
|
||||
|
||||
log, err := c.Log.NewSLogLogger()
|
||||
if err != nil {
|
||||
return nil, nil, trace.Wrap(err)
|
||||
}
|
||||
b, err := NewBot(c, "local", "", log)
|
||||
b, err := NewBot(c, "local", "", slog.Default())
|
||||
if err != nil {
|
||||
return nil, nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -39,6 +40,7 @@ import (
|
||||
"github.com/gravitational/teleport/integrations/lib/logger"
|
||||
"github.com/gravitational/teleport/integrations/lib/watcherjob"
|
||||
"github.com/gravitational/teleport/lib/utils"
|
||||
logutils "github.com/gravitational/teleport/lib/utils/log"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -115,7 +117,7 @@ func (a *App) run(ctx context.Context) error {
|
||||
var err error
|
||||
|
||||
log := logger.Get(ctx)
|
||||
log.Infof("Starting Teleport Access Opsgenie Plugin")
|
||||
log.InfoContext(ctx, "Starting Teleport Access Opsgenie Plugin")
|
||||
|
||||
if err = a.init(ctx); err != nil {
|
||||
return trace.Wrap(err)
|
||||
@@ -147,9 +149,9 @@ func (a *App) run(ctx context.Context) error {
|
||||
|
||||
a.mainJob.SetReady(ok)
|
||||
if ok {
|
||||
log.Info("Plugin is ready")
|
||||
log.InfoContext(ctx, "Plugin is ready")
|
||||
} else {
|
||||
log.Error("Plugin is not ready")
|
||||
log.ErrorContext(ctx, "Plugin is not ready")
|
||||
}
|
||||
|
||||
<-watcherJob.Done()
|
||||
@@ -177,24 +179,24 @@ func (a *App) init(ctx context.Context) error {
|
||||
}
|
||||
|
||||
log := logger.Get(ctx)
|
||||
log.Debug("Starting API health check...")
|
||||
log.DebugContext(ctx, "Starting API health check")
|
||||
if err = a.opsgenie.CheckHealth(ctx); err != nil {
|
||||
return trace.Wrap(err, "API health check failed")
|
||||
}
|
||||
log.Debug("API health check finished ok")
|
||||
log.DebugContext(ctx, "API health check finished ok")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *App) checkTeleportVersion(ctx context.Context) (proto.PingResponse, error) {
|
||||
log := logger.Get(ctx)
|
||||
log.Debug("Checking Teleport server version")
|
||||
log.DebugContext(ctx, "Checking Teleport server version")
|
||||
|
||||
pong, err := a.teleport.Ping(ctx)
|
||||
if err != nil {
|
||||
if trace.IsNotImplemented(err) {
|
||||
return pong, trace.Wrap(err, "server version must be at least %s", minServerVersion)
|
||||
}
|
||||
log.Error("Unable to get Teleport server version")
|
||||
log.ErrorContext(ctx, "Unable to get Teleport server version")
|
||||
return pong, trace.Wrap(err)
|
||||
}
|
||||
err = utils.CheckMinVersion(pong.ServerVersion, minServerVersion)
|
||||
@@ -219,16 +221,16 @@ func (a *App) handleAcessRequest(ctx context.Context, event types.Event) error {
|
||||
}
|
||||
op := event.Type
|
||||
reqID := event.Resource.GetName()
|
||||
ctx, _ = logger.WithField(ctx, "request_id", reqID)
|
||||
ctx, _ = logger.With(ctx, "request_id", reqID)
|
||||
|
||||
switch op {
|
||||
case types.OpPut:
|
||||
ctx, _ = logger.WithField(ctx, "request_op", "put")
|
||||
ctx, _ = logger.With(ctx, "request_op", "put")
|
||||
req, ok := event.Resource.(types.AccessRequest)
|
||||
if !ok {
|
||||
return trace.Errorf("unexpected resource type %T", event.Resource)
|
||||
}
|
||||
ctx, log := logger.WithField(ctx, "request_state", req.GetState().String())
|
||||
ctx, log := logger.With(ctx, "request_state", req.GetState().String())
|
||||
|
||||
var err error
|
||||
switch {
|
||||
@@ -237,21 +239,29 @@ func (a *App) handleAcessRequest(ctx context.Context, event types.Event) error {
|
||||
case req.GetState().IsResolved():
|
||||
err = a.onResolvedRequest(ctx, req)
|
||||
default:
|
||||
log.WithField("event", event).Warn("Unknown request state")
|
||||
log.WarnContext(ctx, "Unknown request state",
|
||||
slog.Group("event",
|
||||
slog.Any("type", logutils.StringerAttr(event.Type)),
|
||||
slog.Group("resource",
|
||||
"kind", event.Resource.GetKind(),
|
||||
"name", event.Resource.GetName(),
|
||||
),
|
||||
),
|
||||
)
|
||||
return nil
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to process request")
|
||||
log.ErrorContext(ctx, "Failed to process request", "error", err)
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
case types.OpDelete:
|
||||
ctx, log := logger.WithField(ctx, "request_op", "delete")
|
||||
ctx, log := logger.With(ctx, "request_op", "delete")
|
||||
|
||||
if err := a.onDeletedRequest(ctx, reqID); err != nil {
|
||||
log.WithError(err).Error("Failed to process deleted request")
|
||||
log.ErrorContext(ctx, "Failed to process deleted request", "error", err)
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
return nil
|
||||
@@ -310,13 +320,13 @@ func (a *App) getNotifySchedulesAndTeams(ctx context.Context, req types.AccessRe
|
||||
scheduleAnnotationKey := types.TeleportNamespace + types.ReqAnnotationNotifySchedulesLabel
|
||||
schedules, err = common.GetNamesFromAnnotations(req, scheduleAnnotationKey)
|
||||
if err != nil {
|
||||
log.Debugf("No schedules to notify in %s", scheduleAnnotationKey)
|
||||
log.DebugContext(ctx, "No schedules to notify", "schedule", scheduleAnnotationKey)
|
||||
}
|
||||
|
||||
teamAnnotationKey := types.TeleportNamespace + types.ReqAnnotationTeamsLabel
|
||||
teams, err = common.GetNamesFromAnnotations(req, teamAnnotationKey)
|
||||
if err != nil {
|
||||
log.Debugf("No teams to notify in %s", teamAnnotationKey)
|
||||
log.DebugContext(ctx, "No teams to notify", "teams", teamAnnotationKey)
|
||||
}
|
||||
|
||||
if len(schedules) == 0 && len(teams) == 0 {
|
||||
@@ -336,7 +346,7 @@ func (a *App) tryNotifyService(ctx context.Context, req types.AccessRequest) (bo
|
||||
|
||||
recipientSchedules, recipientTeams, err := a.getMessageRecipients(ctx, req)
|
||||
if err != nil {
|
||||
log.Debugf("Skipping the notification: %s", err)
|
||||
log.DebugContext(ctx, "Skipping notification", "error", err)
|
||||
return false, trace.Wrap(errMissingAnnotation)
|
||||
}
|
||||
|
||||
@@ -434,8 +444,8 @@ func (a *App) createAlert(ctx context.Context, reqID string, reqData RequestData
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
ctx, log := logger.WithField(ctx, "opsgenie_alert_id", data.AlertID)
|
||||
log.Info("Successfully created Opsgenie alert")
|
||||
ctx, log := logger.With(ctx, "opsgenie_alert_id", data.AlertID)
|
||||
log.InfoContext(ctx, "Successfully created Opsgenie alert")
|
||||
|
||||
// Save opsgenie alert info in plugin data.
|
||||
_, err = a.modifyPluginData(ctx, reqID, func(existing *PluginData) (PluginData, bool) {
|
||||
@@ -479,10 +489,10 @@ func (a *App) postReviewNotes(ctx context.Context, reqID string, reqReviews []ty
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
if !ok {
|
||||
logger.Get(ctx).Debug("Failed to post the note: plugin data is missing")
|
||||
logger.Get(ctx).DebugContext(ctx, "Failed to post the note: plugin data is missing")
|
||||
return nil
|
||||
}
|
||||
ctx, _ = logger.WithField(ctx, "opsgenie_alert_id", data.AlertID)
|
||||
ctx, _ = logger.With(ctx, "opsgenie_alert_id", data.AlertID)
|
||||
|
||||
slice := reqReviews[oldCount:]
|
||||
if len(slice) == 0 {
|
||||
@@ -504,7 +514,7 @@ func (a *App) tryApproveRequest(ctx context.Context, req types.AccessRequest) er
|
||||
|
||||
serviceNames, err := a.getOnCallServiceNames(req)
|
||||
if err != nil {
|
||||
logger.Get(ctx).Debugf("Skipping the approval: %s", err)
|
||||
logger.Get(ctx).DebugContext(ctx, "Skipping approval", "error", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -537,14 +547,14 @@ func (a *App) tryApproveRequest(ctx context.Context, req types.AccessRequest) er
|
||||
},
|
||||
}); err != nil {
|
||||
if strings.HasSuffix(err.Error(), "has already reviewed this request") {
|
||||
log.Debug("Already reviewed the request")
|
||||
log.DebugContext(ctx, "Already reviewed the request")
|
||||
return nil
|
||||
}
|
||||
return trace.Wrap(err, "submitting access request")
|
||||
}
|
||||
|
||||
}
|
||||
log.Info("Successfully submitted a request approval")
|
||||
log.InfoContext(ctx, "Successfully submitted a request approval")
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -576,15 +586,15 @@ func (a *App) resolveAlert(ctx context.Context, reqID string, resolution Resolut
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
if !ok {
|
||||
logger.Get(ctx).Debug("Failed to resolve the alert: plugin data is missing")
|
||||
logger.Get(ctx).DebugContext(ctx, "Failed to resolve the alert: plugin data is missing")
|
||||
return nil
|
||||
}
|
||||
|
||||
ctx, log := logger.WithField(ctx, "opsgenie_alert_id", alertID)
|
||||
ctx, log := logger.With(ctx, "opsgenie_alert_id", alertID)
|
||||
if err := a.opsgenie.ResolveAlert(ctx, alertID, resolution); err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
log.Info("Successfully resolved the alert")
|
||||
log.InfoContext(ctx, "Successfully resolved the alert")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -185,10 +185,10 @@ func (og Client) tryGetAlertRequestResult(ctx context.Context, reqID string) (Ge
|
||||
for {
|
||||
alertRequestResult, err := og.getAlertRequestResult(ctx, reqID)
|
||||
if err == nil {
|
||||
logger.Get(ctx).Debugf("Got alert request result: %+v", alertRequestResult)
|
||||
logger.Get(ctx).DebugContext(ctx, "Got alert request result", "alert_id", alertRequestResult.Data.AlertID)
|
||||
return alertRequestResult, nil
|
||||
}
|
||||
logger.Get(ctx).Debug("Failed to get alert request result:", err)
|
||||
logger.Get(ctx).DebugContext(ctx, "Failed to get alert request result", "error", err)
|
||||
if err := backoff.Do(ctx); err != nil {
|
||||
return GetAlertRequestResult{}, trace.Wrap(err)
|
||||
}
|
||||
@@ -344,8 +344,10 @@ func (og Client) CheckHealth(ctx context.Context) error {
|
||||
code = types.PluginStatusCode_OTHER_ERROR
|
||||
}
|
||||
if err := og.StatusSink.Emit(ctx, &types.PluginStatusV1{Code: code}); err != nil {
|
||||
logger.Get(resp.Request.Context()).WithError(err).
|
||||
WithField("code", resp.StatusCode()).Errorf("Error while emitting servicenow plugin status: %v", err)
|
||||
logger.Get(resp.Request.Context()).ErrorContext(ctx, "Error while emitting servicenow plugin status",
|
||||
"error", err,
|
||||
"code", resp.StatusCode(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,6 @@ import (
|
||||
|
||||
"github.com/gravitational/trace"
|
||||
"github.com/julienschmidt/httprouter"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/gravitational/teleport/api/types"
|
||||
"github.com/gravitational/teleport/integrations/access/opsgenie"
|
||||
@@ -314,7 +313,7 @@ func (s *FakeOpsgenie) GetSchedule(scheduleName string) ([]opsgenie.Responder, b
|
||||
|
||||
func panicIf(err error) {
|
||||
if err != nil {
|
||||
log.Panicf("%v at %v", err, string(debug.Stack()))
|
||||
panic(fmt.Sprintf("%v at %v", err, string(debug.Stack())))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -38,6 +39,7 @@ import (
|
||||
"github.com/gravitational/teleport/integrations/lib/logger"
|
||||
"github.com/gravitational/teleport/integrations/lib/watcherjob"
|
||||
"github.com/gravitational/teleport/lib/utils"
|
||||
logutils "github.com/gravitational/teleport/lib/utils/log"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -106,7 +108,6 @@ func (a *App) run(ctx context.Context) error {
|
||||
var err error
|
||||
|
||||
log := logger.Get(ctx)
|
||||
log.Infof("Starting Teleport Access PagerDuty Plugin")
|
||||
|
||||
if err = a.init(ctx); err != nil {
|
||||
return trace.Wrap(err)
|
||||
@@ -146,9 +147,9 @@ func (a *App) run(ctx context.Context) error {
|
||||
|
||||
a.mainJob.SetReady(ok)
|
||||
if ok {
|
||||
log.Info("Plugin is ready")
|
||||
log.InfoContext(ctx, "Plugin is ready")
|
||||
} else {
|
||||
log.Error("Plugin is not ready")
|
||||
log.ErrorContext(ctx, "Plugin is not ready")
|
||||
}
|
||||
|
||||
<-watcherJob.Done()
|
||||
@@ -202,25 +203,25 @@ func (a *App) init(ctx context.Context) error {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
log.Debug("Starting PagerDuty API health check...")
|
||||
log.DebugContext(ctx, "Starting PagerDuty API health check")
|
||||
if err = a.pagerduty.HealthCheck(ctx); err != nil {
|
||||
return trace.Wrap(err, "api health check failed. check your credentials and service_id settings")
|
||||
}
|
||||
log.Debug("PagerDuty API health check finished ok")
|
||||
log.DebugContext(ctx, "PagerDuty API health check finished ok")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *App) checkTeleportVersion(ctx context.Context) (proto.PingResponse, error) {
|
||||
log := logger.Get(ctx)
|
||||
log.Debug("Checking Teleport server version")
|
||||
log.DebugContext(ctx, "Checking Teleport server version")
|
||||
|
||||
pong, err := a.teleport.Ping(ctx)
|
||||
if err != nil {
|
||||
if trace.IsNotImplemented(err) {
|
||||
return pong, trace.Wrap(err, "server version must be at least %s", minServerVersion)
|
||||
}
|
||||
log.Error("Unable to get Teleport server version")
|
||||
log.ErrorContext(ctx, "Unable to get Teleport server version")
|
||||
return pong, trace.Wrap(err)
|
||||
}
|
||||
err = utils.CheckMinVersion(pong.ServerVersion, minServerVersion)
|
||||
@@ -245,16 +246,16 @@ func (a *App) handleAccessRequest(ctx context.Context, event types.Event) error
|
||||
}
|
||||
op := event.Type
|
||||
reqID := event.Resource.GetName()
|
||||
ctx, _ = logger.WithField(ctx, "request_id", reqID)
|
||||
ctx, _ = logger.With(ctx, "request_id", reqID)
|
||||
|
||||
switch op {
|
||||
case types.OpPut:
|
||||
ctx, _ = logger.WithField(ctx, "request_op", "put")
|
||||
ctx, _ = logger.With(ctx, "request_op", "put")
|
||||
req, ok := event.Resource.(types.AccessRequest)
|
||||
if !ok {
|
||||
return trace.Errorf("unexpected resource type %T", event.Resource)
|
||||
}
|
||||
ctx, log := logger.WithField(ctx, "request_state", req.GetState().String())
|
||||
ctx, log := logger.With(ctx, "request_state", req.GetState().String())
|
||||
|
||||
var err error
|
||||
switch {
|
||||
@@ -263,21 +264,29 @@ func (a *App) handleAccessRequest(ctx context.Context, event types.Event) error
|
||||
case req.GetState().IsResolved():
|
||||
err = a.onResolvedRequest(ctx, req)
|
||||
default:
|
||||
log.WithField("event", event).Warn("Unknown request state")
|
||||
log.WarnContext(ctx, "Unknown request state",
|
||||
slog.Group("event",
|
||||
slog.Any("type", logutils.StringerAttr(event.Type)),
|
||||
slog.Group("resource",
|
||||
"kind", event.Resource.GetKind(),
|
||||
"name", event.Resource.GetName(),
|
||||
),
|
||||
),
|
||||
)
|
||||
return nil
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to process request")
|
||||
log.ErrorContext(ctx, "Failed to process request", "error", err)
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
case types.OpDelete:
|
||||
ctx, log := logger.WithField(ctx, "request_op", "delete")
|
||||
ctx, log := logger.With(ctx, "request_op", "delete")
|
||||
|
||||
if err := a.onDeletedRequest(ctx, reqID); err != nil {
|
||||
log.WithError(err).Error("Failed to process deleted request")
|
||||
log.ErrorContext(ctx, "Failed to process deleted request", "error", err)
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
return nil
|
||||
@@ -288,7 +297,7 @@ func (a *App) handleAccessRequest(ctx context.Context, event types.Event) error
|
||||
|
||||
func (a *App) onPendingRequest(ctx context.Context, req types.AccessRequest) error {
|
||||
if len(req.GetSystemAnnotations()) == 0 {
|
||||
logger.Get(ctx).Debug("Cannot proceed further. Request is missing any annotations")
|
||||
logger.Get(ctx).DebugContext(ctx, "Cannot proceed further - request is missing any annotations")
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -370,11 +379,11 @@ func (a *App) tryNotifyService(ctx context.Context, req types.AccessRequest) (bo
|
||||
|
||||
serviceName, err := a.getNotifyServiceName(ctx, req)
|
||||
if err != nil {
|
||||
log.Debugf("Skipping the notification: %s", err)
|
||||
log.DebugContext(ctx, "Skipping the notification", "error", err)
|
||||
return false, trace.Wrap(errSkip)
|
||||
}
|
||||
|
||||
ctx, _ = logger.WithField(ctx, "pd_service_name", serviceName)
|
||||
ctx, _ = logger.With(ctx, "pd_service_name", serviceName)
|
||||
service, err := a.pagerduty.FindServiceByName(ctx, serviceName)
|
||||
if err != nil {
|
||||
return false, trace.Wrap(err, "finding pagerduty service %s", serviceName)
|
||||
@@ -420,8 +429,8 @@ func (a *App) createIncident(ctx context.Context, serviceID, reqID string, reqDa
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
ctx, log := logger.WithField(ctx, "pd_incident_id", data.IncidentID)
|
||||
log.Info("Successfully created PagerDuty incident")
|
||||
ctx, log := logger.With(ctx, "pd_incident_id", data.IncidentID)
|
||||
log.InfoContext(ctx, "Successfully created PagerDuty incident")
|
||||
|
||||
// Save pagerduty incident info in plugin data.
|
||||
_, err = a.modifyPluginData(ctx, reqID, func(existing *PluginData) (PluginData, bool) {
|
||||
@@ -465,10 +474,10 @@ func (a *App) postReviewNotes(ctx context.Context, reqID string, reqReviews []ty
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
if !ok {
|
||||
logger.Get(ctx).Debug("Failed to post the note: plugin data is missing")
|
||||
logger.Get(ctx).DebugContext(ctx, "Failed to post the note: plugin data is missing")
|
||||
return nil
|
||||
}
|
||||
ctx, _ = logger.WithField(ctx, "pd_incident_id", data.IncidentID)
|
||||
ctx, _ = logger.With(ctx, "pd_incident_id", data.IncidentID)
|
||||
|
||||
slice := reqReviews[oldCount:]
|
||||
if len(slice) == 0 {
|
||||
@@ -490,36 +499,40 @@ func (a *App) tryApproveRequest(ctx context.Context, req types.AccessRequest) er
|
||||
|
||||
serviceNames, err := a.getOnCallServiceNames(req)
|
||||
if err != nil {
|
||||
logger.Get(ctx).Debugf("Skipping the approval: %s", err)
|
||||
logger.Get(ctx).DebugContext(ctx, "Skipping approval", "error", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
userName := req.GetUser()
|
||||
if !lib.IsEmail(userName) {
|
||||
logger.Get(ctx).Warningf("Skipping the approval: %q does not look like a valid email", userName)
|
||||
logger.Get(ctx).WarnContext(ctx, "Skipping approval, found invalid email", "pd_user_email", userName)
|
||||
return nil
|
||||
}
|
||||
|
||||
user, err := a.pagerduty.FindUserByEmail(ctx, userName)
|
||||
if err != nil {
|
||||
if trace.IsNotFound(err) {
|
||||
log.WithError(err).WithField("pd_user_email", userName).Debug("Skipping the approval: email is not found")
|
||||
log.DebugContext(ctx, "Skipping approval, email is not found",
|
||||
"error", err,
|
||||
"pd_user_email", userName)
|
||||
return nil
|
||||
}
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
ctx, log = logger.WithFields(ctx, logger.Fields{
|
||||
"pd_user_email": user.Email,
|
||||
"pd_user_name": user.Name,
|
||||
})
|
||||
ctx, log = logger.With(ctx,
|
||||
"pd_user_email", user.Email,
|
||||
"pd_user_name", user.Name,
|
||||
)
|
||||
|
||||
services, err := a.pagerduty.FindServicesByNames(ctx, serviceNames)
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
if len(services) == 0 {
|
||||
log.WithField("pd_service_names", serviceNames).Warning("Failed to find any service")
|
||||
log.WarnContext(ctx, "Failed to find any service",
|
||||
"pd_service_names", serviceNames,
|
||||
)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -536,7 +549,7 @@ func (a *App) tryApproveRequest(ctx context.Context, req types.AccessRequest) er
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
if len(escalationPolicyIDs) == 0 {
|
||||
log.Debug("Skipping the approval: user is not on call")
|
||||
log.DebugContext(ctx, "Skipping the approval: user is not on call")
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -561,13 +574,13 @@ func (a *App) tryApproveRequest(ctx context.Context, req types.AccessRequest) er
|
||||
},
|
||||
}); err != nil {
|
||||
if strings.HasSuffix(err.Error(), "has already reviewed this request") {
|
||||
log.Debug("Already reviewed the request")
|
||||
log.DebugContext(ctx, "Already reviewed the request")
|
||||
return nil
|
||||
}
|
||||
return trace.Wrap(err, "submitting access request")
|
||||
}
|
||||
|
||||
log.Info("Successfully submitted a request approval")
|
||||
log.InfoContext(ctx, "Successfully submitted a request approval")
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -599,15 +612,15 @@ func (a *App) resolveIncident(ctx context.Context, reqID string, resolution Reso
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
if !ok {
|
||||
logger.Get(ctx).Debug("Failed to resolve the incident: plugin data is missing")
|
||||
logger.Get(ctx).DebugContext(ctx, "Failed to resolve the incident: plugin data is missing")
|
||||
return nil
|
||||
}
|
||||
|
||||
ctx, log := logger.WithField(ctx, "pd_incident_id", incidentID)
|
||||
ctx, log := logger.With(ctx, "pd_incident_id", incidentID)
|
||||
if err := a.pagerduty.ResolveIncident(ctx, incidentID, resolution); err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
log.Info("Successfully resolved the incident")
|
||||
log.InfoContext(ctx, "Successfully resolved the incident")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -122,7 +122,7 @@ func onAfterPagerDutyResponse(sink common.StatusSink) resty.ResponseMiddleware {
|
||||
defer cancel()
|
||||
|
||||
if err := sink.Emit(ctx, status); err != nil {
|
||||
log.WithError(err).Errorf("Error while emitting PagerDuty plugin status: %v", err)
|
||||
log.ErrorContext(ctx, "Error while emitting PagerDuty plugin status", "error", err)
|
||||
}
|
||||
|
||||
if resp.IsError() {
|
||||
@@ -288,7 +288,7 @@ func (p *Pagerduty) FindUserByEmail(ctx context.Context, userEmail string) (User
|
||||
}
|
||||
|
||||
if len(result.Users) > 0 && result.More {
|
||||
logger.Get(ctx).Warningf("PagerDuty returned too many results when querying by email %q", userEmail)
|
||||
logger.Get(ctx).WarnContext(ctx, "PagerDuty returned too many results when querying user email", "email", userEmail)
|
||||
}
|
||||
|
||||
return User{}, trace.NotFound("failed to find pagerduty user by email %s", userEmail)
|
||||
@@ -387,10 +387,10 @@ func (p *Pagerduty) FilterOnCallPolicies(ctx context.Context, userID string, esc
|
||||
|
||||
if len(filteredIDSet) == 0 {
|
||||
if anyData {
|
||||
logger.Get(ctx).WithFields(logger.Fields{
|
||||
"pd_user_id": userID,
|
||||
"pd_escalation_policy_ids": escalationPolicyIDs,
|
||||
}).Warningf("PagerDuty returned some oncalls array but none of them matched the query")
|
||||
logger.Get(ctx).WarnContext(ctx, "PagerDuty returned some oncalls array but none of them matched the query",
|
||||
"pd_user_id", userID,
|
||||
"pd_escalation_policy_ids", escalationPolicyIDs,
|
||||
)
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
"context"
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
|
||||
"github.com/alecthomas/kingpin/v2"
|
||||
@@ -65,12 +66,13 @@ func main() {
|
||||
if err := run(*path, *debug); err != nil {
|
||||
lib.Bail(err)
|
||||
} else {
|
||||
logger.Standard().Info("Successfully shut down")
|
||||
slog.InfoContext(context.Background(), "Successfully shut down")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func run(configPath string, debug bool) error {
|
||||
ctx := context.Background()
|
||||
conf, err := pagerduty.LoadConfig(configPath)
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
@@ -84,7 +86,7 @@ func run(configPath string, debug bool) error {
|
||||
return err
|
||||
}
|
||||
if debug {
|
||||
logger.Standard().Debugf("DEBUG logging enabled")
|
||||
slog.DebugContext(ctx, "DEBUG logging enabled")
|
||||
}
|
||||
|
||||
app, err := pagerduty.NewApp(*conf)
|
||||
@@ -94,8 +96,9 @@ func run(configPath string, debug bool) error {
|
||||
|
||||
go lib.ServeSignals(app, common.PluginShutdownTimeout)
|
||||
|
||||
logger.Standard().Infof("Starting Teleport Access PagerDuty Plugin %s:%s", teleport.Version, teleport.Gitref)
|
||||
return trace.Wrap(
|
||||
app.Run(context.Background()),
|
||||
slog.InfoContext(ctx, "Starting Teleport Access PagerDuty Plugin",
|
||||
"version", teleport.Version,
|
||||
"git_ref", teleport.Gitref,
|
||||
)
|
||||
return trace.Wrap(app.Run(ctx))
|
||||
}
|
||||
|
||||
@@ -32,7 +32,6 @@ import (
|
||||
|
||||
"github.com/gravitational/trace"
|
||||
"github.com/julienschmidt/httprouter"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/gravitational/teleport/integrations/access/pagerduty"
|
||||
"github.com/gravitational/teleport/integrations/lib/stringset"
|
||||
@@ -565,6 +564,6 @@ func (s *FakePagerduty) CheckNewIncidentNote(ctx context.Context) (FakeIncidentN
|
||||
|
||||
func panicIf(err error) {
|
||||
if err != nil {
|
||||
log.Panicf("%v at %v", err, string(debug.Stack()))
|
||||
panic(fmt.Sprintf("%v at %v", err, string(debug.Stack())))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ package servicenow
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/url"
|
||||
"slices"
|
||||
"strings"
|
||||
@@ -41,6 +42,7 @@ import (
|
||||
"github.com/gravitational/teleport/integrations/lib/logger"
|
||||
"github.com/gravitational/teleport/integrations/lib/watcherjob"
|
||||
"github.com/gravitational/teleport/lib/utils"
|
||||
logutils "github.com/gravitational/teleport/lib/utils/log"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -116,7 +118,7 @@ func (a *App) WaitReady(ctx context.Context) (bool, error) {
|
||||
|
||||
func (a *App) run(ctx context.Context) error {
|
||||
log := logger.Get(ctx)
|
||||
log.Infof("Starting Teleport Access Servicenow Plugin")
|
||||
log.InfoContext(ctx, "Starting Teleport Access Servicenow Plugin")
|
||||
|
||||
if err := a.init(ctx); err != nil {
|
||||
return trace.Wrap(err)
|
||||
@@ -153,9 +155,9 @@ func (a *App) run(ctx context.Context) error {
|
||||
}
|
||||
a.mainJob.SetReady(ok)
|
||||
if ok {
|
||||
log.Info("ServiceNow plugin is ready")
|
||||
log.InfoContext(ctx, "ServiceNow plugin is ready")
|
||||
} else {
|
||||
log.Error("ServiceNow plugin is not ready")
|
||||
log.ErrorContext(ctx, "ServiceNow plugin is not ready")
|
||||
}
|
||||
|
||||
<-watcherJob.Done()
|
||||
@@ -190,25 +192,25 @@ func (a *App) init(ctx context.Context) error {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
log.Debug("Starting API health check...")
|
||||
log.DebugContext(ctx, "Starting API health check")
|
||||
if err = a.serviceNow.CheckHealth(ctx); err != nil {
|
||||
return trace.Wrap(err, "API health check failed")
|
||||
}
|
||||
log.Debug("API health check finished ok")
|
||||
log.DebugContext(ctx, "API health check finished ok")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *App) checkTeleportVersion(ctx context.Context) (proto.PingResponse, error) {
|
||||
log := logger.Get(ctx)
|
||||
log.Debug("Checking Teleport server version")
|
||||
log.DebugContext(ctx, "Checking Teleport server version")
|
||||
|
||||
pong, err := a.teleport.Ping(ctx)
|
||||
if err != nil {
|
||||
if trace.IsNotImplemented(err) {
|
||||
return pong, trace.Wrap(err, "server version must be at least %s", minServerVersion)
|
||||
}
|
||||
log.Error("Unable to get Teleport server version")
|
||||
log.ErrorContext(ctx, "Unable to get Teleport server version")
|
||||
return pong, trace.Wrap(err)
|
||||
}
|
||||
err = utils.CheckMinVersion(pong.ServerVersion, minServerVersion)
|
||||
@@ -233,16 +235,16 @@ func (a *App) handleAccessRequest(ctx context.Context, event types.Event) error
|
||||
}
|
||||
op := event.Type
|
||||
reqID := event.Resource.GetName()
|
||||
ctx, _ = logger.WithField(ctx, "request_id", reqID)
|
||||
ctx, _ = logger.With(ctx, "request_id", reqID)
|
||||
|
||||
switch op {
|
||||
case types.OpPut:
|
||||
ctx, _ = logger.WithField(ctx, "request_op", "put")
|
||||
ctx, _ = logger.With(ctx, "request_op", "put")
|
||||
req, ok := event.Resource.(types.AccessRequest)
|
||||
if !ok {
|
||||
return trace.Errorf("unexpected resource type %T", event.Resource)
|
||||
}
|
||||
ctx, log := logger.WithField(ctx, "request_state", req.GetState().String())
|
||||
ctx, log := logger.With(ctx, "request_state", req.GetState().String())
|
||||
|
||||
var err error
|
||||
switch {
|
||||
@@ -251,21 +253,29 @@ func (a *App) handleAccessRequest(ctx context.Context, event types.Event) error
|
||||
case req.GetState().IsResolved():
|
||||
err = a.onResolvedRequest(ctx, req)
|
||||
default:
|
||||
log.WithField("event", event).Warnf("Unknown request state: %q", req.GetState())
|
||||
log.WarnContext(ctx, "Unknown request state",
|
||||
slog.Group("event",
|
||||
slog.Any("type", logutils.StringerAttr(event.Type)),
|
||||
slog.Group("resource",
|
||||
"kind", event.Resource.GetKind(),
|
||||
"name", event.Resource.GetName(),
|
||||
),
|
||||
),
|
||||
)
|
||||
return nil
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to process request")
|
||||
log.ErrorContext(ctx, "Failed to process request", "error", err)
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
case types.OpDelete:
|
||||
ctx, log := logger.WithField(ctx, "request_op", "delete")
|
||||
ctx, log := logger.With(ctx, "request_op", "delete")
|
||||
|
||||
if err := a.onDeletedRequest(ctx, reqID); err != nil {
|
||||
log.WithError(err).Error("Failed to process deleted request")
|
||||
log.ErrorContext(ctx, "Failed to process deleted request", "error", err)
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
return nil
|
||||
@@ -276,7 +286,7 @@ func (a *App) handleAccessRequest(ctx context.Context, event types.Event) error
|
||||
|
||||
func (a *App) onPendingRequest(ctx context.Context, req types.AccessRequest) error {
|
||||
reqID := req.GetName()
|
||||
log := logger.Get(ctx).WithField("reqId", reqID)
|
||||
log := logger.Get(ctx).With("req_id", reqID)
|
||||
|
||||
resourceNames, err := a.getResourceNames(ctx, req)
|
||||
if err != nil {
|
||||
@@ -303,7 +313,7 @@ func (a *App) onPendingRequest(ctx context.Context, req types.AccessRequest) err
|
||||
}
|
||||
|
||||
if isNew {
|
||||
log.Infof("Creating servicenow incident")
|
||||
log.InfoContext(ctx, "Creating servicenow incident")
|
||||
recipientAssignee := a.accessMonitoringRules.RecipientsFromAccessMonitoringRules(ctx, req)
|
||||
assignees := []string{}
|
||||
recipientAssignee.ForEach(func(r common.Recipient) {
|
||||
@@ -375,8 +385,8 @@ func (a *App) createIncident(ctx context.Context, reqID string, reqData RequestD
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
ctx, log := logger.WithField(ctx, "servicenow_incident_id", data.IncidentID)
|
||||
log.Info("Successfully created Servicenow incident")
|
||||
ctx, log := logger.With(ctx, "servicenow_incident_id", data.IncidentID)
|
||||
log.InfoContext(ctx, "Successfully created Servicenow incident")
|
||||
|
||||
// Save servicenow incident info in plugin data.
|
||||
_, err = a.modifyPluginData(ctx, reqID, func(existing *PluginData) (PluginData, bool) {
|
||||
@@ -420,10 +430,10 @@ func (a *App) postReviewNotes(ctx context.Context, reqID string, reqReviews []ty
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
if !ok {
|
||||
logger.Get(ctx).Debug("Failed to post the note: plugin data is missing")
|
||||
logger.Get(ctx).DebugContext(ctx, "Failed to post the note: plugin data is missing")
|
||||
return nil
|
||||
}
|
||||
ctx, _ = logger.WithField(ctx, "servicenow_incident_id", data.IncidentID)
|
||||
ctx, _ = logger.With(ctx, "servicenow_incident_id", data.IncidentID)
|
||||
|
||||
slice := reqReviews[oldCount:]
|
||||
if len(slice) == 0 {
|
||||
@@ -445,22 +455,28 @@ func (a *App) tryApproveRequest(ctx context.Context, req types.AccessRequest) er
|
||||
|
||||
serviceNames, err := a.getOnCallServiceNames(req)
|
||||
if err != nil {
|
||||
logger.Get(ctx).Debugf("Skipping the approval: %s", err)
|
||||
logger.Get(ctx).DebugContext(ctx, "Skipping the approval", "error", err)
|
||||
return nil
|
||||
}
|
||||
log.Debugf("Checking the following shifts to see if the requester is on-call: %s", serviceNames)
|
||||
log.DebugContext(ctx, "Checking the shifts to see if the requester is on-call", "shifts", serviceNames)
|
||||
|
||||
onCallUsers, err := a.getOnCallUsers(ctx, serviceNames)
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
log.Debugf("Users on-call are: %s", onCallUsers)
|
||||
log.DebugContext(ctx, "Users on-call are", "on_call_users", onCallUsers)
|
||||
|
||||
if userIsOnCall := slices.Contains(onCallUsers, req.GetUser()); !userIsOnCall {
|
||||
log.Debugf("User %q is not on-call, not approving the request %q.", req.GetUser(), req.GetName())
|
||||
log.DebugContext(ctx, "User is not on-call, not approving the request",
|
||||
"user", req.GetUser(),
|
||||
"request", req.GetName(),
|
||||
)
|
||||
return nil
|
||||
}
|
||||
log.Debugf("User %q is on-call. Auto-approving the request %q.", req.GetUser(), req.GetName())
|
||||
log.DebugContext(ctx, "User is on-call, auto-approving the request",
|
||||
"user", req.GetUser(),
|
||||
"request", req.GetName(),
|
||||
)
|
||||
if _, err := a.teleport.SubmitAccessReview(ctx, types.AccessReviewSubmission{
|
||||
RequestID: req.GetName(),
|
||||
Review: types.AccessReview{
|
||||
@@ -474,12 +490,12 @@ func (a *App) tryApproveRequest(ctx context.Context, req types.AccessRequest) er
|
||||
},
|
||||
}); err != nil {
|
||||
if strings.HasSuffix(err.Error(), "has already reviewed this request") {
|
||||
log.Debug("Already reviewed the request")
|
||||
log.DebugContext(ctx, "Already reviewed the request")
|
||||
return nil
|
||||
}
|
||||
return trace.Wrap(err, "submitting access request")
|
||||
}
|
||||
log.Info("Successfully submitted a request approval")
|
||||
log.InfoContext(ctx, "Successfully submitted a request approval")
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -490,7 +506,7 @@ func (a *App) getOnCallUsers(ctx context.Context, serviceNames []string) ([]stri
|
||||
respondersResult, err := a.serviceNow.GetOnCall(ctx, scheduleName)
|
||||
if err != nil {
|
||||
if trace.IsNotFound(err) {
|
||||
log.WithError(err).Error("Failed to retrieve responder from schedule")
|
||||
log.ErrorContext(ctx, "Failed to retrieve responder from schedule", "error", err)
|
||||
continue
|
||||
}
|
||||
return nil, trace.Wrap(err)
|
||||
@@ -528,15 +544,15 @@ func (a *App) resolveIncident(ctx context.Context, reqID string, resolution Reso
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
if !ok {
|
||||
logger.Get(ctx).Debug("Failed to resolve the incident: plugin data is missing")
|
||||
logger.Get(ctx).DebugContext(ctx, "Failed to resolve the incident: plugin data is missing")
|
||||
return nil
|
||||
}
|
||||
|
||||
ctx, log := logger.WithField(ctx, "servicenow_incident_id", incidentID)
|
||||
ctx, log := logger.With(ctx, "servicenow_incident_id", incidentID)
|
||||
if err := a.serviceNow.ResolveIncident(ctx, incidentID, resolution); err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
log.Info("Successfully resolved the incident")
|
||||
log.InfoContext(ctx, "Successfully resolved the incident")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -287,7 +287,10 @@ func (snc *Client) CheckHealth(ctx context.Context) error {
|
||||
}
|
||||
if err := snc.StatusSink.Emit(ctx, &types.PluginStatusV1{Code: code}); err != nil {
|
||||
log := logger.Get(resp.Request.Context())
|
||||
log.WithError(err).WithField("code", resp.StatusCode()).Errorf("Error while emitting servicenow plugin status: %v", err)
|
||||
log.ErrorContext(ctx, "Error while emitting servicenow plugin status",
|
||||
"error", err,
|
||||
"code", resp.StatusCode(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,6 @@ import (
|
||||
"github.com/google/uuid"
|
||||
"github.com/gravitational/trace"
|
||||
"github.com/julienschmidt/httprouter"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/gravitational/teleport/integrations/access/servicenow"
|
||||
"github.com/gravitational/teleport/integrations/lib/stringset"
|
||||
@@ -284,6 +283,6 @@ func (s *FakeServiceNow) getOnCall(rotationName string) []string {
|
||||
|
||||
func panicIf(err error) {
|
||||
if err != nil {
|
||||
log.Panicf("%v at %v", err, string(debug.Stack()))
|
||||
panic(fmt.Sprintf("%v at %v", err, string(debug.Stack())))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,6 @@ import (
|
||||
"github.com/go-resty/resty/v2"
|
||||
"github.com/gravitational/trace"
|
||||
"github.com/jonboulle/clockwork"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/gravitational/teleport/api/types"
|
||||
"github.com/gravitational/teleport/api/types/accesslist"
|
||||
@@ -37,6 +36,7 @@ import (
|
||||
"github.com/gravitational/teleport/integrations/access/accessrequest"
|
||||
"github.com/gravitational/teleport/integrations/access/common"
|
||||
"github.com/gravitational/teleport/integrations/lib"
|
||||
"github.com/gravitational/teleport/integrations/lib/logger"
|
||||
pd "github.com/gravitational/teleport/integrations/lib/plugindata"
|
||||
)
|
||||
|
||||
@@ -68,7 +68,7 @@ func onAfterResponseSlack(sink common.StatusSink) func(_ *resty.Client, resp *re
|
||||
ctx, cancel := context.WithTimeout(context.Background(), statusEmitTimeout)
|
||||
defer cancel()
|
||||
if err := sink.Emit(ctx, status); err != nil {
|
||||
log.Errorf("Error while emitting plugin status: %v", err)
|
||||
logger.Get(ctx).ErrorContext(ctx, "Error while emitting plugin status", "error", err)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -139,7 +139,7 @@ func (b Bot) BroadcastAccessRequestMessage(ctx context.Context, recipients []com
|
||||
// the case with most SSO setups.
|
||||
userRecipient, err := b.FetchRecipient(ctx, reqData.User)
|
||||
if err != nil {
|
||||
log.Warningf("Unable to find user %s in Slack, will not be able to notify.", reqData.User)
|
||||
logger.Get(ctx).WarnContext(ctx, "Unable to find user in Slack, will not be able to notify", "user", reqData.User)
|
||||
}
|
||||
|
||||
// Include the user in the list of recipients if it exists.
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
"context"
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
|
||||
"github.com/alecthomas/kingpin/v2"
|
||||
@@ -65,12 +66,13 @@ func main() {
|
||||
if err := run(*path, *debug); err != nil {
|
||||
lib.Bail(err)
|
||||
} else {
|
||||
logger.Standard().Info("Successfully shut down")
|
||||
slog.InfoContext(context.Background(), "Successfully shut down")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func run(configPath string, debug bool) error {
|
||||
ctx := context.Background()
|
||||
conf, err := slack.LoadSlackConfig(configPath)
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
@@ -84,14 +86,15 @@ func run(configPath string, debug bool) error {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
if debug {
|
||||
logger.Standard().Debugf("DEBUG logging enabled")
|
||||
slog.DebugContext(ctx, "DEBUG logging enabled")
|
||||
}
|
||||
|
||||
app := slack.NewSlackApp(conf)
|
||||
go lib.ServeSignals(app, common.PluginShutdownTimeout)
|
||||
|
||||
logger.Standard().Infof("Starting Teleport Access Slack Plugin %s:%s", teleport.Version, teleport.Gitref)
|
||||
return trace.Wrap(
|
||||
app.Run(context.Background()),
|
||||
slog.InfoContext(ctx, "Starting Teleport Access Slack Plugin",
|
||||
"version", teleport.Version,
|
||||
"git_ref", teleport.Gitref,
|
||||
)
|
||||
return trace.Wrap(app.Run(ctx))
|
||||
}
|
||||
|
||||
@@ -31,7 +31,6 @@ import (
|
||||
|
||||
"github.com/gravitational/trace"
|
||||
"github.com/julienschmidt/httprouter"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/gravitational/teleport/integrations/access/slack"
|
||||
)
|
||||
@@ -315,6 +314,6 @@ func (s *FakeSlack) CheckMessageUpdateByResponding(ctx context.Context) (slack.M
|
||||
|
||||
func panicIf(err error) {
|
||||
if err != nil {
|
||||
log.Panicf("%v at %v", err, string(debug.Stack()))
|
||||
panic(fmt.Sprintf("%v at %v", err, string(debug.Stack())))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,8 +31,6 @@ import (
|
||||
|
||||
"github.com/gravitational/trace"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/gravitational/teleport/integrations/lib/logger"
|
||||
)
|
||||
|
||||
type FakeFluentd struct {
|
||||
@@ -150,7 +148,6 @@ func (f *FakeFluentd) GetURL() string {
|
||||
func (f *FakeFluentd) Respond(w http.ResponseWriter, r *http.Request) {
|
||||
req, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
logger.Standard().WithError(err).Error("FakeFluentd Respond() failed to read body")
|
||||
fmt.Fprintln(w, "NOK")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -46,8 +46,6 @@ const (
|
||||
)
|
||||
|
||||
func main() {
|
||||
// This initializes the legacy logrus logger. This has been kept in place
|
||||
// in case any of the dependencies are still using logrus.
|
||||
logger.Init()
|
||||
|
||||
ctx := kong.Parse(
|
||||
@@ -64,17 +62,13 @@ func main() {
|
||||
Format: "text",
|
||||
}
|
||||
if cli.Debug {
|
||||
enableLogDebug()
|
||||
logCfg.Severity = "debug"
|
||||
}
|
||||
log, err := logCfg.NewSLogLogger()
|
||||
if err != nil {
|
||||
fmt.Println(trace.DebugReport(trace.Wrap(err, "initializing logger")))
|
||||
|
||||
if err := logger.Setup(logCfg); err != nil {
|
||||
fmt.Println(trace.DebugReport(err))
|
||||
os.Exit(-1)
|
||||
}
|
||||
// Whilst this package mostly dependency injects slog, upstream dependencies
|
||||
// may still use the default slog logger.
|
||||
slog.SetDefault(log)
|
||||
|
||||
switch {
|
||||
case ctx.Command() == "version":
|
||||
@@ -86,25 +80,16 @@ func main() {
|
||||
os.Exit(-1)
|
||||
}
|
||||
case ctx.Command() == "start":
|
||||
err := start(log)
|
||||
err := start(slog.Default())
|
||||
|
||||
if err != nil {
|
||||
lib.Bail(err)
|
||||
} else {
|
||||
log.InfoContext(context.TODO(), "Successfully shut down")
|
||||
slog.InfoContext(context.TODO(), "Successfully shut down")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// turn on log debugging
|
||||
func enableLogDebug() {
|
||||
err := logger.Setup(logger.Config{Severity: "debug", Output: "stderr"})
|
||||
if err != nil {
|
||||
fmt.Println(trace.DebugReport(err))
|
||||
os.Exit(-1)
|
||||
}
|
||||
}
|
||||
|
||||
// start spawns the main process
|
||||
func start(log *slog.Logger) error {
|
||||
app, err := NewApp(&cli.Start, log)
|
||||
|
||||
@@ -19,22 +19,24 @@
|
||||
package lib
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"log/slog"
|
||||
"os"
|
||||
|
||||
"github.com/gravitational/trace"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// Bail exits with nonzero exit code and prints an error to a log.
|
||||
func Bail(err error) {
|
||||
ctx := context.Background()
|
||||
var agg trace.Aggregate
|
||||
if errors.As(trace.Unwrap(err), &agg) {
|
||||
for i, err := range agg.Errors() {
|
||||
log.WithError(err).Errorf("Terminating with fatal error [%d]...", i+1)
|
||||
slog.ErrorContext(ctx, "Terminating with fatal error", "error_number", i+1, "error", err)
|
||||
}
|
||||
} else {
|
||||
log.WithError(err).Error("Terminating with fatal error...")
|
||||
slog.ErrorContext(ctx, "Terminating with fatal error", "error", err)
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
@@ -22,12 +22,12 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"log/slog"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gravitational/trace"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"google.golang.org/grpc"
|
||||
grpcbackoff "google.golang.org/grpc/backoff"
|
||||
|
||||
@@ -137,7 +137,7 @@ func NewIdentityFileWatcher(ctx context.Context, path string, interval time.Dura
|
||||
}
|
||||
|
||||
if err := dynamicCred.Reload(); err != nil {
|
||||
log.WithError(err).Error("Failed to reload identity file from disk.")
|
||||
slog.ErrorContext(ctx, "Failed to reload identity file from disk", "error", err)
|
||||
}
|
||||
timer.Reset(interval)
|
||||
}
|
||||
@@ -152,7 +152,7 @@ func (cfg TeleportConfig) NewClient(ctx context.Context) (*client.Client, error)
|
||||
case cfg.Addr != "":
|
||||
addr = cfg.Addr
|
||||
case cfg.AuthServer != "":
|
||||
log.Warn("Configuration setting `auth_server` is deprecated, consider to change it to `addr`")
|
||||
slog.WarnContext(ctx, "Configuration setting `auth_server` is deprecated, consider to change it to `addr`")
|
||||
addr = cfg.AuthServer
|
||||
}
|
||||
|
||||
@@ -173,13 +173,13 @@ func (cfg TeleportConfig) NewClient(ctx context.Context) (*client.Client, error)
|
||||
}
|
||||
|
||||
if validCred, err := credentials.CheckIfExpired(creds); err != nil {
|
||||
log.Warn(err)
|
||||
slog.WarnContext(ctx, "found expired credentials", "error", err)
|
||||
if !validCred {
|
||||
return nil, trace.BadParameter(
|
||||
"No valid credentials found, this likely means credentials are expired. In this case, please sign new credentials and increase their TTL if needed.",
|
||||
)
|
||||
}
|
||||
log.Info("At least one non-expired credential has been found, continuing startup")
|
||||
slog.InfoContext(ctx, "At least one non-expired credential has been found, continuing startup")
|
||||
}
|
||||
|
||||
bk := grpcbackoff.DefaultConfig
|
||||
|
||||
@@ -26,7 +26,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/gravitational/trace"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/gravitational/teleport/api/client"
|
||||
"github.com/gravitational/teleport/api/client/proto"
|
||||
@@ -106,9 +105,9 @@ func (b *EmbeddedBot) start(ctx context.Context) {
|
||||
go func() {
|
||||
err := bot.Run(botCtx)
|
||||
if err != nil {
|
||||
log.Errorf("bot exited with error: %s", err)
|
||||
slog.ErrorContext(botCtx, "bot exited with error", "error", err)
|
||||
} else {
|
||||
log.Infof("bot exited without error")
|
||||
slog.InfoContext(botCtx, "bot exited without error")
|
||||
}
|
||||
b.errCh <- trace.Wrap(err)
|
||||
}()
|
||||
@@ -142,10 +141,10 @@ func (b *EmbeddedBot) waitForCredentials(ctx context.Context, deadline time.Dura
|
||||
|
||||
select {
|
||||
case <-waitCtx.Done():
|
||||
log.Warn("context canceled while waiting for the bot client")
|
||||
slog.WarnContext(ctx, "context canceled while waiting for the bot client")
|
||||
return nil, trace.Wrap(ctx.Err())
|
||||
case <-b.credential.Ready():
|
||||
log.Infof("credential ready")
|
||||
slog.InfoContext(ctx, "credential ready")
|
||||
}
|
||||
|
||||
return b.credential, nil
|
||||
@@ -177,7 +176,7 @@ func (b *EmbeddedBot) StartAndWaitForCredentials(ctx context.Context, deadline t
|
||||
// buildClient reads tbot's memory disttination, retrieves the certificates
|
||||
// and builds a new Teleport client using those certs.
|
||||
func (b *EmbeddedBot) buildClient(ctx context.Context) (*client.Client, error) {
|
||||
log.Infof("Building a new client to connect to %s", b.cfg.AuthServer)
|
||||
slog.InfoContext(ctx, "Building a new client to connect to cluster", "auth_server_address", b.cfg.AuthServer)
|
||||
c, err := client.New(ctx, client.Config{
|
||||
Addrs: []string{b.cfg.AuthServer},
|
||||
Credentials: []client.Credentials{b.credential},
|
||||
|
||||
@@ -24,6 +24,7 @@ import (
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
@@ -33,7 +34,8 @@ import (
|
||||
|
||||
"github.com/gravitational/trace"
|
||||
"github.com/julienschmidt/httprouter"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
logutils "github.com/gravitational/teleport/lib/utils/log"
|
||||
)
|
||||
|
||||
// TLSConfig stores TLS configuration for a http service
|
||||
@@ -178,7 +180,7 @@ func NewHTTP(config HTTPConfig) (*HTTP, error) {
|
||||
if verify := config.TLS.VerifyClientCertificateFunc; verify != nil {
|
||||
tlsConfig.VerifyPeerCertificate = func(_ [][]byte, chains [][]*x509.Certificate) error {
|
||||
if err := verify(chains); err != nil {
|
||||
log.WithError(err).Error("HTTPS client certificate verification failed")
|
||||
slog.ErrorContext(context.Background(), "HTTPS client certificate verification failed", "error", err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
@@ -217,7 +219,7 @@ func BuildURLPath(args ...interface{}) string {
|
||||
|
||||
// ListenAndServe runs a http(s) server on a provided port.
|
||||
func (h *HTTP) ListenAndServe(ctx context.Context) error {
|
||||
defer log.Debug("HTTP server terminated")
|
||||
defer slog.DebugContext(ctx, "HTTP server terminated")
|
||||
var err error
|
||||
|
||||
h.server.BaseContext = func(_ net.Listener) context.Context {
|
||||
@@ -256,10 +258,10 @@ func (h *HTTP) ListenAndServe(ctx context.Context) error {
|
||||
}
|
||||
|
||||
if h.Insecure {
|
||||
log.Debugf("Starting insecure HTTP server on %s", addr)
|
||||
slog.DebugContext(ctx, "Starting insecure HTTP server", "listen_addr", logutils.StringerAttr(addr))
|
||||
err = h.server.Serve(listener)
|
||||
} else {
|
||||
log.Debugf("Starting secure HTTPS server on %s", addr)
|
||||
slog.DebugContext(ctx, "Starting secure HTTPS server", "listen_addr", logutils.StringerAttr(addr))
|
||||
err = h.server.ServeTLS(listener, h.CertFile, h.KeyFile)
|
||||
}
|
||||
if errors.Is(err, http.ErrServerClosed) {
|
||||
@@ -288,7 +290,7 @@ func (h *HTTP) ServiceJob() ServiceJob {
|
||||
return NewServiceJob(func(ctx context.Context) error {
|
||||
MustGetProcess(ctx).OnTerminate(func(ctx context.Context) error {
|
||||
if err := h.ShutdownWithTimeout(ctx, time.Second*5); err != nil {
|
||||
log.Error("HTTP server graceful shutdown failed")
|
||||
slog.ErrorContext(ctx, "HTTP server graceful shutdown failed")
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -20,16 +20,11 @@ package logger
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"io/fs"
|
||||
"log/slog"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/gravitational/trace"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/gravitational/teleport"
|
||||
"github.com/gravitational/teleport/lib/utils"
|
||||
logutils "github.com/gravitational/teleport/lib/utils/log"
|
||||
)
|
||||
@@ -41,8 +36,6 @@ type Config struct {
|
||||
Format string `toml:"format"`
|
||||
}
|
||||
|
||||
type Fields = log.Fields
|
||||
|
||||
type contextKey struct{}
|
||||
|
||||
var extraFields = []string{logutils.LevelField, logutils.ComponentField, logutils.CallerField}
|
||||
@@ -50,179 +43,50 @@ var extraFields = []string{logutils.LevelField, logutils.ComponentField, logutil
|
||||
// Init sets up logger for a typical daemon scenario until configuration
|
||||
// file is parsed
|
||||
func Init() {
|
||||
formatter := &logutils.TextFormatter{
|
||||
EnableColors: utils.IsTerminal(os.Stderr),
|
||||
ComponentPadding: 1, // We don't use components so strip the padding
|
||||
ExtraFields: extraFields,
|
||||
}
|
||||
|
||||
log.SetOutput(os.Stderr)
|
||||
if err := formatter.CheckAndSetDefaults(); err != nil {
|
||||
log.WithError(err).Error("unable to create text log formatter")
|
||||
return
|
||||
}
|
||||
|
||||
log.SetFormatter(formatter)
|
||||
enableColors := utils.IsTerminal(os.Stderr)
|
||||
logutils.Initialize(logutils.Config{
|
||||
Severity: slog.LevelInfo.String(),
|
||||
Format: "text",
|
||||
ExtraFields: extraFields,
|
||||
EnableColors: enableColors,
|
||||
Padding: 1,
|
||||
})
|
||||
}
|
||||
|
||||
func Setup(conf Config) error {
|
||||
var enableColors bool
|
||||
switch conf.Output {
|
||||
case "stderr", "error", "2":
|
||||
log.SetOutput(os.Stderr)
|
||||
enableColors = utils.IsTerminal(os.Stderr)
|
||||
case "", "stdout", "out", "1":
|
||||
log.SetOutput(os.Stdout)
|
||||
enableColors = utils.IsTerminal(os.Stdout)
|
||||
default:
|
||||
// assume it's a file path:
|
||||
logFile, err := os.Create(conf.Output)
|
||||
if err != nil {
|
||||
return trace.Wrap(err, "failed to create the log file")
|
||||
}
|
||||
log.SetOutput(logFile)
|
||||
}
|
||||
|
||||
switch strings.ToLower(conf.Severity) {
|
||||
case "info":
|
||||
log.SetLevel(log.InfoLevel)
|
||||
case "err", "error":
|
||||
log.SetLevel(log.ErrorLevel)
|
||||
case "debug":
|
||||
log.SetLevel(log.DebugLevel)
|
||||
case "warn", "warning":
|
||||
log.SetLevel(log.WarnLevel)
|
||||
case "trace":
|
||||
log.SetLevel(log.TraceLevel)
|
||||
default:
|
||||
return trace.BadParameter("unsupported logger severity: '%v'", conf.Severity)
|
||||
}
|
||||
|
||||
return nil
|
||||
_, _, err := logutils.Initialize(logutils.Config{
|
||||
Output: conf.Output,
|
||||
Severity: conf.Severity,
|
||||
Format: conf.Format,
|
||||
ExtraFields: extraFields,
|
||||
EnableColors: enableColors,
|
||||
Padding: 1,
|
||||
})
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
// NewSLogLogger builds a slog.Logger from the logger.Config.
|
||||
// TODO(tross): Defer logging initialization to logutils.Initialize and use the
|
||||
// global slog loggers once integrations has been updated to use slog.
|
||||
func (conf Config) NewSLogLogger() (*slog.Logger, error) {
|
||||
const (
|
||||
// logFileDefaultMode is the preferred permissions mode for log file.
|
||||
logFileDefaultMode fs.FileMode = 0o644
|
||||
// logFileDefaultFlag is the preferred flags set to log file.
|
||||
logFileDefaultFlag = os.O_WRONLY | os.O_CREATE | os.O_APPEND
|
||||
)
|
||||
|
||||
var w io.Writer
|
||||
switch conf.Output {
|
||||
case "":
|
||||
w = logutils.NewSharedWriter(os.Stderr)
|
||||
case "stderr", "error", "2":
|
||||
w = logutils.NewSharedWriter(os.Stderr)
|
||||
case "stdout", "out", "1":
|
||||
w = logutils.NewSharedWriter(os.Stdout)
|
||||
case teleport.Syslog:
|
||||
w = os.Stderr
|
||||
sw, err := logutils.NewSyslogWriter()
|
||||
if err != nil {
|
||||
slog.Default().ErrorContext(context.Background(), "Failed to switch logging to syslog", "error", err)
|
||||
break
|
||||
}
|
||||
|
||||
// If syslog output has been configured and is supported by the operating system,
|
||||
// then the shared writer is not needed because the syslog writer is already
|
||||
// protected with a mutex.
|
||||
w = sw
|
||||
default:
|
||||
// Assume this is a file path.
|
||||
sharedWriter, err := logutils.NewFileSharedWriter(conf.Output, logFileDefaultFlag, logFileDefaultMode)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err, "failed to init the log file shared writer")
|
||||
}
|
||||
w = logutils.NewWriterFinalizer[*logutils.FileSharedWriter](sharedWriter)
|
||||
if err := sharedWriter.RunWatcherReopen(context.Background()); err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
}
|
||||
|
||||
level := new(slog.LevelVar)
|
||||
switch strings.ToLower(conf.Severity) {
|
||||
case "", "info":
|
||||
level.Set(slog.LevelInfo)
|
||||
case "err", "error":
|
||||
level.Set(slog.LevelError)
|
||||
case teleport.DebugLevel:
|
||||
level.Set(slog.LevelDebug)
|
||||
case "warn", "warning":
|
||||
level.Set(slog.LevelWarn)
|
||||
case "trace":
|
||||
level.Set(logutils.TraceLevel)
|
||||
default:
|
||||
return nil, trace.BadParameter("unsupported logger severity: %q", conf.Severity)
|
||||
}
|
||||
|
||||
configuredFields, err := logutils.ValidateFields(extraFields)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
var slogLogger *slog.Logger
|
||||
switch strings.ToLower(conf.Format) {
|
||||
case "":
|
||||
fallthrough // not set. defaults to 'text'
|
||||
case "text":
|
||||
enableColors := utils.IsTerminal(os.Stderr)
|
||||
slogLogger = slog.New(logutils.NewSlogTextHandler(w, logutils.SlogTextHandlerConfig{
|
||||
Level: level,
|
||||
EnableColors: enableColors,
|
||||
ConfiguredFields: configuredFields,
|
||||
}))
|
||||
slog.SetDefault(slogLogger)
|
||||
case "json":
|
||||
slogLogger = slog.New(logutils.NewSlogJSONHandler(w, logutils.SlogJSONHandlerConfig{
|
||||
Level: level,
|
||||
ConfiguredFields: configuredFields,
|
||||
}))
|
||||
slog.SetDefault(slogLogger)
|
||||
default:
|
||||
return nil, trace.BadParameter("unsupported log output format : %q", conf.Format)
|
||||
}
|
||||
|
||||
return slogLogger, nil
|
||||
}
|
||||
|
||||
func WithLogger(ctx context.Context, logger log.FieldLogger) context.Context {
|
||||
return withLogger(ctx, logger)
|
||||
}
|
||||
|
||||
func withLogger(ctx context.Context, logger log.FieldLogger) context.Context {
|
||||
func WithLogger(ctx context.Context, logger *slog.Logger) context.Context {
|
||||
return context.WithValue(ctx, contextKey{}, logger)
|
||||
}
|
||||
|
||||
func WithField(ctx context.Context, key string, value interface{}) (context.Context, log.FieldLogger) {
|
||||
logger := Get(ctx).WithField(key, value)
|
||||
return withLogger(ctx, logger), logger
|
||||
func With(ctx context.Context, args ...any) (context.Context, *slog.Logger) {
|
||||
logger := Get(ctx).With(args...)
|
||||
return WithLogger(ctx, logger), logger
|
||||
}
|
||||
|
||||
func WithFields(ctx context.Context, logFields Fields) (context.Context, log.FieldLogger) {
|
||||
logger := Get(ctx).WithFields(logFields)
|
||||
return withLogger(ctx, logger), logger
|
||||
}
|
||||
|
||||
func SetField(ctx context.Context, key string, value interface{}) context.Context {
|
||||
ctx, _ = WithField(ctx, key, value)
|
||||
return ctx
|
||||
}
|
||||
|
||||
func SetFields(ctx context.Context, logFields Fields) context.Context {
|
||||
ctx, _ = WithFields(ctx, logFields)
|
||||
return ctx
|
||||
}
|
||||
|
||||
func Get(ctx context.Context) log.FieldLogger {
|
||||
if logger, ok := ctx.Value(contextKey{}).(log.FieldLogger); ok && logger != nil {
|
||||
func Get(ctx context.Context) *slog.Logger {
|
||||
if logger, ok := ctx.Value(contextKey{}).(*slog.Logger); ok && logger != nil {
|
||||
return logger
|
||||
}
|
||||
|
||||
return Standard()
|
||||
}
|
||||
|
||||
func Standard() log.FieldLogger {
|
||||
return log.StandardLogger()
|
||||
return slog.Default()
|
||||
}
|
||||
|
||||
@@ -20,12 +20,11 @@ package lib
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type Terminable interface {
|
||||
@@ -48,9 +47,9 @@ func ServeSignals(app Terminable, shutdownTimeout time.Duration) {
|
||||
gracefulShutdown := func() {
|
||||
tctx, tcancel := context.WithTimeout(ctx, shutdownTimeout)
|
||||
defer tcancel()
|
||||
log.Infof("Attempting graceful shutdown...")
|
||||
slog.InfoContext(tctx, "Attempting graceful shutdown")
|
||||
if err := app.Shutdown(tctx); err != nil {
|
||||
log.Infof("Graceful shutdown failed. Trying fast shutdown...")
|
||||
slog.InfoContext(tctx, "Graceful shutdown failed, attempting fast shutdown")
|
||||
app.Close()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import (
|
||||
|
||||
"github.com/gravitational/teleport/api/types"
|
||||
"github.com/gravitational/teleport/integrations/lib/logger"
|
||||
logutils "github.com/gravitational/teleport/lib/utils/log"
|
||||
)
|
||||
|
||||
var regexpStatusCAPin = regexp.MustCompile(`CA pin +(sha256:[a-zA-Z0-9]+)`)
|
||||
@@ -59,10 +60,14 @@ func (tctl Tctl) Sign(ctx context.Context, username, format, outPath string) err
|
||||
outPath,
|
||||
)
|
||||
cmd := exec.CommandContext(ctx, tctl.cmd(), args...)
|
||||
log.Debugf("Running %s", cmd)
|
||||
log.DebugContext(ctx, "Running tctl auth sign", "command", logutils.StringerAttr(cmd))
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
log.WithError(err).WithField("args", args).Debug("tctl auth sign failed:", string(output))
|
||||
log.DebugContext(ctx, "tctl auth sign failed",
|
||||
"error", err,
|
||||
"args", args,
|
||||
"command_output", string(output),
|
||||
)
|
||||
return trace.Wrap(err, "tctl auth sign failed")
|
||||
}
|
||||
return nil
|
||||
@@ -73,7 +78,7 @@ func (tctl Tctl) Create(ctx context.Context, resources []types.Resource) error {
|
||||
log := logger.Get(ctx)
|
||||
args := append(tctl.baseArgs(), "create")
|
||||
cmd := exec.CommandContext(ctx, tctl.cmd(), args...)
|
||||
log.Debugf("Running %s", cmd)
|
||||
log.DebugContext(ctx, "Running tctl create", "command", logutils.StringerAttr(cmd))
|
||||
stdinPipe, err := cmd.StdinPipe()
|
||||
if err != nil {
|
||||
return trace.Wrap(err, "failed to get stdin pipe")
|
||||
@@ -81,16 +86,19 @@ func (tctl Tctl) Create(ctx context.Context, resources []types.Resource) error {
|
||||
go func() {
|
||||
defer func() {
|
||||
if err := stdinPipe.Close(); err != nil {
|
||||
log.WithError(trace.Wrap(err)).Error("Failed to close stdin pipe")
|
||||
log.ErrorContext(ctx, "Failed to close stdin pipe", "error", err)
|
||||
}
|
||||
}()
|
||||
if err := writeResourcesYAML(stdinPipe, resources); err != nil {
|
||||
log.WithError(trace.Wrap(err)).Error("Failed to serialize resources stdin")
|
||||
log.ErrorContext(ctx, "Failed to serialize resources stdin", "error", err)
|
||||
}
|
||||
}()
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
log.WithError(err).Debug("tctl create failed:", string(output))
|
||||
log.DebugContext(ctx, "tctl create failed",
|
||||
"error", err,
|
||||
"command_output", string(output),
|
||||
)
|
||||
return trace.Wrap(err, "tctl create failed")
|
||||
}
|
||||
return nil
|
||||
@@ -102,7 +110,7 @@ func (tctl Tctl) GetAll(ctx context.Context, query string) ([]types.Resource, er
|
||||
args := append(tctl.baseArgs(), "get", query)
|
||||
cmd := exec.CommandContext(ctx, tctl.cmd(), args...)
|
||||
|
||||
log.Debugf("Running %s", cmd)
|
||||
log.DebugContext(ctx, "Running tctl get", "command", logutils.StringerAttr(cmd))
|
||||
stdoutPipe, err := cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err, "failed to get stdout")
|
||||
@@ -140,7 +148,7 @@ func (tctl Tctl) GetCAPin(ctx context.Context) (string, error) {
|
||||
args := append(tctl.baseArgs(), "status")
|
||||
cmd := exec.CommandContext(ctx, tctl.cmd(), args...)
|
||||
|
||||
log.Debugf("Running %s", cmd)
|
||||
log.DebugContext(ctx, "Running tctl status", "command", logutils.StringerAttr(cmd))
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
return "", trace.Wrap(err, "failed to get auth status")
|
||||
|
||||
@@ -93,7 +93,7 @@ func (s *Suite) initContexts(oldT *testing.T, newT *testing.T) {
|
||||
} else {
|
||||
baseCtx = context.Background()
|
||||
}
|
||||
baseCtx, _ = logger.WithField(baseCtx, "test", newT.Name())
|
||||
baseCtx, _ = logger.With(baseCtx, "test", newT.Name())
|
||||
baseCtx, cancel := context.WithCancel(baseCtx)
|
||||
newT.Cleanup(cancel)
|
||||
|
||||
@@ -163,7 +163,7 @@ func (s *Suite) StartApp(app AppI) {
|
||||
if err := app.Run(ctx); err != nil {
|
||||
// We're in a goroutine so we can't just require.NoError(t, err).
|
||||
// All we can do is to log an error.
|
||||
logger.Get(ctx).WithError(err).Error("Application failed")
|
||||
logger.Get(ctx).ErrorContext(ctx, "Application failed", "error", err)
|
||||
}
|
||||
}()
|
||||
|
||||
|
||||
@@ -130,23 +130,23 @@ func newJobWithEvents(events types.Events, config Config, fn EventFunc, watchIni
|
||||
if config.FailFast {
|
||||
return trace.WrapWithMessage(err, "Connection problem detected. Exiting as fail fast is on.")
|
||||
}
|
||||
log.WithError(err).Error("Connection problem detected. Attempting to reconnect.")
|
||||
log.ErrorContext(ctx, "Connection problem detected, attempting to reconnect", "error", err)
|
||||
case errors.Is(err, io.EOF):
|
||||
if config.FailFast {
|
||||
return trace.WrapWithMessage(err, "Watcher stream closed. Exiting as fail fast is on.")
|
||||
}
|
||||
log.WithError(err).Error("Watcher stream closed. Attempting to reconnect.")
|
||||
log.ErrorContext(ctx, "Watcher stream closed attempting to reconnect", "error", err)
|
||||
case lib.IsCanceled(err):
|
||||
log.Debug("Watcher context is canceled")
|
||||
log.DebugContext(ctx, "Watcher context is canceled")
|
||||
return trace.Wrap(err)
|
||||
default:
|
||||
log.WithError(err).Error("Watcher event loop failed")
|
||||
log.ErrorContext(ctx, "Watcher event loop failed", "error", err)
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
// To mitigate a potentially aggressive retry loop, we wait
|
||||
if err := bk.Do(ctx); err != nil {
|
||||
log.Debug("Watcher context was canceled while waiting before a reconnection")
|
||||
log.DebugContext(ctx, "Watcher context was canceled while waiting before a reconnection")
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
}
|
||||
@@ -162,7 +162,7 @@ func (job job) watchEvents(ctx context.Context) error {
|
||||
}
|
||||
defer func() {
|
||||
if err := watcher.Close(); err != nil {
|
||||
logger.Get(ctx).WithError(err).Error("Failed to close a watcher")
|
||||
logger.Get(ctx).ErrorContext(ctx, "Failed to close a watcher", "error", err)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -170,7 +170,7 @@ func (job job) watchEvents(ctx context.Context) error {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
logger.Get(ctx).Debug("Watcher connected")
|
||||
logger.Get(ctx).DebugContext(ctx, "Watcher connected")
|
||||
job.SetReady(true)
|
||||
|
||||
for {
|
||||
@@ -253,7 +253,7 @@ func (job job) eventLoop(ctx context.Context) error {
|
||||
event := *eventPtr
|
||||
resource := event.Resource
|
||||
if resource == nil {
|
||||
log.Error("received an event with empty resource field")
|
||||
log.ErrorContext(ctx, "received an event with empty resource field")
|
||||
}
|
||||
key := eventKey{kind: resource.GetKind(), name: resource.GetName()}
|
||||
if queue, loaded := queues[key]; loaded {
|
||||
|
||||
@@ -21,38 +21,37 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
"os"
|
||||
|
||||
"github.com/gravitational/trace"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
crdgen "github.com/gravitational/teleport/integrations/operator/crdgen"
|
||||
logutils "github.com/gravitational/teleport/lib/utils/log"
|
||||
)
|
||||
|
||||
func main() {
|
||||
log.SetLevel(log.DebugLevel)
|
||||
log.SetOutput(os.Stderr)
|
||||
slog.SetDefault(slog.New(logutils.NewSlogTextHandler(os.Stderr,
|
||||
logutils.SlogTextHandlerConfig{
|
||||
Level: slog.LevelDebug,
|
||||
},
|
||||
)))
|
||||
|
||||
ctx := context.Background()
|
||||
inputPath := os.Getenv(crdgen.PluginInputPathEnvironment)
|
||||
if inputPath == "" {
|
||||
log.Error(
|
||||
trace.BadParameter(
|
||||
"When built with the 'debug' tag, the input path must be set through the environment variable: %s",
|
||||
crdgen.PluginInputPathEnvironment,
|
||||
),
|
||||
)
|
||||
slog.ErrorContext(ctx, "When built with the 'debug' tag, the input path must be set through the TELEPORT_PROTOC_READ_FILE environment variable")
|
||||
os.Exit(-1)
|
||||
}
|
||||
log.Infof("This is a debug build, the protoc request is read from the file: '%s'", inputPath)
|
||||
slog.InfoContext(ctx, "This is a debug build, the protoc request is read from the file", "input_path", inputPath)
|
||||
|
||||
req, err := crdgen.ReadRequestFromFile(inputPath)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("error reading request from file")
|
||||
slog.ErrorContext(ctx, "error reading request from file", "error", err)
|
||||
os.Exit(-1)
|
||||
}
|
||||
|
||||
if err := crdgen.HandleDocsRequest(req); err != nil {
|
||||
log.WithError(err).Error("Failed to generate docs")
|
||||
slog.ErrorContext(ctx, "Failed to generate docs", "error", err)
|
||||
os.Exit(-1)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,20 +21,26 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
"os"
|
||||
|
||||
"github.com/gogo/protobuf/vanity/command"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
crdgen "github.com/gravitational/teleport/integrations/operator/crdgen"
|
||||
logutils "github.com/gravitational/teleport/lib/utils/log"
|
||||
)
|
||||
|
||||
func main() {
|
||||
log.SetLevel(log.DebugLevel)
|
||||
log.SetOutput(os.Stderr)
|
||||
slog.SetDefault(slog.New(logutils.NewSlogTextHandler(os.Stderr,
|
||||
logutils.SlogTextHandlerConfig{
|
||||
Level: slog.LevelDebug,
|
||||
},
|
||||
)))
|
||||
|
||||
req := command.Read()
|
||||
if err := crdgen.HandleDocsRequest(req); err != nil {
|
||||
log.WithError(err).Error("Failed to generate schema")
|
||||
slog.ErrorContext(context.Background(), "Failed to generate schema", "error", err)
|
||||
os.Exit(-1)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,38 +21,37 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
"os"
|
||||
|
||||
"github.com/gravitational/trace"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
crdgen "github.com/gravitational/teleport/integrations/operator/crdgen"
|
||||
logutils "github.com/gravitational/teleport/lib/utils/log"
|
||||
)
|
||||
|
||||
func main() {
|
||||
log.SetLevel(log.DebugLevel)
|
||||
log.SetOutput(os.Stderr)
|
||||
slog.SetDefault(slog.New(logutils.NewSlogTextHandler(os.Stderr,
|
||||
logutils.SlogTextHandlerConfig{
|
||||
Level: slog.LevelDebug,
|
||||
},
|
||||
)))
|
||||
|
||||
ctx := context.Background()
|
||||
inputPath := os.Getenv(crdgen.PluginInputPathEnvironment)
|
||||
if inputPath == "" {
|
||||
log.Error(
|
||||
trace.BadParameter(
|
||||
"When built with the 'debug' tag, the input path must be set through the environment variable: %s",
|
||||
crdgen.PluginInputPathEnvironment,
|
||||
),
|
||||
)
|
||||
slog.ErrorContext(ctx, "When built with the 'debug' tag, the input path must be set through the TELEPORT_PROTOC_READ_FILE environment variable")
|
||||
os.Exit(-1)
|
||||
}
|
||||
log.Infof("This is a debug build, the protoc request is read from the file: '%s'", inputPath)
|
||||
slog.InfoContext(ctx, "This is a debug build, the protoc request is read from the file", "input_path", inputPath)
|
||||
|
||||
req, err := crdgen.ReadRequestFromFile(inputPath)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("error reading request from file")
|
||||
slog.ErrorContext(ctx, "error reading request from file", "error", err)
|
||||
os.Exit(-1)
|
||||
}
|
||||
|
||||
if err := crdgen.HandleCRDRequest(req); err != nil {
|
||||
log.WithError(err).Error("Failed to generate schema")
|
||||
slog.ErrorContext(ctx, "Failed to generate schema", "error", err)
|
||||
os.Exit(-1)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,20 +21,26 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
"os"
|
||||
|
||||
"github.com/gogo/protobuf/vanity/command"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
crdgen "github.com/gravitational/teleport/integrations/operator/crdgen"
|
||||
logutils "github.com/gravitational/teleport/lib/utils/log"
|
||||
)
|
||||
|
||||
func main() {
|
||||
log.SetLevel(log.DebugLevel)
|
||||
log.SetOutput(os.Stderr)
|
||||
slog.SetDefault(slog.New(logutils.NewSlogTextHandler(os.Stderr,
|
||||
logutils.SlogTextHandlerConfig{
|
||||
Level: slog.LevelDebug,
|
||||
},
|
||||
)))
|
||||
|
||||
req := command.Read()
|
||||
if err := crdgen.HandleCRDRequest(req); err != nil {
|
||||
log.WithError(err).Error("Failed to generate schema")
|
||||
slog.ErrorContext(context.Background(), "Failed to generate schema", "error", err)
|
||||
os.Exit(-1)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ require (
|
||||
github.com/hashicorp/terraform-plugin-log v0.9.0
|
||||
github.com/hashicorp/terraform-plugin-sdk/v2 v2.10.1
|
||||
github.com/jonboulle/clockwork v0.4.0
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/stretchr/testify v1.10.0
|
||||
google.golang.org/grpc v1.69.2
|
||||
google.golang.org/protobuf v1.36.2
|
||||
@@ -307,6 +306,7 @@ require (
|
||||
github.com/shirou/gopsutil/v4 v4.24.12 // indirect
|
||||
github.com/shopspring/decimal v1.4.0 // indirect
|
||||
github.com/sijms/go-ora/v2 v2.8.22 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/spf13/cast v1.7.0 // indirect
|
||||
github.com/spf13/cobra v1.8.1 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
|
||||
@@ -17,9 +17,11 @@ limitations under the License.
|
||||
package provider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
|
||||
"github.com/gravitational/trace"
|
||||
"github.com/hashicorp/terraform-plugin-framework/diag"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// diagFromWrappedErr wraps error with additional information
|
||||
@@ -43,7 +45,7 @@ func diagFromWrappedErr(summary string, err error, kind string) diag.Diagnostic
|
||||
|
||||
// diagFromErr converts error to diag.Diagnostics. If logging level is debug, provides trace.DebugReport instead of short text.
|
||||
func diagFromErr(summary string, err error) diag.Diagnostic {
|
||||
if log.GetLevel() >= log.DebugLevel {
|
||||
if slog.Default().Enabled(context.Background(), slog.LevelDebug) {
|
||||
return diag.NewErrorDiagnostic(err.Error(), trace.DebugReport(err))
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ package provider
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net"
|
||||
"os"
|
||||
"strconv"
|
||||
@@ -29,13 +30,13 @@ import (
|
||||
"github.com/hashicorp/terraform-plugin-framework/diag"
|
||||
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/grpclog"
|
||||
|
||||
"github.com/gravitational/teleport/api/client"
|
||||
"github.com/gravitational/teleport/api/constants"
|
||||
"github.com/gravitational/teleport/lib/utils"
|
||||
logutils "github.com/gravitational/teleport/lib/utils/log"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -305,7 +306,7 @@ func (p *Provider) Configure(ctx context.Context, req tfsdk.ConfigureProviderReq
|
||||
return
|
||||
}
|
||||
|
||||
log.WithFields(log.Fields{"addr": addr}).Debug("Using Teleport address")
|
||||
slog.DebugContext(ctx, "Using Teleport address", "addr", addr)
|
||||
|
||||
dialTimeoutDuration, err := time.ParseDuration(dialTimeoutDurationStr)
|
||||
if err != nil {
|
||||
@@ -393,7 +394,7 @@ func (p *Provider) Configure(ctx context.Context, req tfsdk.ConfigureProviderReq
|
||||
|
||||
// checkTeleportVersion ensures that Teleport version is at least minServerVersion
|
||||
func (p *Provider) checkTeleportVersion(ctx context.Context, client *client.Client, resp *tfsdk.ConfigureProviderResponse) bool {
|
||||
log.Debug("Checking Teleport server version")
|
||||
slog.DebugContext(ctx, "Checking Teleport server version")
|
||||
pong, err := client.Ping(ctx)
|
||||
if err != nil {
|
||||
if trace.IsNotImplemented(err) {
|
||||
@@ -403,13 +404,13 @@ func (p *Provider) checkTeleportVersion(ctx context.Context, client *client.Clie
|
||||
)
|
||||
return false
|
||||
}
|
||||
log.WithError(err).Debug("Teleport version check error!")
|
||||
slog.DebugContext(ctx, "Teleport version check error", "error", err)
|
||||
resp.Diagnostics.AddError("Unable to get Teleport server version!", "Unable to get Teleport server version!")
|
||||
return false
|
||||
}
|
||||
err = utils.CheckMinVersion(pong.ServerVersion, minServerVersion)
|
||||
if err != nil {
|
||||
log.WithError(err).Debug("Teleport version check error!")
|
||||
slog.DebugContext(ctx, "Teleport version check error", "error", err)
|
||||
resp.Diagnostics.AddError("Teleport version check error!", err.Error())
|
||||
return false
|
||||
}
|
||||
@@ -447,7 +448,7 @@ func (p *Provider) validateAddr(addr string, resp *tfsdk.ConfigureProviderRespon
|
||||
|
||||
_, _, err := net.SplitHostPort(addr)
|
||||
if err != nil {
|
||||
log.WithField("addr", addr).WithError(err).Debug("Teleport address format error!")
|
||||
slog.DebugContext(context.Background(), "Teleport address format error", "error", err, "addr", addr)
|
||||
resp.Diagnostics.AddError(
|
||||
"Invalid Teleport address format",
|
||||
fmt.Sprintf("Teleport address must be specified as host:port. Got %q", addr),
|
||||
@@ -461,20 +462,32 @@ func (p *Provider) validateAddr(addr string, resp *tfsdk.ConfigureProviderRespon
|
||||
|
||||
// configureLog configures logging
|
||||
func (p *Provider) configureLog() {
|
||||
level := slog.LevelError
|
||||
// Get Terraform log level
|
||||
level, err := log.ParseLevel(os.Getenv("TF_LOG"))
|
||||
if err != nil {
|
||||
log.SetLevel(log.ErrorLevel)
|
||||
} else {
|
||||
log.SetLevel(level)
|
||||
switch strings.ToLower(os.Getenv("TF_LOG")) {
|
||||
case "panic", "fatal", "error":
|
||||
level = slog.LevelError
|
||||
case "warn", "warning":
|
||||
level = slog.LevelWarn
|
||||
case "info":
|
||||
level = slog.LevelInfo
|
||||
case "debug":
|
||||
level = slog.LevelDebug
|
||||
case "trace":
|
||||
level = logutils.TraceLevel
|
||||
}
|
||||
|
||||
log.SetFormatter(&log.TextFormatter{})
|
||||
_, _, err := logutils.Initialize(logutils.Config{
|
||||
Severity: level.String(),
|
||||
Format: "text",
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Show GRPC debug logs only if TF_LOG=DEBUG
|
||||
if log.GetLevel() >= log.DebugLevel {
|
||||
l := grpclog.NewLoggerV2(log.StandardLogger().Out, log.StandardLogger().Out, log.StandardLogger().Out)
|
||||
grpclog.SetLoggerV2(l)
|
||||
if level <= slog.LevelDebug {
|
||||
grpclog.SetLoggerV2(grpclog.NewLoggerV2(os.Stderr, os.Stderr, os.Stderr))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,8 @@ type Config struct {
|
||||
ExtraFields []string
|
||||
// EnableColors dictates if output should be colored.
|
||||
EnableColors bool
|
||||
// Padding to use for various components.
|
||||
Padding int
|
||||
}
|
||||
|
||||
// Initialize configures the default global logger based on the
|
||||
@@ -112,6 +114,7 @@ func Initialize(loggerConfig Config) (*slog.Logger, *slog.LevelVar, error) {
|
||||
Level: level,
|
||||
EnableColors: loggerConfig.EnableColors,
|
||||
ConfiguredFields: configuredFields,
|
||||
Padding: loggerConfig.Padding,
|
||||
}))
|
||||
slog.SetDefault(logger)
|
||||
case "json":
|
||||
|
||||
Reference in New Issue
Block a user