Skip to content

Commit 47e5e34

Browse files
authored
Support "enterprise" license types (#49474)
This adds "enterprise" as an acceptable type for a license loaded through the PUT _license API. Internally an enterprise license is treated as having a "platinum" operating mode. The handling of License types was refactored to have a new explicit "LicenseType" enum in addition to the existing "OperatingMode" enum. By default (in 7.x) the GET license API will return "platinum" when an enterprise license is active in order to be compatible with existing consumers of that API. A new "accept_enterprise" flag has been introduced to allow clients to opt-in to receive the correct "enterprise" type. Backport of: #49223
1 parent 54467b5 commit 47e5e34

File tree

17 files changed

+339
-140
lines changed

17 files changed

+339
-140
lines changed

x-pack/license-tools/src/main/java/org/elasticsearch/license/licensor/tools/LicenseGeneratorTool.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@ protected void execute(Terminal terminal, OptionSet options) throws Exception {
8888
ExitCodes.USAGE,
8989
"Must specify either --license or --licenseFile");
9090
}
91+
if (licenseSpec == null) {
92+
throw new UserException(ExitCodes.DATA_ERROR, "Could not parse license spec");
93+
}
9194

9295
// sign
9396
License license = new LicenseSigner(privateKeyPath, publicKeyPath).sign(licenseSpec);

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

Lines changed: 103 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,6 @@
55
*/
66
package org.elasticsearch.license;
77

8-
import java.io.IOException;
9-
import java.io.InputStream;
10-
import java.nio.ByteBuffer;
11-
import java.util.ArrayList;
12-
import java.util.Base64;
13-
import java.util.Comparator;
14-
import java.util.List;
15-
import java.util.Locale;
16-
178
import org.apache.lucene.util.CollectionUtil;
189
import org.elasticsearch.ElasticsearchException;
1910
import org.elasticsearch.ElasticsearchParseException;
@@ -31,11 +22,83 @@
3122
import org.elasticsearch.common.xcontent.XContentType;
3223
import org.elasticsearch.protocol.xpack.license.LicenseStatus;
3324

