@@ -113,13 +113,19 @@ static boolean isBasic(String typeName) {
113113 static boolean isTrial (String typeName ) {
114114 return TRIAL .getTypeName ().equals (typeName );
115115 }
116+
117+ static boolean isEnterprise (String typeName ) {
118+ return ENTERPRISE .getTypeName ().equals (typeName );
119+ }
120+
116121 }
117122
118123 public static final int VERSION_START = 1 ;
119124 public static final int VERSION_NO_FEATURE_TYPE = 2 ;
120125 public static final int VERSION_START_DATE = 3 ;
121126 public static final int VERSION_CRYPTO_ALGORITHMS = 4 ;
122- public static final int VERSION_CURRENT = VERSION_CRYPTO_ALGORITHMS ;
127+ public static final int VERSION_ENTERPRISE = 5 ;
128+ public static final int VERSION_CURRENT = VERSION_ENTERPRISE ;
123129
124130 /**
125131 * XContent param name to deserialize license(s) with
@@ -159,13 +165,14 @@ static boolean isTrial(String typeName) {
159165 private final long expiryDate ;
160166 private final long startDate ;
161167 private final int maxNodes ;
168+ private final int maxResourceUnits ;
162169 private final OperationMode operationMode ;
163170
164171 /**
165172 * Decouples operation mode of a license from the license type value.
166173 * <p>
167174 * Note: The mode indicates features that should be made available, but it does not indicate whether the license is active!
168- *
175+ * <p>
169176 * The id byte is used for ordering operation modes
170177 */
171178 public enum OperationMode {
@@ -182,13 +189,16 @@ public enum OperationMode {
182189 this .id = id ;
183190 }
184191
185- /** Returns non-zero positive number when <code>opMode1</code> is greater than <code>opMode2</code> */
192+ /**
193+ * Returns non-zero positive number when <code>opMode1</code> is greater than <code>opMode2</code>
194+ */
186195 public static int compare (OperationMode opMode1 , OperationMode opMode2 ) {
187196 return Integer .compare (opMode1 .id , opMode2 .id );
188197 }
189198
190199 /**
191200 * Determine the operating mode for a license type
201+ *
192202 * @see LicenseType#resolve(License)
193203 * @see #parse(String)
194204 */
@@ -217,6 +227,7 @@ public static OperationMode resolve(LicenseType type) {
217227 * Parses an {@code OperatingMode} from a String.
218228 * The string must name an operating mode, and not a licensing level (that is, it cannot parse old style license levels
219229 * such as "dev" or "silver").
230+ *
220231 * @see #description()
221232 */
222233 public static OperationMode parse (String mode ) {
@@ -233,8 +244,8 @@ public String description() {
233244 }
234245 }
235246
236- private License (int version , String uid , String issuer , String issuedTo , long issueDate , String type ,
237- String subscriptionType , String feature , String signature , long expiryDate , int maxNodes , long startDate ) {
247+ private License (int version , String uid , String issuer , String issuedTo , long issueDate , String type , String subscriptionType ,
248+ String feature , String signature , long expiryDate , int maxNodes , int maxResourceUnits , long startDate ) {
238249 this .version = version ;
239250 this .uid = uid ;
240251 this .issuer = issuer ;
@@ -252,6 +263,7 @@ private License(int version, String uid, String issuer, String issuedTo, long is
252263 this .expiryDate = expiryDate ;
253264 }
254265 this .maxNodes = maxNodes ;
266+ this .maxResourceUnits = maxResourceUnits ;
255267 this .startDate = startDate ;
256268 this .operationMode = OperationMode .resolve (LicenseType .resolve (this ));
257269 validate ();
@@ -300,12 +312,21 @@ public long expiryDate() {
300312 }
301313
302314 /**
303- * @return the maximum number of nodes this license has been issued for
315+ * @return the maximum number of nodes this license has been issued for, or {@code -1} if this license is not node based.
304316 */
305317 public int maxNodes () {
306318 return maxNodes ;
307319 }
308320
321+ /**
322+ * @return the maximum number of "resource units" this license has been issued for, or {@code -1} if this license is not resource based.
323+ * A "resource unit" is a measure of computing power (RAM/CPU), the definition of which is maintained outside of the license format,
324+ * or this class.
325+ */
326+ public int maxResourceUnits () {
327+ return maxResourceUnits ;
328+ }
329+
309330 /**
310331 * @return a string representing the entity this licenses has been issued to
311332 */
@@ -392,20 +413,39 @@ private void validate() {
392413 throw new IllegalStateException ("uid can not be null" );
393414 } else if (feature == null && version == VERSION_START ) {
394415 throw new IllegalStateException ("feature can not be null" );
395- } else if (maxNodes == -1 ) {
396- throw new IllegalStateException ("maxNodes has to be set" );
397416 } else if (expiryDate == -1 ) {
398417 throw new IllegalStateException ("expiryDate has to be set" );
399418 } else if (expiryDate == LicenseService .BASIC_SELF_GENERATED_LICENSE_EXPIRATION_MILLIS && LicenseType .isBasic (type ) == false ) {
400419 throw new IllegalStateException ("only basic licenses are allowed to have no expiration" );
401420 }
421+
422+ if (LicenseType .isEnterprise (type ) && version < VERSION_ENTERPRISE ) {
423+ throw new IllegalStateException ("license type [" + type + "] is not a valid for version [" + version + "] licenses" );
424+ }
425+ validateLimits (type , maxNodes , maxResourceUnits );
426+ }
427+
428+ private static void validateLimits (String type , int maxNodes , int maxResourceUnits ) {
429+ if (LicenseType .isEnterprise (type )) {
430+ if (maxResourceUnits == -1 ) {
431+ throw new IllegalStateException ("maxResourceUnits must be set for enterprise licenses (type=[" + type + "])" );
432+ } else if (maxNodes != -1 ) {
433+ throw new IllegalStateException ("maxNodes may not be set for enterprise licenses (type=[" + type + "])" );
434+ }
435+ } else {
436+ if (maxNodes == -1 ) {
437+ throw new IllegalStateException ("maxNodes has to be set" );
438+ } else if (maxResourceUnits != -1 ) {
439+ throw new IllegalStateException ("maxResourceUnits may only be set for enterprise licenses (not permitted for type=[" +
440+ type + "])" );
441+ }
442+ }
402443 }
403444
404445 public static License readLicense (StreamInput in ) throws IOException {
405446 int version = in .readVInt (); // Version for future extensibility
406447 if (version > VERSION_CURRENT ) {
407- throw new ElasticsearchException ("Unknown license version found, please upgrade all nodes to the latest elasticsearch-license" +
408- " plugin" );
448+ throw new ElasticsearchException ("Unknown license version found, please upgrade all nodes to the latest elasticsearch release" );
409449 }
410450 Builder builder = builder ();
411451 builder .version (version );
@@ -420,6 +460,9 @@ public static License readLicense(StreamInput in) throws IOException {
420460 }
421461 builder .expiryDate (in .readLong ());
422462 builder .maxNodes (in .readInt ());
463+ if (version >= VERSION_ENTERPRISE ) {
464+ builder .maxResourceUnits (in .readInt ());
465+ }
423466 builder .issuedTo (in .readString ());
424467 builder .issuer (in .readString ());
425468 builder .signature (in .readOptionalString ());
@@ -442,6 +485,9 @@ public void writeTo(StreamOutput out) throws IOException {
442485 }
443486 out .writeLong (expiryDate );
444487 out .writeInt (maxNodes );
488+ if (version >= VERSION_ENTERPRISE ) {
489+ out .writeInt (maxResourceUnits );
490+ }
445491 out .writeString (issuedTo );
446492 out .writeString (issuer );
447493 out .writeOptionalString (signature );
@@ -506,7 +552,16 @@ public XContentBuilder toInnerXContent(XContentBuilder builder, Params params) t
506552 if (expiryDate != LicenseService .BASIC_SELF_GENERATED_LICENSE_EXPIRATION_MILLIS ) {
507553 builder .timeField (Fields .EXPIRY_DATE_IN_MILLIS , Fields .EXPIRY_DATE , expiryDate );
508554 }
509- builder .field (Fields .MAX_NODES , maxNodes );
555+
556+ if (version >= VERSION_ENTERPRISE ) {
557+ builder .field (Fields .MAX_NODES , maxNodes == -1 ? null : maxNodes );
558+ builder .field (Fields .MAX_RESOURCE_UNITS , maxResourceUnits == -1 ? null : maxResourceUnits );
559+ } else if (hideEnterprise && maxNodes == -1 ) {
560+ builder .field (Fields .MAX_NODES , maxResourceUnits );
561+ } else {
562+ builder .field (Fields .MAX_NODES , maxNodes );
563+ }
564+
510565 builder .field (Fields .ISSUED_TO , issuedTo );
511566 builder .field (Fields .ISSUER , issuer );
512567 if (!licenseSpecMode && !restViewMode && signature != null ) {
@@ -551,6 +606,8 @@ public static License fromXContent(XContentParser parser) throws IOException {
551606 builder .startDate (parser .longValue ());
552607 } else if (Fields .MAX_NODES .equals (currentFieldName )) {
553608 builder .maxNodes (parser .intValue ());
609+ } else if (Fields .MAX_RESOURCE_UNITS .equals (currentFieldName )) {
610+ builder .maxResourceUnits (parser .intValue ());
554611 } else if (Fields .ISSUED_TO .equals (currentFieldName )) {
555612 builder .issuedTo (parser .text ());
556613 } else if (Fields .ISSUER .equals (currentFieldName )) {
@@ -593,7 +650,7 @@ public static License fromXContent(XContentParser parser) throws IOException {
593650 throw new ElasticsearchException ("malformed signature for license [" + builder .uid + "]" );
594651 } else if (version > VERSION_CURRENT ) {
595652 throw new ElasticsearchException ("Unknown license version found, please upgrade all nodes to the latest " +
596- "elasticsearch-license plugin" );
653+ "elasticsearch-license plugin" );
597654 }
598655 // signature version is the source of truth
599656 builder .version (version );
@@ -625,8 +682,7 @@ public static License fromSource(BytesReference bytes, XContentType xContentType
625682 // EMPTY is safe here because we don't call namedObject
626683 try (InputStream byteStream = bytes .streamInput ();
627684 XContentParser parser = xContentType .xContent ()
628- .createParser (NamedXContentRegistry .EMPTY , LoggingDeprecationHandler .INSTANCE , byteStream ))
629- {
685+ .createParser (NamedXContentRegistry .EMPTY , LoggingDeprecationHandler .INSTANCE , byteStream )) {
630686 License license = null ;
631687 if (parser .nextToken () == XContentParser .Token .START_OBJECT ) {
632688 if (parser .nextToken () == XContentParser .Token .FIELD_NAME ) {
@@ -675,7 +731,7 @@ public boolean equals(Object o) {
675731
676732 if (issueDate != license .issueDate ) return false ;
677733 if (expiryDate != license .expiryDate ) return false ;
678- if (startDate != license .startDate ) return false ;
734+ if (startDate != license .startDate ) return false ;
679735 if (maxNodes != license .maxNodes ) return false ;
680736 if (version != license .version ) return false ;
681737 if (uid != null ? !uid .equals (license .uid ) : license .uid != null ) return false ;
@@ -700,7 +756,7 @@ public int hashCode() {
700756 result = 31 * result + (feature != null ? feature .hashCode () : 0 );
701757 result = 31 * result + (signature != null ? signature .hashCode () : 0 );
702758 result = 31 * result + (int ) (expiryDate ^ (expiryDate >>> 32 ));
703- result = 31 * result + (int ) (startDate ^ (startDate >>> 32 ));
759+ result = 31 * result + (int ) (startDate ^ (startDate >>> 32 ));
704760 result = 31 * result + maxNodes ;
705761 result = 31 * result + version ;
706762 return result ;
@@ -719,6 +775,7 @@ public static final class Fields {
719775 public static final String START_DATE_IN_MILLIS = "start_date_in_millis" ;
720776 public static final String START_DATE = "start_date" ;
721777 public static final String MAX_NODES = "max_nodes" ;
778+ public static final String MAX_RESOURCE_UNITS = "max_resource_units" ;
722779 public static final String ISSUED_TO = "issued_to" ;
723780 public static final String ISSUER = "issuer" ;
724781 public static final String VERSION = "version" ;
@@ -762,6 +819,7 @@ public static class Builder {
762819 private long expiryDate = -1 ;
763820 private long startDate = -1 ;
764821 private int maxNodes = -1 ;
822+ private int maxResourceUnits = -1 ;
765823
766824 public Builder uid (String uid ) {
767825 this .uid = uid ;
@@ -817,6 +875,11 @@ public Builder maxNodes(int maxNodes) {
817875 return this ;
818876 }
819877
878+ public Builder maxResourceUnits (int maxUnits ) {
879+ this .maxResourceUnits = maxUnits ;
880+ return this ;
881+ }
882+
820883 public Builder signature (String signature ) {
821884 if (signature != null ) {
822885 this .signature = signature ;
@@ -831,17 +894,18 @@ public Builder startDate(long startDate) {
831894
832895 public Builder fromLicenseSpec (License license , String signature ) {
833896 return uid (license .uid ())
834- .version (license .version ())
835- .issuedTo (license .issuedTo ())
836- .issueDate (license .issueDate ())
837- .startDate (license .startDate ())
838- .type (license .type ())
839- .subscriptionType (license .subscriptionType )
840- .feature (license .feature )
841- .maxNodes (license .maxNodes ())
842- .expiryDate (license .expiryDate ())
843- .issuer (license .issuer ())
844- .signature (signature );
897+ .version (license .version ())
898+ .issuedTo (license .issuedTo ())
899+ .issueDate (license .issueDate ())
900+ .startDate (license .startDate ())
901+ .type (license .type ())
902+ .subscriptionType (license .subscriptionType )
903+ .feature (license .feature )
904+ .maxNodes (license .maxNodes ())
905+ .maxResourceUnits (license .maxResourceUnits ())
906+ .expiryDate (license .expiryDate ())
907+ .issuer (license .issuer ())
908+ .signature (signature );
845909 }
846910
847911 /**
@@ -850,15 +914,15 @@ public Builder fromLicenseSpec(License license, String signature) {
850914 */
851915 public Builder fromPre20LicenseSpec (License pre20License ) {
852916 return uid (pre20License .uid ())
853- .issuedTo (pre20License .issuedTo ())
854- .issueDate (pre20License .issueDate ())
855- .maxNodes (pre20License .maxNodes ())
856- .expiryDate (pre20License .expiryDate ());
917+ .issuedTo (pre20License .issuedTo ())
918+ .issueDate (pre20License .issueDate ())
919+ .maxNodes (pre20License .maxNodes ())
920+ .expiryDate (pre20License .expiryDate ());
857921 }
858922
859923 public License build () {
860924 return new License (version , uid , issuer , issuedTo , issueDate , type ,
861- subscriptionType , feature , signature , expiryDate , maxNodes , startDate );
925+ subscriptionType , feature , signature , expiryDate , maxNodes , maxResourceUnits , startDate );
862926 }
863927
864928 public Builder validate () {
@@ -874,11 +938,10 @@ public Builder validate() {
874938 throw new IllegalStateException ("uid can not be null" );
875939 } else if (signature == null ) {
876940 throw new IllegalStateException ("signature can not be null" );
877- } else if (maxNodes == -1 ) {
878- throw new IllegalStateException ("maxNodes has to be set" );
879941 } else if (expiryDate == -1 ) {
880942 throw new IllegalStateException ("expiryDate has to be set" );
881943 }
944+ validateLimits (type , maxNodes , maxResourceUnits );
882945 return this ;
883946 }
884947
0 commit comments