// Verify if the method that choose the domains that needs to be verified is correct func domainsNotification(domainDAO dao.DomainDAO) { numberOfItemsToBeVerified := 1000 numberOfItemsToDontBeVerified := 1000 nameserverErrorAlertDays := 7 nameserverTimeoutAlertDays := 30 dsErrorAlertDays := 1 dsTimeoutAlertDays := 7 maxExpirationAlertDays := 5 data := []struct { name string numberOfItems int nameserverTimeoutLastOKAt time.Time nameserverErrorLastOKAt time.Time dsTimeoutLastOkAt time.Time dsErrorLastOkAt time.Time dsExpiresAt time.Time }{ { name: "shouldbenotified", numberOfItems: numberOfItemsToBeVerified, nameserverTimeoutLastOKAt: time.Now().Add(time.Duration(-nameserverTimeoutAlertDays*24) * time.Hour), nameserverErrorLastOKAt: time.Now().Add(time.Duration(-nameserverErrorAlertDays*24) * time.Hour), dsTimeoutLastOkAt: time.Now().Add(time.Duration(-dsTimeoutAlertDays*24) * time.Hour), dsErrorLastOkAt: time.Now().Add(time.Duration(-dsErrorAlertDays*24) * time.Hour), dsExpiresAt: time.Now().Add(time.Duration((maxExpirationAlertDays)*24) * time.Hour), }, { name: "shouldnotbenotified", numberOfItems: numberOfItemsToDontBeVerified, nameserverTimeoutLastOKAt: time.Now().Add(time.Duration((-nameserverTimeoutAlertDays+1)*24) * time.Hour), nameserverErrorLastOKAt: time.Now().Add(time.Duration((-nameserverErrorAlertDays+1)*24) * time.Hour), dsTimeoutLastOkAt: time.Now().Add(time.Duration((-dsTimeoutAlertDays+1)*24) * time.Hour), dsErrorLastOkAt: time.Now().Add(time.Duration((-dsErrorAlertDays+1)*24) * time.Hour), dsExpiresAt: time.Now().Add(time.Duration((maxExpirationAlertDays+1)*24) * time.Hour), }, } for _, item := range data { for i := 0; i < item.numberOfItems/5; i++ { domain := model.Domain{ FQDN: fmt.Sprintf("%s%d.com.br", item.name, i), Nameservers: []model.Nameserver{ { LastStatus: model.NameserverStatusTimeout, LastOKAt: item.nameserverTimeoutLastOKAt, }, }, } if err := domainDAO.Save(&domain); err != nil { utils.Fatalln("Error saving domain in database", err) } } for i := item.numberOfItems / 5; i < item.numberOfItems/5*2; i++ { domain := model.Domain{ FQDN: fmt.Sprintf("%s%d.com.br", item.name, i), Nameservers: []model.Nameserver{ { LastStatus: model.NameserverStatusNoAuthority, LastOKAt: item.nameserverErrorLastOKAt, }, }, } if err := domainDAO.Save(&domain); err != nil { utils.Fatalln("Error saving domain in database", err) } } for i := item.numberOfItems / 5 * 2; i < item.numberOfItems/5*3; i++ { domain := model.Domain{ FQDN: fmt.Sprintf("%s%d.com.br", item.name, i), DSSet: []model.DS{ { LastStatus: model.DSStatusTimeout, LastOKAt: item.dsTimeoutLastOkAt, ExpiresAt: time.Now().Add(time.Duration((maxExpirationAlertDays+1)*24) * time.Hour), }, }, } if err := domainDAO.Save(&domain); err != nil { utils.Fatalln("Error saving domain in database", err) } } for i := item.numberOfItems / 5 * 3; i < item.numberOfItems/5*4; i++ { domain := model.Domain{ FQDN: fmt.Sprintf("%s%d.com.br", item.name, i), DSSet: []model.DS{ { LastStatus: model.DSStatusExpiredSignature, LastOKAt: item.dsErrorLastOkAt, ExpiresAt: time.Now().Add(time.Duration((maxExpirationAlertDays+1)*24) * time.Hour), }, }, } if err := domainDAO.Save(&domain); err != nil { utils.Fatalln("Error saving domain in database", err) } } for i := item.numberOfItems / 5 * 4; i < item.numberOfItems; i++ { domain := model.Domain{ FQDN: fmt.Sprintf("%s%d.com.br", item.name, i), DSSet: []model.DS{ { LastStatus: model.DSStatusOK, LastOKAt: time.Now(), ExpiresAt: item.dsExpiresAt, }, }, } if err := domainDAO.Save(&domain); err != nil { utils.Fatalln("Error saving domain in database", err) } } } domainChannel, err := domainDAO.FindAllAsyncToBeNotified( nameserverErrorAlertDays, nameserverTimeoutAlertDays, dsErrorAlertDays, dsTimeoutAlertDays, maxExpirationAlertDays, ) if err != nil { utils.Fatalln("Error retrieving domains to be notified", err) } var domains []*model.Domain for { domainResult := <-domainChannel if domainResult.Error != nil { utils.Fatalln("Error retrieving domain to be notified", domainResult.Error) } if domainResult.Error != nil || domainResult.Domain == nil { break } domains = append(domains, domainResult.Domain) } if len(domains) != numberOfItemsToBeVerified { utils.Fatalln(fmt.Sprintf("Did not select all the domains ready for notification. "+ "Expected %d and got %d", numberOfItemsToBeVerified, len(domains)), nil) } for _, item := range data { for i := 0; i < item.numberOfItems; i++ { fqdn := fmt.Sprintf("%s%d.com.br", item.name, i) if err := domainDAO.RemoveByFQDN(fqdn); err != nil { utils.Fatalln("Error removing domain from database", err) } } } }
// Notify is responsable for selecting the domains that should be notified in the system. // It will send alert e-mails for each owner of a domain func Notify() { defer func() { // Something went really wrong while notifying the owners. Log the error stacktrace // and move out if r := recover(); r != nil { const size = 64 << 10 buf := make([]byte, size) buf = buf[:runtime.Stack(buf, false)] log.Printf("Panic detected while notifying the owners. Details: %v\n%s", r, buf) } }() log.Info("Start notification job") defer func() { log.Info("End notification job") }() log.Debugf("Initializing database with the parameters: URIS - %v | Name - %s | Auth - %t | Username - %s", config.ShelterConfig.Database.URIs, config.ShelterConfig.Database.Name, config.ShelterConfig.Database.Auth.Enabled, config.ShelterConfig.Database.Auth.Username, ) database, databaseSession, err := mongodb.Open( config.ShelterConfig.Database.URIs, config.ShelterConfig.Database.Name, config.ShelterConfig.Database.Auth.Enabled, config.ShelterConfig.Database.Auth.Username, config.ShelterConfig.Database.Auth.Password, ) if err != nil { log.Println("Error while initializing database. Details:", err) return } defer databaseSession.Close() domainDAO := dao.DomainDAO{ Database: database, } domainChannel, err := domainDAO.FindAllAsyncToBeNotified( config.ShelterConfig.Notification.NameserverErrorAlertDays, config.ShelterConfig.Notification.NameserverTimeoutAlertDays, config.ShelterConfig.Notification.DSErrorAlertDays, config.ShelterConfig.Notification.DSTimeoutAlertDays, // TODO: Should we move this configuration parameter to a place were both modules can // access it. This sounds better for configuration deployment config.ShelterConfig.Scan.VerificationIntervals.MaxExpirationAlertDays, ) if err != nil { log.Println("Error retrieving domains to notify. Details:", err) return } // Dispatch the asynchronous part of the method for { // Get domain from the database (one-by-one) domainResult := <-domainChannel // Detect errors while retrieving a specific domain. We are not going to stop all the // process when only one domain got an error if domainResult.Error != nil { log.Println("Error retrieving domain to notify. Details:", domainResult.Error) continue } // Problem detected while retrieving a domain or we don't have domains anymore if domainResult.Error != nil || domainResult.Domain == nil { break } if err := notifyDomain(domainResult.Domain); err != nil { log.Println("Error notifying a domain. Details:", err) } } }