moira
248 строк · 7.8 Кб
1package controller
2
3import (
4"errors"
5"fmt"
6"strings"
7"time"
8
9"github.com/go-graphite/carbonapi/date"
10"github.com/satori/go.uuid"
11
12"go.avito.ru/DO/moira"
13"go.avito.ru/DO/moira/api"
14"go.avito.ru/DO/moira/api/dto"
15"go.avito.ru/DO/moira/database"
16)
17
18func GetSubscriptionsByContactValue(database moira.Database, contactValue string) (*dto.SubscriptionFilteredList, *api.ErrorResponse) {
19contactValue = strings.ToLower(contactValue)
20if len(contactValue) < 3 {
21return nil, api.ErrorInvalidRequest(errors.New("\"contact\" must be at least 3 bytes long"))
22}
23
24result := &dto.SubscriptionFilteredList{
25List: nil,
26}
27
28// all existing contacts
29contacts, err := database.GetAllContacts()
30if err != nil {
31return nil, api.ErrorInternalServer(fmt.Errorf("Failed to get contacts data: %v", err))
32}
33
34// filter all contacts by value
35contactsAllMap := make(map[string]moira.ContactData, len(contacts))
36contactsMatchedSet := make(map[string]bool, len(contacts))
37usersSet := make(map[string]bool, len(contacts))
38for _, contact := range contacts {
39if contact == nil || contact.ID == "" {
40continue
41}
42
43contactsAllMap[contact.ID] = *contact
44if strings.Contains(strings.ToLower(contact.Value), contactValue) {
45contactsMatchedSet[contact.ID] = true
46usersSet[contact.User] = true
47}
48}
49
50// no contact has matched - hence no need to hit DB for subscriptions
51if len(contactsMatchedSet) == 0 {
52return result, nil
53}
54
55// search for all subscriptions of found users
56subscriptions := make([]*moira.SubscriptionData, 0, 100)
57for user := range usersSet {
58subscriptionIDs, err := database.GetUserSubscriptionIDs(user)
59if err != nil {
60return nil, api.ErrorInternalServer(err)
61}
62
63subscriptionsByUser, err := database.GetSubscriptions(subscriptionIDs)
64if err != nil {
65return nil, api.ErrorInternalServer(err)
66}
67
68for _, subscriptionByUser := range subscriptionsByUser {
69if subscriptionByUser != nil {
70subscriptions = append(subscriptions, subscriptionByUser)
71}
72}
73}
74result.List = make([]dto.SubscriptionFiltered, 0, len(subscriptions))
75
76// filter subscriptions and escalations by contact ids
77for _, subscription := range subscriptions {
78matchedEsc := make([]bool, len(subscription.Escalations)) // indicated which escalations have matched
79matchedSub := false // indicates if subscription itself has matched
80matchedAny := false // indicates if anything (either subscription or at least one escalation) has matched
81
82// define if subscription itself matches any contact
83for _, contactID := range subscription.Contacts {
84if contactID != "" && contactsMatchedSet[contactID] {
85matchedAny = true
86matchedSub = true
87break
88}
89}
90
91// for each escalation define if it matches any contact
92for i, escalation := range subscription.Escalations {
93for _, contactID := range escalation.Contacts {
94if contactID != "" && contactsMatchedSet[contactID] {
95matchedAny = true
96matchedEsc[i] = true
97break // range escalation.Contacts
98}
99}
100}
101
102// don't include unmatched subscription into result set
103if !matchedAny {
104continue
105}
106
107// make a copy of escalations
108escalations := make([]dto.EscalationFiltered, 0, len(subscription.Escalations))
109for _, escalation := range subscription.Escalations {
110escalations = append(escalations, dto.EscalationFiltered{
111ID: escalation.ID,
112Contacts: transformContactIDs(contactsAllMap, escalation.Contacts),
113OffsetInMinutes: escalation.OffsetInMinutes,
114})
115}
116
117// search result
118result.List = append(result.List, dto.SubscriptionFiltered{
119ID: subscription.ID,
120Enabled: subscription.Enabled,
121Tags: subscription.Tags,
122User: subscription.User,
123Contacts: transformContactIDs(contactsAllMap, subscription.Contacts),
124Escalations: escalations,
125MatchedEsc: matchedEsc,
126MatchedSub: matchedSub,
127})
128}
129
130return result, nil
131}
132
133// GetSubscriptionById is a proxy for the same database method
134func GetSubscriptionById(database moira.Database, id string) (*moira.SubscriptionData, *api.ErrorResponse) {
135subscriptionData, err := database.GetSubscription(id)
136if err != nil {
137return nil, api.ErrorInternalServer(err)
138} else {
139return &subscriptionData, nil
140}
141}
142
143// GetUserSubscriptions get all user subscriptions
144func GetUserSubscriptions(database moira.Database, userLogin string) (*dto.SubscriptionList, *api.ErrorResponse) {
145subscriptionIDs, err := database.GetUserSubscriptionIDs(userLogin)
146if err != nil {
147return nil, api.ErrorInternalServer(err)
148}
149subscriptions, err := database.GetSubscriptions(subscriptionIDs)
150if err != nil {
151return nil, api.ErrorInternalServer(err)
152}
153subscriptionsList := &dto.SubscriptionList{
154List: make([]moira.SubscriptionData, 0),
155}
156for _, subscription := range subscriptions {
157if subscription != nil {
158subscriptionsList.List = append(subscriptionsList.List, *subscription)
159}
160}
161return subscriptionsList, nil
162}
163
164// CreateSubscription create or update subscription
165func CreateSubscription(dataBase moira.Database, userLogin string, subscription *dto.Subscription) *api.ErrorResponse {
166if subscription.ID == "" {
167subscription.ID = uuid.NewV4().String()
168} else {
169exists, err := isSubscriptionExists(dataBase, subscription.ID)
170if err != nil {
171return api.ErrorInternalServer(err)
172}
173if exists {
174return api.ErrorInvalidRequest(fmt.Errorf("Subscription with this ID already exists"))
175}
176}
177
178subscription.User = userLogin
179data := moira.SubscriptionData(*subscription)
180if err := dataBase.SaveSubscription(&data); err != nil {
181return api.ErrorInternalServer(err)
182}
183return nil
184}
185
186// UpdateSubscription updates existing subscription
187func UpdateSubscription(dataBase moira.Database, subscriptionID string, userLogin string, subscription *dto.Subscription) *api.ErrorResponse {
188subscription.ID = subscriptionID
189subscription.User = userLogin
190data := moira.SubscriptionData(*subscription)
191if err := dataBase.SaveSubscription(&data); err != nil {
192return api.ErrorInternalServer(err)
193}
194return nil
195}
196
197// RemoveSubscription deletes subscription
198func RemoveSubscription(database moira.Database, subscriptionID string) *api.ErrorResponse {
199if err := database.RemoveSubscription(subscriptionID); err != nil {
200return api.ErrorInternalServer(err)
201}
202return nil
203}
204
205// SendTestNotification push test notification to verify the correct notification settings
206func SendTestNotification(database moira.Database, subscriptionID string) *api.ErrorResponse {
207var value float64 = 1
208eventData := &moira.NotificationEvent{
209SubscriptionID: &subscriptionID,
210Metric: "Test.metric.value",
211Value: &value,
212OldState: moira.TEST,
213State: moira.TEST,
214Timestamp: int64(date.DateParamToEpoch("now", "", time.Now().Add(-24*time.Hour).Unix(), time.UTC)),
215}
216
217if err := database.PushNotificationEvent(eventData); err != nil {
218return api.ErrorInternalServer(err)
219}
220
221return nil
222}
223
224// CheckUserPermissionsForSubscription checks subscription for existence and permissions for given user
225func CheckUserPermissionsForSubscription(dataBase moira.Database, subscriptionID string, userLogin string) (moira.SubscriptionData, *api.ErrorResponse) {
226subscription, err := dataBase.GetSubscription(subscriptionID)
227if err != nil {
228if err == database.ErrNil {
229return subscription, api.ErrorNotFound(fmt.Sprintf("Subscription with ID '%s' does not exists", subscriptionID))
230}
231return subscription, api.ErrorInternalServer(err)
232}
233if subscription.User != userLogin {
234return subscription, api.ErrorForbidden("You have not permissions")
235}
236return subscription, nil
237}
238
239func isSubscriptionExists(dataBase moira.Database, subscriptionID string) (bool, error) {
240_, err := dataBase.GetSubscription(subscriptionID)
241if err == database.ErrNil {
242return false, nil
243}
244if err != nil {
245return false, err
246}
247return true, nil
248}
249