25+
import java.io.IOException;
26+
import java.io.InputStream;
27+
import java.nio.ByteBuffer;
28+
import java.util.ArrayList;
29+
import java.util.Base64;
30+
import java.util.Comparator;
31+
import java.util.List;
32+
import java.util.Locale;
33+
import java.util.stream.Collectors;
34+
import java.util.stream.Stream;
35+
3436
/**
3537
* Data structure for license. Use {@link Builder} to build a license.
3638
* Provides serialization/deserialization & validation methods for license object
3739
*/
3840
public class License implements ToXContentObject {
41+
42+
public enum LicenseType {
43+
BASIC,
44+
STANDARD,
45+
GOLD,
46+
PLATINUM,
47+
ENTERPRISE,
48+
TRIAL;
49+
50+
public String getTypeName() {
51+
return name().toLowerCase(Locale.ROOT);
52+
}
53+
54+
public static LicenseType parse(String type) throws IllegalArgumentException {
55+
try {
56+
return LicenseType.valueOf(type.toUpperCase(Locale.ROOT));
57+
} catch (IllegalArgumentException e) {
58+
throw new IllegalArgumentException("unrecognised license type [ " + type + "], supported license types are ["
59+
+ Stream.of(values()).map(LicenseType::getTypeName).collect(Collectors.joining(",")) + "]");
60+
}
61+
}
62+
63+
/**
64+
* Backward compatible license type parsing for older license models
65+
*/
66+
public static LicenseType resolve(String name) {
67+
switch (name.toLowerCase(Locale.ROOT)) {
68+
case "missing":
69+
return null;
70+
case "trial":
71+
case "none": // bwc for 1.x subscription_type field
72+
case "dev": // bwc for 1.x subscription_type field
73+
case "development": // bwc for 1.x subscription_type field
74+
return TRIAL;
75+
case "basic":
76+
return BASIC;
77+
case "standard":
78+
return STANDARD;
79+
case "silver":
80+
case "gold":
81+
return GOLD;
82+
case "platinum":
83+
case "cloud_internal":
84+
case "internal": // bwc for 1.x subscription_type field
85+
return PLATINUM;
86+
case "enterprise":
87+
return ENTERPRISE;
88+
default:
89+
throw new IllegalArgumentException("unknown license type [" + name + "]");
90+
}
91+
}
92+
93+
static boolean isBasic(String typeName) {
94+
return BASIC.getTypeName().equals(typeName);
95+
}
96+
97+
static boolean isTrial(String typeName) {
98+
return TRIAL.getTypeName().equals(typeName);
99+
}
100+
}
101+
39102
public static final int VERSION_START = 1;
40103
public static final int VERSION_NO_FEATURE_TYPE = 2;
41104
public static final int VERSION_START_DATE = 3;
@@ -49,6 +112,12 @@ public class License implements ToXContentObject {
49112
* and in a human readable format
50113
*/
51114
public static final String REST_VIEW_MODE = "rest_view";
115+
/**
116+
* XContent param name to map the "enterprise" license type to "platinum"
117+
* for backwards compatibility with older clients
118+
*/
119+
public static final String XCONTENT_HIDE_ENTERPRISE = "hide_enterprise";
120+
52121
/**
53122
* XContent param name to deserialize license(s) with
54123
* no signature
@@ -102,28 +171,25 @@ public static int compare(OperationMode opMode1, OperationMode opMode2) {
102171
return Integer.compare(opMode1.id, opMode2.id);
103172
}
104173

105-
public static OperationMode resolve(String type) {
106-
switch (type.toLowerCase(Locale.ROOT)) {
107-
case "missing":
108-
return MISSING;
109-
case "trial":
110-
case "none": // bwc for 1.x subscription_type field
111-
case "dev": // bwc for 1.x subscription_type field
112-
case "development": // bwc for 1.x subscription_type field
113-
return TRIAL;
114-
case "basic":
174+
public static OperationMode resolve(String typeName) {
175+
LicenseType type = LicenseType.resolve(typeName);
176+
if (type == null) {
177+
return MISSING;
178+
}
179+
switch (type) {
180+
case BASIC:
115181
return BASIC;
116-
case "standard":
182+
case STANDARD:
117183
return STANDARD;
118-
case "silver":
119-
case "gold":
184+
case GOLD:
120185
return GOLD;
121-
case "platinum":
122-
case "cloud_internal":
123-
case "internal": // bwc for 1.x subscription_type field
186+
case PLATINUM:
187+
case ENTERPRISE: // TODO Add an explicit enterprise operating mode
124188
return PLATINUM;
189+
case TRIAL:
190+
return TRIAL;
125191
default:
126-
throw new IllegalArgumentException("unknown type [" + type + "]");
192+
throw new IllegalArgumentException("unsupported license type [" + type.getTypeName() + "]");
127193
}
128194
}
129195

@@ -301,7 +367,7 @@ private void validate() {
301367
throw new IllegalStateException("maxNodes has to be set");
302368
} else if (expiryDate == -1) {
303369
throw new IllegalStateException("expiryDate has to be set");
304-
} else if (expiryDate == LicenseService.BASIC_SELF_GENERATED_LICENSE_EXPIRATION_MILLIS && "basic".equals(type) == false) {
370+
} else if (expiryDate == LicenseService.BASIC_SELF_GENERATED_LICENSE_EXPIRATION_MILLIS && LicenseType.isBasic(type) == false) {
305371
throw new IllegalStateException("only basic licenses are allowed to have no expiration");
306372
}
307373
}
@@ -377,6 +443,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
377443
public XContentBuilder toInnerXContent(XContentBuilder builder, Params params) throws IOException {
378444
boolean licenseSpecMode = params.paramAsBoolean(LICENSE_SPEC_VIEW_MODE, false);
379445
boolean restViewMode = params.paramAsBoolean(REST_VIEW_MODE, false);
446+
boolean hideEnterprise = params.paramAsBoolean(XCONTENT_HIDE_ENTERPRISE, false);
380447
boolean previouslyHumanReadable = builder.humanReadable();
381448
if (licenseSpecMode && restViewMode) {
382449
throw new IllegalArgumentException("can have either " + REST_VIEW_MODE + " or " + LICENSE_SPEC_VIEW_MODE);
@@ -395,7 +462,10 @@ public XContentBuilder toInnerXContent(XContentBuilder builder, Params params) t
395462
builder.field(Fields.STATUS, status().label());
396463
}
397464
builder.field(Fields.UID, uid);
398-
builder.field(Fields.TYPE, type);
465+
466+
final String bwcType = hideEnterprise && "enterprise".equals(type) ? "platinum" : type;
467+
builder.field(Fields.TYPE, bwcType);
468+
399469
if (version == VERSION_START) {
400470
builder.field(Fields.SUBSCRIPTION_TYPE, subscriptionType);
401471
}
@@ -689,6 +759,10 @@ public Builder issueDate(long issueDate) {
689759
return this;
690760
}
691761

762+
public Builder type(LicenseType type) {
763+
return type(type.getTypeName());
764+
}
765+
692766
public Builder type(String type) {
693767
this.type = type;
694768
return this;
@@ -778,6 +852,7 @@ public Builder validate() {
778852
}
779853
return this;
780854
}
855+
781856
}
782857

783858
}

0 commit comments

Comments
 (0)