Skip to content

Commit 7cefba7

Browse files
authored
License removal leads back to a basic license (#52407) (#52683)
A new basic license will be generated when existing license is deleted. In addition, deleting an existing basic license is a no-op. Resolves: #45022
1 parent d26d772 commit 7cefba7

File tree

8 files changed

+49
-62
lines changed

8 files changed

+49
-62
lines changed

x-pack/plugin/core/src/main/java/org/elasticsearch/license/LicenseService.java

+3-23
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
import org.elasticsearch.cluster.ClusterChangedEvent;
1515
import org.elasticsearch.cluster.ClusterState;
1616
import org.elasticsearch.cluster.ClusterStateListener;
17-
import org.elasticsearch.cluster.ack.ClusterStateUpdateResponse;
1817
import org.elasticsearch.cluster.metadata.MetaData;
1918
import org.elasticsearch.cluster.node.DiscoveryNode;
2019
import org.elasticsearch.cluster.service.ClusterService;
@@ -343,29 +342,10 @@ public void triggered(SchedulerEngine.Event event) {
343342
/**
344343
* Remove license from the cluster state metadata
345344
*/
346-
public void removeLicense(final DeleteLicenseRequest request, final ActionListener<ClusterStateUpdateResponse> listener) {
345+
public void removeLicense(final DeleteLicenseRequest request, final ActionListener<PostStartBasicResponse> listener) {
346+
final PostStartBasicRequest startBasicRequest = new PostStartBasicRequest().acknowledge(true);
347347
clusterService.submitStateUpdateTask("delete license",
348-
new AckedClusterStateUpdateTask<ClusterStateUpdateResponse>(request, listener) {
349-
@Override
350-
protected ClusterStateUpdateResponse newResponse(boolean acknowledged) {
351-
return new ClusterStateUpdateResponse(acknowledged);
352-
}
353-
354-
@Override
355-
public ClusterState execute(ClusterState currentState) throws Exception {
356-
MetaData metaData = currentState.metaData();
357-
final LicensesMetaData currentLicenses = metaData.custom(LicensesMetaData.TYPE);
358-
if (currentLicenses.getLicense() != LicensesMetaData.LICENSE_TOMBSTONE) {
359-
MetaData.Builder mdBuilder = MetaData.builder(currentState.metaData());
360-
LicensesMetaData newMetadata = new LicensesMetaData(LicensesMetaData.LICENSE_TOMBSTONE,
361-
currentLicenses.getMostRecentTrialVersion());
362-
mdBuilder.putCustom(LicensesMetaData.TYPE, newMetadata);
363-
return ClusterState.builder(currentState).metaData(mdBuilder).build();
364-
} else {
365-
return currentState;
366-
}
367-
}
368-
});
348+
new StartBasicClusterTask(logger, clusterService.getClusterName().value(), clock, startBasicRequest, listener));
369349
}
370350

371351
public License getLicense() {

x-pack/plugin/core/src/main/java/org/elasticsearch/license/StartBasicClusterTask.java

+25-17
Original file line numberDiff line numberDiff line change
@@ -61,31 +61,20 @@ public void clusterStateProcessed(String source, ClusterState oldState, ClusterS
6161
@Override
6262
public ClusterState execute(ClusterState currentState) throws Exception {
6363
XPackPlugin.checkReadyForXPackCustomMetadata(currentState);
64-
LicensesMetaData licensesMetaData = currentState.metaData().custom(LicensesMetaData.TYPE);
65-
License currentLicense = LicensesMetaData.extractLicense(licensesMetaData);
66-
if (currentLicense == null || License.LicenseType.isBasic(currentLicense.type()) == false) {
67-
long issueDate = clock.millis();
68-
MetaData.Builder mdBuilder = MetaData.builder(currentState.metaData());
69-
License.Builder specBuilder = License.builder()
70-
.uid(UUID.randomUUID().toString())
71-
.issuedTo(clusterName)
72-
.maxNodes(LicenseService.SELF_GENERATED_LICENSE_MAX_NODES)
73-
.issueDate(issueDate)
74-
.type(License.LicenseType.BASIC)
75-
.expiryDate(LicenseService.BASIC_SELF_GENERATED_LICENSE_EXPIRATION_MILLIS);
76-
License selfGeneratedLicense = SelfGeneratedLicense.create(specBuilder, currentState.nodes());
64+
LicensesMetaData currentLicensesMetaData = currentState.metaData().custom(LicensesMetaData.TYPE);
65+
License currentLicense = LicensesMetaData.extractLicense(currentLicensesMetaData);
66+
if (shouldGenerateNewBasicLicense(currentLicense)) {
67+
License selfGeneratedLicense = generateBasicLicense(currentState);
7768
if (request.isAcknowledged() == false && currentLicense != null) {
7869
Map<String, String[]> ackMessages = LicenseService.getAckMessages(selfGeneratedLicense, currentLicense);
7970
if (ackMessages.isEmpty() == false) {
8071
this.ackMessages.set(ackMessages);
8172
return currentState;
8273
}
8374
}
84-
Version trialVersion = null;
85-
if (licensesMetaData != null) {
86-
trialVersion = licensesMetaData.getMostRecentTrialVersion();
87-
}
75+
Version trialVersion = currentLicensesMetaData != null ? currentLicensesMetaData.getMostRecentTrialVersion() : null;
8876
LicensesMetaData newLicensesMetaData = new LicensesMetaData(selfGeneratedLicense, trialVersion);
77+
MetaData.Builder mdBuilder = MetaData.builder(currentState.metaData());
8978
mdBuilder.putCustom(LicensesMetaData.TYPE, newLicensesMetaData);
9079
return ClusterState.builder(currentState).metaData(mdBuilder).build();
9180
} else {
@@ -98,4 +87,23 @@ public void onFailure(String source, @Nullable Exception e) {
9887
logger.error(new ParameterizedMessage("unexpected failure during [{}]", source), e);
9988
listener.onFailure(e);
10089
}
90+
91+
private boolean shouldGenerateNewBasicLicense(License currentLicense) {
92+
return currentLicense == null
93+
|| License.LicenseType.isBasic(currentLicense.type()) == false
94+
|| LicenseService.SELF_GENERATED_LICENSE_MAX_NODES != currentLicense.maxNodes()
95+
|| LicenseService.BASIC_SELF_GENERATED_LICENSE_EXPIRATION_MILLIS != currentLicense.expiryDate();
96+
}
97+
98+
private License generateBasicLicense(ClusterState currentState) {
99+
final License.Builder specBuilder = License.builder()
100+
.uid(UUID.randomUUID().toString())
101+
.issuedTo(clusterName)
102+
.maxNodes(LicenseService.SELF_GENERATED_LICENSE_MAX_NODES)
103+
.issueDate(clock.millis())
104+
.type(License.LicenseType.BASIC)
105+
.expiryDate(LicenseService.BASIC_SELF_GENERATED_LICENSE_EXPIRATION_MILLIS);
106+
107+
return SelfGeneratedLicense.create(specBuilder, currentState.nodes());
108+
}
101109
}

x-pack/plugin/core/src/main/java/org/elasticsearch/license/TransportDeleteLicenseAction.java

+3-4
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
import org.elasticsearch.action.support.master.AcknowledgedResponse;
1212
import org.elasticsearch.action.support.master.TransportMasterNodeAction;
1313
import org.elasticsearch.cluster.ClusterState;
14-
import org.elasticsearch.cluster.ack.ClusterStateUpdateResponse;
1514
import org.elasticsearch.cluster.block.ClusterBlockException;
1615
import org.elasticsearch.cluster.block.ClusterBlockLevel;
1716
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
@@ -55,10 +54,10 @@ protected ClusterBlockException checkBlock(DeleteLicenseRequest request, Cluster
5554
@Override
5655
protected void masterOperation(final DeleteLicenseRequest request, ClusterState state, final ActionListener<AcknowledgedResponse>
5756
listener) throws ElasticsearchException {
58-
licenseService.removeLicense(request, new ActionListener<ClusterStateUpdateResponse>() {
57+
licenseService.removeLicense(request, new ActionListener<PostStartBasicResponse>() {
5958
@Override
60-
public void onResponse(ClusterStateUpdateResponse clusterStateUpdateResponse) {
61-
listener.onResponse(new AcknowledgedResponse(clusterStateUpdateResponse.isAcknowledged()));
59+
public void onResponse(PostStartBasicResponse postStartBasicResponse) {
60+
listener.onResponse(new AcknowledgedResponse(postStartBasicResponse.isAcknowledged()));
6261
}
6362

6463
@Override

x-pack/plugin/core/src/test/java/org/elasticsearch/license/LicenseServiceClusterTests.java

+3-4
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323

2424
import static org.elasticsearch.test.ESIntegTestCase.Scope.TEST;
2525
import static org.hamcrest.CoreMatchers.equalTo;
26-
import static org.hamcrest.CoreMatchers.nullValue;
2726

2827
@ClusterScope(scope = TEST, numDataNodes = 0, numClientNodes = 0, maxNumDataNodes = 0, transportClientRatio = 0)
2928
public class LicenseServiceClusterTests extends AbstractLicensesIntegrationTestCase {
@@ -78,14 +77,14 @@ public void testClusterRestartWithLicense() throws Exception {
7877
assertThat(licensingClient.prepareGetLicense().get().license(), equalTo(license));
7978
logger.info("--> remove licenses");
8079
licensingClient.prepareDeleteLicense().get();
81-
assertOperationMode(License.OperationMode.MISSING);
80+
assertOperationMode(License.OperationMode.BASIC);
8281

8382
logger.info("--> restart all nodes");
8483
internalCluster().fullRestart();
8584
licensingClient = new LicensingClient(client());
8685
ensureYellow();
87-
assertThat(licensingClient.prepareGetLicense().get().license(), nullValue());
88-
assertOperationMode(License.OperationMode.MISSING);
86+
assertTrue(License.LicenseType.isBasic(licensingClient.prepareGetLicense().get().license().type()));
87+
assertOperationMode(License.OperationMode.BASIC);
8988

9089

9190
wipeAllLicenses();

x-pack/plugin/core/src/test/java/org/elasticsearch/license/LicensesManagerServiceTests.java

+4-5
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
package org.elasticsearch.license;
77

88
import org.elasticsearch.action.ActionListener;
9-
import org.elasticsearch.cluster.ack.ClusterStateUpdateResponse;
109
import org.elasticsearch.cluster.service.ClusterService;
1110
import org.elasticsearch.common.settings.Settings;
1211
import org.elasticsearch.common.unit.TimeValue;
@@ -120,16 +119,16 @@ public void testRemoveLicenses() throws Exception {
120119
// remove signed licenses
121120
removeAndAckSignedLicenses(licenseService);
122121
licensesMetaData = clusterService.state().metaData().custom(LicensesMetaData.TYPE);
123-
assertThat(licensesMetaData.getLicense(), equalTo(LicensesMetaData.LICENSE_TOMBSTONE));
122+
assertTrue(License.LicenseType.isBasic(licensesMetaData.getLicense().type()));
124123
}
125124

126125
private void removeAndAckSignedLicenses(final LicenseService licenseService) {
127126
final CountDownLatch latch = new CountDownLatch(1);
128127
final AtomicBoolean success = new AtomicBoolean(false);
129-
licenseService.removeLicense(new DeleteLicenseRequest(), new ActionListener<ClusterStateUpdateResponse>() {
128+
licenseService.removeLicense(new DeleteLicenseRequest(), new ActionListener<PostStartBasicResponse>() {
130129
@Override
131-
public void onResponse(ClusterStateUpdateResponse clusterStateUpdateResponse) {
132-
if (clusterStateUpdateResponse.isAcknowledged()) {
130+
public void onResponse(PostStartBasicResponse postStartBasicResponse) {
131+
if (postStartBasicResponse.isAcknowledged()) {
133132
success.set(true);
134133
}
135134
latch.countDown();

x-pack/plugin/core/src/test/java/org/elasticsearch/license/LicensesTransportTests.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ public void testRemoveLicensesSimple() throws Exception {
187187
assertThat(deleteLicenseResponse.isAcknowledged(), equalTo(true));
188188
// get licenses (expected no licenses)
189189
getLicenseResponse = new GetLicenseRequestBuilder(client().admin().cluster(), GetLicenseAction.INSTANCE).get();
190-
assertNull(getLicenseResponse.license());
190+
assertTrue(License.LicenseType.isBasic(getLicenseResponse.license().type()));
191191
}
192192

193193
public void testLicenseIsRejectWhenStartDateLaterThanNow() throws Exception {

x-pack/plugin/core/src/test/java/org/elasticsearch/license/StartBasicLicenseTests.java

-6
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,6 @@ public void testStartBasicLicense() throws Exception {
6161
assertEquals("trial", getLicenseResponse.license().type());
6262
});
6363

64-
// Testing that you can start a basic license when you have no license
65-
if (randomBoolean()) {
66-
licensingClient.prepareDeleteLicense().get();
67-
assertNull(licensingClient.prepareGetLicense().get().license());
68-
}
69-
7064
RestClient restClient = getRestClient();
7165
Response response = restClient.performRequest(new Request("GET", "/_license/basic_status"));
7266
String body = Streams.copyToString(new InputStreamReader(response.getEntity().getContent(), StandardCharsets.UTF_8));

x-pack/plugin/src/test/resources/rest-api-spec/test/license/20_put_license.yml

+10-2
Original file line numberDiff line numberDiff line change
@@ -66,15 +66,23 @@ teardown:
6666
- length: { license: 11 }
6767
- match: { license.uid: "893361dc-9749-4997-93cb-802e3dofh7aa" }
6868
---
69-
"Should throw 404 after license deletion":
69+
"Should revert back to basic license after license deletion":
7070
- do:
7171
license.delete: {}
7272

7373
- match: { acknowledged: true }
7474

7575
- do:
7676
license.get: {}
77-
catch: missing
77+
78+
- match: { license.type: "basic" }
79+
- set: { license.uid: id }
80+
81+
- do: # delete an existing basic license is a no-op
82+
license.delete: {}
83+
- do:
84+
license.get: {}
85+
- match: { license.uid: $id}
7886

7987
---
8088
"Should install a feature type license":

0 commit comments

Comments
 (0)