Skip to content

Commit

Permalink
Adjust SyntheticSourceLicenseService
Browse files Browse the repository at this point in the history
Allow gold and platinum license to use synthetic source for a limited time.
If the start time of a license if before a cut off date, then gold and platinum licenses will not fallback to stored source if synthetic source is used.
  • Loading branch information
martijnvg committed Nov 12, 2024
1 parent 19291cf commit b66645f
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public LogsDBPlugin(Settings settings) {

@Override
public Collection<?> createComponents(PluginServices services) {
licenseService.setLicenseService(XPackPlugin.getSharedLicenseService());
licenseService.setLicenseState(XPackPlugin.getSharedLicenseState());
var clusterSettings = services.clusterService().getClusterSettings();
clusterSettings.addSettingsUpdateConsumer(FALLBACK_SETTING, licenseService::setSyntheticSourceFallback);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,13 @@
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.license.License;
import org.elasticsearch.license.LicenseService;
import org.elasticsearch.license.LicensedFeature;
import org.elasticsearch.license.XPackLicenseState;

import java.time.LocalDateTime;
import java.time.ZoneOffset;

/**
* Determines based on license and fallback setting whether synthetic source usages should fallback to stored source.
*/
Expand All @@ -36,11 +40,27 @@ final class SyntheticSourceLicenseService {
License.OperationMode.ENTERPRISE
);

private static final LicensedFeature.Momentary SYNTHETIC_SOURCE_FEATURE_GOLD = LicensedFeature.momentary(
MAPPINGS_FEATURE_FAMILY,
"synthetic-source-gold",
License.OperationMode.GOLD
);

private static final LicensedFeature.Momentary SYNTHETIC_SOURCE_FEATURE_PLATINUM = LicensedFeature.momentary(
MAPPINGS_FEATURE_FAMILY,
"synthetic-source-platinum",
License.OperationMode.PLATINUM
);

private final long cutoffDate;
private LicenseService licenseService;
private XPackLicenseState licenseState;
private volatile boolean syntheticSourceFallback;

SyntheticSourceLicenseService(Settings settings) {
syntheticSourceFallback = FALLBACK_SETTING.get(settings);
// turn into a constant and allow overwriting via system property
this.cutoffDate = LocalDateTime.of(2025, 1, 1, 0, 0).toInstant(ZoneOffset.UTC).toEpochMilli();
}

/**
Expand All @@ -51,17 +71,30 @@ public boolean fallbackToStoredSource(boolean isTemplateValidation) {
return true;
}

LicensedFeature.Momentary licensedFeature;
boolean beforeCutoffDate = licenseService.getLicense().startDate() <= cutoffDate;
if (beforeCutoffDate && licenseState.getOperationMode() == License.OperationMode.GOLD) {
licensedFeature = SYNTHETIC_SOURCE_FEATURE_GOLD;
} else if (beforeCutoffDate && licenseState.getOperationMode() == License.OperationMode.PLATINUM) {
licensedFeature = SYNTHETIC_SOURCE_FEATURE_PLATINUM;
} else {
licensedFeature = SYNTHETIC_SOURCE_FEATURE;
}
if (isTemplateValidation) {
return SYNTHETIC_SOURCE_FEATURE.checkWithoutTracking(licenseState) == false;
return licensedFeature.checkWithoutTracking(licenseState) == false;
} else {
return SYNTHETIC_SOURCE_FEATURE.check(licenseState) == false;
return licensedFeature.check(licenseState) == false;
}
}

void setSyntheticSourceFallback(boolean syntheticSourceFallback) {
this.syntheticSourceFallback = syntheticSourceFallback;
}

void setLicenseService(LicenseService licenseService) {
this.licenseService = licenseService;
}

void setLicenseState(XPackLicenseState licenseState) {
this.licenseState = licenseState;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
import org.elasticsearch.index.IndexSettings;
import org.elasticsearch.index.MapperTestUtils;
import org.elasticsearch.index.mapper.SourceFieldMapper;
import org.elasticsearch.license.License;
import org.elasticsearch.license.LicenseService;
import org.elasticsearch.license.MockLicenseState;
import org.elasticsearch.test.ESTestCase;
import org.junit.Before;
Expand All @@ -27,6 +29,7 @@
import java.util.concurrent.atomic.AtomicInteger;

import static org.elasticsearch.common.settings.Settings.builder;
import static org.elasticsearch.xpack.logsdb.SyntheticSourceLicenseServiceTests.createDummyLicense;
import static org.hamcrest.Matchers.equalTo;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
Expand All @@ -43,13 +46,17 @@ private static LogsdbIndexModeSettingsProvider getLogsdbIndexModeSettingsProvide
}

@Before
public void setup() {
public void setup() throws Exception {
MockLicenseState licenseState = mock(MockLicenseState.class);
when(licenseState.isAllowed(any())).thenReturn(true);
var licenseService = new SyntheticSourceLicenseService(Settings.EMPTY);
licenseService.setLicenseState(licenseState);
var mockLicenseService = mock(LicenseService.class);
License license = createDummyLicense();
when(mockLicenseService.getLicense()).thenReturn(license);
syntheticSourceLicenseService = new SyntheticSourceLicenseService(Settings.EMPTY);
syntheticSourceLicenseService.setLicenseState(licenseState);
syntheticSourceLicenseService.setLicenseService(mockLicenseService);

provider = new SyntheticSourceIndexSettingsProvider(syntheticSourceLicenseService, im -> {
newMapperServiceCounter.incrementAndGet();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,48 +8,66 @@
package org.elasticsearch.xpack.logsdb;

import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.license.License;
import org.elasticsearch.license.LicenseService;
import org.elasticsearch.license.MockLicenseState;
import org.elasticsearch.license.TestUtils;
import org.elasticsearch.test.ESTestCase;
import org.junit.Before;
import org.mockito.Mockito;

import java.util.UUID;

import static org.elasticsearch.license.TestUtils.dateMath;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class SyntheticSourceLicenseServiceTests extends ESTestCase {

private LicenseService mockLicenseService;
private SyntheticSourceLicenseService licenseService;

@Before
public void setup() throws Exception {
mockLicenseService = mock(LicenseService.class);
License license = createDummyLicense();
when(mockLicenseService.getLicense()).thenReturn(license);
licenseService = new SyntheticSourceLicenseService(Settings.EMPTY);
}

public void testLicenseAllowsSyntheticSource() {
MockLicenseState licenseState = mock(MockLicenseState.class);
when(licenseState.isAllowed(any())).thenReturn(true);
var licenseService = new SyntheticSourceLicenseService(Settings.EMPTY);
licenseService.setLicenseState(licenseState);
licenseService.setLicenseService(mockLicenseService);
assertFalse("synthetic source is allowed, so not fallback to stored source", licenseService.fallbackToStoredSource(false));
Mockito.verify(licenseState, Mockito.times(1)).featureUsed(any());
}

public void testLicenseAllowsSyntheticSourceTemplateValidation() {
MockLicenseState licenseState = mock(MockLicenseState.class);
when(licenseState.isAllowed(any())).thenReturn(true);
var licenseService = new SyntheticSourceLicenseService(Settings.EMPTY);
licenseService.setLicenseState(licenseState);
licenseService.setLicenseService(mockLicenseService);
assertFalse("synthetic source is allowed, so not fallback to stored source", licenseService.fallbackToStoredSource(true));
Mockito.verify(licenseState, Mockito.never()).featureUsed(any());
}

public void testDefaultDisallow() {
MockLicenseState licenseState = mock(MockLicenseState.class);
when(licenseState.isAllowed(any())).thenReturn(false);
var licenseService = new SyntheticSourceLicenseService(Settings.EMPTY);
licenseService.setLicenseState(licenseState);
licenseService.setLicenseService(mockLicenseService);
assertTrue("synthetic source is not allowed, so fallback to stored source", licenseService.fallbackToStoredSource(false));
Mockito.verify(licenseState, Mockito.never()).featureUsed(any());
}

public void testFallback() {
MockLicenseState licenseState = mock(MockLicenseState.class);
when(licenseState.isAllowed(any())).thenReturn(true);
var licenseService = new SyntheticSourceLicenseService(Settings.EMPTY);
licenseService.setLicenseState(licenseState);
licenseService.setLicenseService(mockLicenseService);
licenseService.setSyntheticSourceFallback(true);
assertTrue(
"synthetic source is allowed, but fallback has been enabled, so fallback to stored source",
Expand All @@ -58,4 +76,20 @@ public void testFallback() {
Mockito.verifyNoInteractions(licenseState);
}

static License createDummyLicense() throws Exception {
long now = System.currentTimeMillis();
String uid = UUID.randomUUID().toString();
final License.Builder builder = License.builder()
.uid(uid)
.version(License.VERSION_CURRENT)
.expiryDate(dateMath("now+2h", now))
.startDate(now)
.issueDate(now)
.type("basic")
.issuedTo("customer")
.issuer("elasticsearch")
.maxNodes(5);
License license = TestUtils.generateSignedLicense(builder);
return license;
}
}

0 comments on commit b66645f

Please sign in to comment.