Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

new bit to disable notifications over a week away #2393

Merged
merged 1 commit into from
Nov 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@
import java.util.function.Function;

public enum DisableNotificationEnum {
USER, ADMIN;
USER, // disable notifications to the users
ADMIN, // disable notifications to the admins
OVER_ONE_WEEK; // disable notifications to the users/admins if the expiry is more than a week out

public static EnumSet<DisableNotificationEnum> getEnumSet(long mask) {
return EnumUtils.processBitVector(DisableNotificationEnum.class, mask);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,18 @@ private Map<String, String> processGroupReminder(Map<String, List<GroupMember>>
continue;
}

// check to see if the administrator has configured to generate notifications
// only for members that are expiring in less than a week

if (disabledNotificationState.contains(DisableNotificationEnum.OVER_ONE_WEEK)) {
Timestamp notificationTimestamp = memberGroup.getExpiration();
if (notificationTimestamp == null || notificationTimestamp.millis() - System.currentTimeMillis() > NotificationUtils.WEEK_EXPIRY_CHECK) {
LOGGER.info("Notification skipped for group {}, domain {}, notification date is more than a week way",
memberGroup.getGroupName(), memberGroup.getDomainName());
continue;
}
}

final String domainName = memberGroup.getDomainName();

// first we're going to update our expiry details string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,15 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import static com.yahoo.athenz.common.server.notification.impl.MetricNotificationService.*;

public class NotificationUtils {

// we're going to use 8 days max for our week expiry disable check
public static final long WEEK_EXPIRY_CHECK = TimeUnit.MILLISECONDS.convert(8, TimeUnit.DAYS);

public static NotificationMetric getNotificationAsMetrics(Notification notification, Timestamp currentTime,
final String notificationType, final String keyName, final String objectType, final String timeType,
NotificationToMetricConverterCommon notificationToMetricConverterCommon) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,11 @@ public StringBuilder getDetailString(MemberRole memberRole) {
detailsRow.append(memberRole.getExpiration());
return detailsRow;
}

@Override
public Timestamp getNotificationTimestamp(MemberRole memberRole) {
return memberRole.getExpiration();
}
}

class ReviewDisableRoleMemberNotificationFilter implements RoleMemberNotificationCommon.DisableRoleMemberNotificationFilter {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import com.yahoo.athenz.zms.DomainRoleMember;
import com.yahoo.athenz.zms.MemberRole;
import com.yahoo.athenz.zms.utils.ZMSUtils;
import com.yahoo.rdl.Timestamp;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -34,11 +35,12 @@

public class RoleMemberNotificationCommon {

private static final Logger LOGGER = LoggerFactory.getLogger(RoleMemberNotificationCommon.class);

private final String userDomainPrefix;
private final boolean consolidatedNotifications;
private final NotificationCommon notificationCommon;
private final DomainRoleMembersFetcher domainRoleMembersFetcher;
private static final Logger LOGGER = LoggerFactory.getLogger(RoleMemberNotificationCommon.class);

public RoleMemberNotificationCommon(DBService dbService, String userDomainPrefix, boolean consolidatedNotifications) {
this.userDomainPrefix = userDomainPrefix;
Expand Down Expand Up @@ -291,6 +293,19 @@ private Map<String, String> processRoleReminder(Map<String, List<MemberRole>> do
LOGGER.info("Notification disabled for role {}, domain {}", memberRole.getRoleName(), memberRole.getDomainName());
continue;
}

// check to see if the administrator has configured to generate notifications
// only for members that are expiring in less than a week

if (disabledNotificationState.contains(DisableNotificationEnum.OVER_ONE_WEEK)) {
Timestamp notificationTimestamp = roleMemberDetailStringer.getNotificationTimestamp(memberRole);
if (notificationTimestamp == null || notificationTimestamp.millis() - System.currentTimeMillis() > NotificationUtils.WEEK_EXPIRY_CHECK) {
LOGGER.info("Notification skipped for role {}, domain {}, notification date is more than a week way",
memberRole.getRoleName(), memberRole.getDomainName());
continue;
}
}

final String domainName = memberRole.getDomainName();

// first we're going to update our expiry details string
Expand Down Expand Up @@ -361,12 +376,19 @@ List<Notification> printNotificationDetailsToLog(List<Notification> notification
*/
public interface RoleMemberDetailStringer {
/**
*
* @param memberRole member role
* @return Details extracted from the memberRole with a semicolon (;) between them
* Get the details extracted from the memberRole with a semicolon (;) between them
* These details should fit in the notification template (for example, the html of an email body)
* @param memberRole member role
* @return StringBuilder object that contains details
*/
StringBuilder getDetailString(MemberRole memberRole);

/**
* Returns the notification date (expiry or review date) for a given role
* @param memberRole member role
* @return notification date
*/
Timestamp getNotificationTimestamp(MemberRole memberRole);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,11 @@ public StringBuilder getDetailString(MemberRole memberRole) {
detailsRow.append(memberRole.getReviewReminder());
return detailsRow;
}

@Override
public Timestamp getNotificationTimestamp(MemberRole memberRole) {
return memberRole.getReviewReminder();
}
}

class ReviewDisableRoleMemberNotificationFilter implements RoleMemberNotificationCommon.DisableRoleMemberNotificationFilter {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.testng.annotations.Test;

import java.util.*;
import java.util.concurrent.TimeUnit;

import static com.yahoo.athenz.common.ServerCommonConsts.USER_DOMAIN_PREFIX;
import static com.yahoo.athenz.common.server.notification.NotificationServiceConstants.*;
Expand Down Expand Up @@ -158,6 +159,98 @@ public void testSendGroupMemberExpiryReminders() {
notificationManager.shutdown();
}

@Test
public void testSendGroupMemberExpiryRemindersDisabledOverOneWeek() {

DBService dbsvc = Mockito.mock(DBService.class);
NotificationToEmailConverterCommon notificationToEmailConverterCommon = new NotificationToEmailConverterCommon(null);
NotificationService mockNotificationService = Mockito.mock(NotificationService.class);
NotificationServiceFactory testfact = () -> mockNotificationService;

Timestamp twoWeekExpiry = Timestamp.fromMillis(System.currentTimeMillis() + TimeUnit.MILLISECONDS.convert(14, TimeUnit.DAYS));
Timestamp oneDayExpiry = Timestamp.fromMillis(System.currentTimeMillis() + TimeUnit.MILLISECONDS.convert(1, TimeUnit.DAYS));

List<GroupMember> memberGroups = new ArrayList<>();
memberGroups.add(new GroupMember().setGroupName("group1")
.setDomainName("athenz1")
.setMemberName("user.joe")
.setExpiration(twoWeekExpiry));
memberGroups.add(new GroupMember().setGroupName("group2")
.setDomainName("athenz1")
.setMemberName("user.joe")
.setExpiration(oneDayExpiry));
DomainGroupMember domainGroupMember = new DomainGroupMember()
.setMemberName("user.joe")
.setMemberGroups(memberGroups);
Map<String, DomainGroupMember> expiryMembers = new HashMap<>();
expiryMembers.put("user.joe", domainGroupMember);

// we're going to return null for our first thread which will
// run during init call and then the real data for the second
// call

Mockito.when(dbsvc.getGroupExpiryMembers(1))
.thenReturn(null)
.thenReturn(expiryMembers);

NotificationManager notificationManager = getNotificationManager(dbsvc, testfact);

ZMSTestUtils.sleep(1000);

AthenzDomain domain = new AthenzDomain("athenz1");
List<RoleMember> roleMembers = new ArrayList<>();
roleMembers.add(new RoleMember().setMemberName("user.jane"));
Role adminRole = new Role().setName("athenz1:role.admin").setRoleMembers(roleMembers);
List<Role> roles = new ArrayList<>();
roles.add(adminRole);
domain.setRoles(roles);

Mockito.when(dbsvc.getRolesByDomain("athenz1")).thenReturn(domain.getRoles());
Mockito.when(dbsvc.getRole("athenz1", "admin", Boolean.FALSE, Boolean.TRUE, Boolean.FALSE))
.thenReturn(adminRole);

Map<String, TagValueList> tags = new HashMap<>();
TagValueList tagValueList = new TagValueList().setList(Collections.singletonList("4"));
tags.put(ZMSConsts.DISABLE_REMINDER_NOTIFICATIONS_TAG, tagValueList);
Group group = new Group().setTags(tags);
Mockito.when(dbsvc.getGroup("athenz1", "group1", false, false)).thenReturn(group);
Mockito.when(dbsvc.getGroup("athenz1", "group2", false, false)).thenReturn(group);

List<Notification> notifications = new GroupMemberExpiryNotificationTask(dbsvc, USER_DOMAIN_PREFIX,
notificationToEmailConverterCommon, false).getNotifications();

// we should get 2 notifications - one for user and one for domain
// group1 should be excluded and group2 should be included

assertEquals(notifications.size(), 2);

// Verify contents of notifications is as expected
Notification expectedFirstNotification = new Notification();
expectedFirstNotification.addRecipient("user.joe");
expectedFirstNotification.addDetails(NOTIFICATION_DETAILS_ROLES_LIST, "athenz1;group2;user.joe;" + oneDayExpiry);
expectedFirstNotification.addDetails("member", "user.joe");
expectedFirstNotification.setNotificationToEmailConverter(
new GroupMemberExpiryNotificationTask.GroupExpiryPrincipalNotificationToEmailConverter(
notificationToEmailConverterCommon));
expectedFirstNotification.setNotificationToMetricConverter(
new GroupMemberExpiryNotificationTask.GroupExpiryPrincipalNotificationToToMetricConverter());

Notification expectedSecondNotification = new Notification();
expectedSecondNotification.addRecipient("user.jane");
expectedSecondNotification.addDetails(NOTIFICATION_DETAILS_MEMBERS_LIST, "athenz1;group2;user.joe;" + oneDayExpiry);
expectedSecondNotification.addDetails("domain", "athenz1");
expectedSecondNotification.setNotificationToEmailConverter(
new GroupMemberExpiryNotificationTask.GroupExpiryDomainNotificationToEmailConverter(
notificationToEmailConverterCommon));
expectedSecondNotification.setNotificationToMetricConverter(
new GroupMemberExpiryNotificationTask.GroupExpiryDomainNotificationToMetricConverter());

assertEquals(notifications.get(0), expectedFirstNotification);
assertEquals(notifications.get(1), expectedSecondNotification);

notificationManager.shutdown();
}

@Test
public void testSendGroupMemberExpiryRemindersNoValidDomain() {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.testng.annotations.Test;

import java.util.*;
import java.util.concurrent.TimeUnit;

import static com.yahoo.athenz.common.ServerCommonConsts.USER_DOMAIN_PREFIX;
import static com.yahoo.athenz.common.server.notification.NotificationServiceConstants.*;
Expand Down Expand Up @@ -84,6 +85,7 @@ public void testSendRoleMemberExpiryRemindersEmptySet() {

notificationManager.shutdown();
}

@Test
public void testSendRoleMemberExpiryReminders() {

Expand Down Expand Up @@ -162,6 +164,99 @@ public void testSendRoleMemberExpiryReminders() {
notificationManager.shutdown();
}

@Test
public void testSendRoleMemberExpiryRemindersDisabledOverOneWeek() {

DBService dbsvc = Mockito.mock(DBService.class);
NotificationService mockNotificationService = Mockito.mock(NotificationService.class);
NotificationServiceFactory testfact = () -> mockNotificationService;

Timestamp twoWeekExpiry = Timestamp.fromMillis(System.currentTimeMillis() + TimeUnit.MILLISECONDS.convert(14, TimeUnit.DAYS));
Timestamp oneDayExpiry = Timestamp.fromMillis(System.currentTimeMillis() + TimeUnit.MILLISECONDS.convert(1, TimeUnit.DAYS));

List<MemberRole> memberRoles = new ArrayList<>();
memberRoles.add(new MemberRole().setRoleName("role1")
.setDomainName("athenz1")
.setMemberName("user.joe")
.setExpiration(twoWeekExpiry));
memberRoles.add(new MemberRole().setRoleName("role2")
.setDomainName("athenz1")
.setMemberName("user.joe")
.setExpiration(oneDayExpiry));
DomainRoleMember domainRoleMember = new DomainRoleMember()
.setMemberName("user.joe")
.setMemberRoles(memberRoles);
Map<String, DomainRoleMember> expiryMembers = new HashMap<>();
expiryMembers.put("user.joe", domainRoleMember);

// we're going to return null for our first thread which will
// run during init call and then the real data for the second
// call

Mockito.when(dbsvc.getRoleExpiryMembers(1, false))
.thenReturn(null)
.thenReturn(expiryMembers);

NotificationManager notificationManager = getNotificationManager(dbsvc, testfact);

ZMSTestUtils.sleep(1000);

AthenzDomain domain = new AthenzDomain("athenz1");
List<RoleMember> roleMembers = new ArrayList<>();
roleMembers.add(new RoleMember().setMemberName("user.jane"));
Role adminRole = new Role()
.setName("athenz1:role.admin")
.setRoleMembers(roleMembers);
List<Role> roles = new ArrayList<>();
roles.add(adminRole);
domain.setRoles(roles);

Mockito.when(dbsvc.getRolesByDomain("athenz1")).thenReturn(domain.getRoles());
Mockito.when(dbsvc.getRole("athenz1", "admin", Boolean.FALSE, Boolean.TRUE, Boolean.FALSE))
.thenThrow(new UnsupportedOperationException());

Map<String, TagValueList> tags = new HashMap<>();
TagValueList tagValueList = new TagValueList().setList(Collections.singletonList("4"));
tags.put(ZMSConsts.DISABLE_EXPIRATION_NOTIFICATIONS_TAG, tagValueList);
Role role = new Role().setTags(tags);
Mockito.when(dbsvc.getRole("athenz1", "role1", false, false, false)).thenReturn(role);
Mockito.when(dbsvc.getRole("athenz1", "role2", false, false, false)).thenReturn(role);

List<Notification> notifications = new RoleMemberExpiryNotificationTask(dbsvc, USER_DOMAIN_PREFIX,
new NotificationToEmailConverterCommon(null), false).getNotifications();

// we should get 2 notifications - one for user and one for domain
// role1 should be excluded and role2 should be included

assertEquals(notifications.size(), 2);

// Verify contents of notifications is as expected
Notification expectedFirstNotification = new Notification();
expectedFirstNotification.addRecipient("user.joe");
expectedFirstNotification.addDetails(NOTIFICATION_DETAILS_ROLES_LIST, "athenz1;role2;user.joe;" + oneDayExpiry);
expectedFirstNotification.addDetails("member", "user.joe");
expectedFirstNotification.setNotificationToEmailConverter(
new RoleMemberExpiryNotificationTask.RoleExpiryPrincipalNotificationToEmailConverter(
new NotificationToEmailConverterCommon(null)));
expectedFirstNotification.setNotificationToMetricConverter(
new RoleMemberExpiryNotificationTask.RoleExpiryPrincipalNotificationToMetricConverter());

Notification expectedSecondNotification = new Notification();
expectedSecondNotification.addRecipient("user.jane");
expectedSecondNotification.addDetails(NOTIFICATION_DETAILS_MEMBERS_LIST, "athenz1;role2;user.joe;" + oneDayExpiry);
expectedSecondNotification.addDetails("domain", "athenz1");
expectedSecondNotification.setNotificationToEmailConverter(
new RoleMemberExpiryNotificationTask.RoleExpiryDomainNotificationToEmailConverter(
new NotificationToEmailConverterCommon(null)));
expectedSecondNotification.setNotificationToMetricConverter(
new RoleMemberExpiryNotificationTask.RoleExpiryDomainNotificationToMetricConverter());

assertEquals(notifications.get(0), expectedFirstNotification);
assertEquals(notifications.get(1), expectedSecondNotification);

notificationManager.shutdown();
}

@Test
public void testSendRoleMemberExpiryRemindersNoValidDomain() {

Expand Down
Loading