Add api to start basic license (elastic/x-pack-elasticsearch#4083)

This is related to elastic/x-pack-elasticsearch#3877. This commit adds a route /start_basic that
will self generate a basic license. The only validation that is
performed is to check that you do not already have a basic license
installed. Additionally, if you lose features from switching to a basic
license, you must acknowledge the changes.

Original commit: elastic/x-pack-elasticsearch@7b8eeb50b1
This commit is contained in:
Tim Brooks 2018-03-12 14:39:58 -06:00 committed by GitHub
parent de10e61765
commit 7f7ac08447
28 changed files with 1085 additions and 74 deletions

View File

@ -0,0 +1,45 @@
[role="xpack"]
[[get-basic-status]]
=== Get Basic Status API
This API enables you to check the status of your basic license.
[float]
==== Request
`GET _xpack/license/basic_status`
[float]
==== Description
In order to initiate a basic license, you must not currently have a basic
license.
For more information about the different types of licenses, see
https://www.elastic.co/subscriptions.
==== Authorization
You must have `monitor` cluster privileges to use this API.
For more information, see
{xpack-ref}/security-privileges.html[Security Privileges].
[float]
==== Examples
The following example checks whether you are eligible to start a basic:
[source,js]
------------------------------------------------------------
GET _xpack/license/basic_status
------------------------------------------------------------
// CONSOLE
Example response:
[source,js]
------------------------------------------------------------
{
"eligible_to_start_basic": true
}
------------------------------------------------------------
// TESTRESPONSE[s/"eligible_to_start_basic": true/"eligible_to_start_basic": $body.eligible_to_start_basic/]

View File

@ -0,0 +1,74 @@
[role="xpack"]
[[start-basic]]
=== Start Basic API
This API starts an indefinite basic license.
[float]
==== Request
`POST _xpack/license/start_basic`
[float]
==== Description
The `start basic` API enables you to initiate an indefinite basic license, which
gives access to all {xpack} basic features. If the basic license does not support
all of the features that are available with your current license, however, you are
notified in the response. You must then re-submit the API request with the
`acknowledge` parameter set to `true`.
To check the status of your basic license, use the following API:
<<get-basic-status>>.
For more information about the different types of licenses, see
https://www.elastic.co/subscriptions.
==== Authorization
You must have `manage` cluster privileges to use this API.
For more information, see
{xpack-ref}/security-privileges.html[Security Privileges].
[float]
==== Examples
The following example starts a basic license if you do not currently have a license:
[source,js]
------------------------------------------------------------
POST _xpack/license/start_basic
------------------------------------------------------------
// CONSOLE
// TEST[skip:license testing issues]
Example response:
[source,js]
------------------------------------------------------------
{
"basic_was_started": true,
"acknowledged": true
}
------------------------------------------------------------
// NOTCONSOLE
The following example starts a basic license if you currently have a license with more
features than a basic license. As you are losing features, you must pass the acknowledge
parameter:
[source,js]
------------------------------------------------------------
POST _xpack/license/start_basic?acknowledge=true
------------------------------------------------------------
// CONSOLE
// TEST[skip:license testing issues]
Example response:
[source,js]
------------------------------------------------------------
{
"basic_was_started": true,
"acknowledged": true
}
------------------------------------------------------------
// NOTCONSOLE

View File

@ -8,6 +8,8 @@ You can use the following APIs to manage your licenses:
* <<get-license>> * <<get-license>>
* <<get-trial-status>> * <<get-trial-status>>
* <<start-trial>> * <<start-trial>>
* <<get-basic-status>>
* <<start-basic>>
* <<update-license>> * <<update-license>>
@ -15,4 +17,6 @@ include::license/delete-license.asciidoc[]
include::license/get-license.asciidoc[] include::license/get-license.asciidoc[]
include::license/get-trial-status.asciidoc[] include::license/get-trial-status.asciidoc[]
include::license/start-trial.asciidoc[] include::license/start-trial.asciidoc[]
include::license/get-basic-status.asciidoc[]
include::license/start-basic.asciidoc[]
include::license/update-license.asciidoc[] include::license/update-license.asciidoc[]

View File

@ -0,0 +1,29 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.license;
import org.elasticsearch.action.Action;
import org.elasticsearch.client.ElasticsearchClient;
public class GetBasicStatusAction extends Action<GetBasicStatusRequest, GetBasicStatusResponse, GetBasicStatusRequestBuilder> {
public static final GetBasicStatusAction INSTANCE = new GetBasicStatusAction();
public static final String NAME = "cluster:admin/xpack/license/basic_status";
private GetBasicStatusAction() {
super(NAME);
}
@Override
public GetBasicStatusRequestBuilder newRequestBuilder(ElasticsearchClient client) {
return new GetBasicStatusRequestBuilder(client, this);
}
@Override
public GetBasicStatusResponse newResponse() {
return new GetBasicStatusResponse();
}
}

View File

@ -0,0 +1,27 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.license;
import org.elasticsearch.action.ActionRequestValidationException;
import org.elasticsearch.action.support.master.MasterNodeReadRequest;
import org.elasticsearch.common.io.stream.StreamInput;
import java.io.IOException;
public class GetBasicStatusRequest extends MasterNodeReadRequest<GetBasicStatusRequest> {
public GetBasicStatusRequest() {
}
public GetBasicStatusRequest(StreamInput in) throws IOException {
super(in);
}
@Override
public ActionRequestValidationException validate() {
return null;
}
}

View File

@ -0,0 +1,17 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.license;
import org.elasticsearch.action.ActionRequestBuilder;
import org.elasticsearch.client.ElasticsearchClient;
class GetBasicStatusRequestBuilder extends ActionRequestBuilder<GetBasicStatusRequest, GetBasicStatusResponse,
GetBasicStatusRequestBuilder> {
GetBasicStatusRequestBuilder(ElasticsearchClient client, GetBasicStatusAction action) {
super(client, action, new GetBasicStatusRequest());
}
}

View File

@ -0,0 +1,38 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.license;
import org.elasticsearch.action.ActionResponse;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import java.io.IOException;
class GetBasicStatusResponse extends ActionResponse {
private boolean eligibleToStartBasic;
GetBasicStatusResponse() {
}
GetBasicStatusResponse(boolean eligibleToStartBasic) {
this.eligibleToStartBasic = eligibleToStartBasic;
}
boolean isEligibleToStartBasic() {
return eligibleToStartBasic;
}
@Override
public void readFrom(StreamInput in) throws IOException {
eligibleToStartBasic = in.readBoolean();
}
@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeBoolean(eligibleToStartBasic);
}
}

View File

@ -26,7 +26,6 @@ import org.elasticsearch.common.logging.LoggerMessageFormat;
import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.util.concurrent.EsExecutors;
import org.elasticsearch.discovery.DiscoveryModule; import org.elasticsearch.discovery.DiscoveryModule;
import org.elasticsearch.env.Environment; import org.elasticsearch.env.Environment;
import org.elasticsearch.gateway.GatewayService; import org.elasticsearch.gateway.GatewayService;
@ -100,7 +99,7 @@ public class LicenseService extends AbstractLifecycleComponent implements Cluste
/** /**
* Max number of nodes licensed by generated trial license * Max number of nodes licensed by generated trial license
*/ */
private int selfGeneratedLicenseMaxNodes = 1000; static final int SELF_GENERATED_LICENSE_MAX_NODES = 1000;
public static final String LICENSE_JOB = "licenseJob"; public static final String LICENSE_JOB = "licenseJob";
@ -192,19 +191,7 @@ public class LicenseService extends AbstractLifecycleComponent implements Cluste
// TODO: ack messages should be generated on the master, since another node's cluster state may be behind... // TODO: ack messages should be generated on the master, since another node's cluster state may be behind...
final License currentLicense = getLicense(); final License currentLicense = getLicense();
if (currentLicense != null) { if (currentLicense != null) {
Map<String, String[]> acknowledgeMessages = new HashMap<>(); Map<String, String[]> acknowledgeMessages = getAckMessages(newLicense, currentLicense);
if (!License.isAutoGeneratedLicense(currentLicense.signature()) // current license is not auto-generated
&& currentLicense.issueDate() > newLicense.issueDate()) { // and has a later issue date
acknowledgeMessages.put("license", new String[]{
"The new license is older than the currently installed license. " +
"Are you sure you want to override the current license?"});
}
XPackLicenseState.ACKNOWLEDGMENT_MESSAGES.forEach((feature, ackMessages) -> {
String[] messages = ackMessages.apply(currentLicense.operationMode(), newLicense.operationMode());
if (messages.length > 0) {
acknowledgeMessages.put(feature, messages);
}
});
if (acknowledgeMessages.isEmpty() == false) { if (acknowledgeMessages.isEmpty() == false) {
// needs acknowledgement // needs acknowledgement
listener.onResponse(new PutLicenseResponse(false, LicensesStatus.VALID, ACKNOWLEDGEMENT_HEADER, listener.onResponse(new PutLicenseResponse(false, LicensesStatus.VALID, ACKNOWLEDGEMENT_HEADER,
@ -248,6 +235,23 @@ public class LicenseService extends AbstractLifecycleComponent implements Cluste
} }
} }
public static Map<String, String[]> getAckMessages(License newLicense, License currentLicense) {
Map<String, String[]> acknowledgeMessages = new HashMap<>();
if (!License.isAutoGeneratedLicense(currentLicense.signature()) // current license is not auto-generated
&& currentLicense.issueDate() > newLicense.issueDate()) { // and has a later issue date
acknowledgeMessages.put("license", new String[]{
"The new license is older than the currently installed license. " +
"Are you sure you want to override the current license?"});
}
XPackLicenseState.ACKNOWLEDGMENT_MESSAGES.forEach((feature, ackMessages) -> {
String[] messages = ackMessages.apply(currentLicense.operationMode(), newLicense.operationMode());
if (messages.length > 0) {
acknowledgeMessages.put(feature, messages);
}
});
return acknowledgeMessages;
}
private static TimeValue days(int days) { private static TimeValue days(int days) {
return TimeValue.timeValueHours(days * 24); return TimeValue.timeValueHours(days * 24);
@ -328,7 +332,7 @@ public class LicenseService extends AbstractLifecycleComponent implements Cluste
License.Builder specBuilder = License.builder() License.Builder specBuilder = License.builder()
.uid(UUID.randomUUID().toString()) .uid(UUID.randomUUID().toString())
.issuedTo(clusterService.getClusterName().value()) .issuedTo(clusterService.getClusterName().value())
.maxNodes(selfGeneratedLicenseMaxNodes) .maxNodes(SELF_GENERATED_LICENSE_MAX_NODES)
.issueDate(issueDate) .issueDate(issueDate)
.type("trial") .type("trial")
.expiryDate(expiryDate); .expiryDate(expiryDate);
@ -349,6 +353,11 @@ public class LicenseService extends AbstractLifecycleComponent implements Cluste
}); });
} }
void startBasicLicense(PostStartBasicRequest request, final ActionListener<PostStartBasicResponse> listener) {
StartBasicClusterTask task = new StartBasicClusterTask(logger, clusterService.getClusterName().value(), clock, request, listener);
clusterService.submitStateUpdateTask("start basic license", task);
}
/** /**
* Master-only operation to generate a one-time global self generated license. * Master-only operation to generate a one-time global self generated license.
* The self generated license is only generated and stored if the current cluster state metadata * The self generated license is only generated and stored if the current cluster state metadata

View File

@ -188,6 +188,18 @@ public class LicensesMetaData extends AbstractNamedDiffable<MetaData.Custom> imp
return readDiffFrom(MetaData.Custom.class, TYPE, streamInput); return readDiffFrom(MetaData.Custom.class, TYPE, streamInput);
} }
public static License extractLicense(LicensesMetaData licensesMetaData) {
if (licensesMetaData != null) {
License license = licensesMetaData.getLicense();
if (license == LicensesMetaData.LICENSE_TOMBSTONE) {
return null;
} else {
return license;
}
}
return null;
}
@Override @Override
public LicensesMetaData merge(LicensesMetaData other) { public LicensesMetaData merge(LicensesMetaData other) {
if (other.license == null) { if (other.license == null) {

View File

@ -65,7 +65,9 @@ public class Licensing implements ActionPlugin {
new ActionHandler<>(GetLicenseAction.INSTANCE, TransportGetLicenseAction.class), new ActionHandler<>(GetLicenseAction.INSTANCE, TransportGetLicenseAction.class),
new ActionHandler<>(DeleteLicenseAction.INSTANCE, TransportDeleteLicenseAction.class), new ActionHandler<>(DeleteLicenseAction.INSTANCE, TransportDeleteLicenseAction.class),
new ActionHandler<>(PostStartTrialAction.INSTANCE, TransportPostStartTrialAction.class), new ActionHandler<>(PostStartTrialAction.INSTANCE, TransportPostStartTrialAction.class),
new ActionHandler<>(GetTrialStatusAction.INSTANCE, TransportGetTrialStatusAction.class)); new ActionHandler<>(GetTrialStatusAction.INSTANCE, TransportGetTrialStatusAction.class),
new ActionHandler<>(PostStartBasicAction.INSTANCE, TransportPostStartBasicAction.class),
new ActionHandler<>(GetBasicStatusAction.INSTANCE, TransportGetBasicStatusAction.class));
} }
@Override @Override
@ -77,7 +79,9 @@ public class Licensing implements ActionPlugin {
handlers.add(new RestPutLicenseAction(settings, restController)); handlers.add(new RestPutLicenseAction(settings, restController));
handlers.add(new RestDeleteLicenseAction(settings, restController)); handlers.add(new RestDeleteLicenseAction(settings, restController));
handlers.add(new RestGetTrialStatus(settings, restController)); handlers.add(new RestGetTrialStatus(settings, restController));
handlers.add(new RestGetBasicStatus(settings, restController));
handlers.add(new RestPostStartTrialLicense(settings, restController)); handlers.add(new RestPostStartTrialLicense(settings, restController));
handlers.add(new RestPostStartBasicLicense(settings, restController));
return handlers; return handlers;
} }

View File

@ -40,7 +40,7 @@ public class LicensingClient {
client.execute(DeleteLicenseAction.INSTANCE, request, listener); client.execute(DeleteLicenseAction.INSTANCE, request, listener);
} }
public PostStartTrialRequestBuilder preparePutUpgradeToTrial() { public PostStartTrialRequestBuilder preparePostUpgradeToTrial() {
return new PostStartTrialRequestBuilder(client, PostStartTrialAction.INSTANCE); return new PostStartTrialRequestBuilder(client, PostStartTrialAction.INSTANCE);
} }
@ -48,7 +48,19 @@ public class LicensingClient {
return new GetTrialStatusRequestBuilder(client, GetTrialStatusAction.INSTANCE); return new GetTrialStatusRequestBuilder(client, GetTrialStatusAction.INSTANCE);
} }
public void putUpgradeToTrial(PostStartTrialRequest request, ActionListener<PostStartTrialResponse> listener) { public void postUpgradeToTrial(PostStartTrialRequest request, ActionListener<PostStartTrialResponse> listener) {
client.execute(PostStartTrialAction.INSTANCE, request, listener); client.execute(PostStartTrialAction.INSTANCE, request, listener);
} }
public void postStartBasic(PostStartBasicRequest request, ActionListener<PostStartBasicResponse> listener) {
client.execute(PostStartBasicAction.INSTANCE, request, listener);
}
public PostStartBasicRequestBuilder preparePostStartBasic() {
return new PostStartBasicRequestBuilder(client, PostStartBasicAction.INSTANCE);
}
public GetBasicStatusRequestBuilder prepareGetStartBasic() {
return new GetBasicStatusRequestBuilder(client, GetBasicStatusAction.INSTANCE);
}
} }

View File

@ -0,0 +1,29 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.license;
import org.elasticsearch.action.Action;
import org.elasticsearch.client.ElasticsearchClient;
public class PostStartBasicAction extends Action<PostStartBasicRequest, PostStartBasicResponse, PostStartBasicRequestBuilder> {
public static final PostStartBasicAction INSTANCE = new PostStartBasicAction();
public static final String NAME = "cluster:admin/xpack/license/start_basic";
private PostStartBasicAction() {
super(NAME);
}
@Override
public PostStartBasicRequestBuilder newRequestBuilder(ElasticsearchClient client) {
return new PostStartBasicRequestBuilder(client, this);
}
@Override
public PostStartBasicResponse newResponse() {
return new PostStartBasicResponse();
}
}

View File

@ -0,0 +1,44 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.license;
import org.elasticsearch.action.ActionRequestValidationException;
import org.elasticsearch.action.support.master.AcknowledgedRequest;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import java.io.IOException;
public class PostStartBasicRequest extends AcknowledgedRequest<PostStartBasicRequest> {
private boolean acknowledge = false;
@Override
public ActionRequestValidationException validate() {
return null;
}
public PostStartBasicRequest acknowledge(boolean acknowledge) {
this.acknowledge = acknowledge;
return this;
}
public boolean isAcknowledged() {
return acknowledge;
}
@Override
public void readFrom(StreamInput in) throws IOException {
super.readFrom(in);
acknowledge = in.readBoolean();
}
@Override
public void writeTo(StreamOutput out) throws IOException {
super.writeTo(out);
out.writeBoolean(acknowledge);
}
}

View File

@ -0,0 +1,22 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.license;
import org.elasticsearch.action.ActionRequestBuilder;
import org.elasticsearch.client.ElasticsearchClient;
class PostStartBasicRequestBuilder extends ActionRequestBuilder<PostStartBasicRequest,
PostStartBasicResponse, PostStartBasicRequestBuilder> {
PostStartBasicRequestBuilder(ElasticsearchClient client, PostStartBasicAction action) {
super(client, action, new PostStartBasicRequest());
}
public PostStartBasicRequestBuilder setAcknowledge(boolean acknowledge) {
request.acknowledge(acknowledge);
return this;
}
}

View File

@ -0,0 +1,131 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.license;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.rest.RestStatus;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import static org.elasticsearch.license.PostStartBasicResponse.Status.NEED_ACKNOWLEDGEMENT;
class PostStartBasicResponse extends AcknowledgedResponse {
private Map<String, String[]> acknowledgeMessages;
private String acknowledgeMessage;
enum Status {
GENERATED_BASIC(true, null, RestStatus.OK),
ALREADY_USING_BASIC(false, "Operation failed: Current license is basic.", RestStatus.FORBIDDEN),
NEED_ACKNOWLEDGEMENT(false, "Operation failed: Needs acknowledgement.", RestStatus.OK);
private final boolean isBasicStarted;
private final String errorMessage;
private final RestStatus restStatus;
Status(boolean isBasicStarted, String errorMessage, RestStatus restStatus) {
this.isBasicStarted = isBasicStarted;
this.errorMessage = errorMessage;
this.restStatus = restStatus;
}
boolean isBasicStarted() {
return isBasicStarted;
}
String getErrorMessage() {
return errorMessage;
}
RestStatus getRestStatus() {
return restStatus;
}
}
private Status status;
PostStartBasicResponse() {
}
PostStartBasicResponse(Status status) {
this(status, Collections.emptyMap(), null);
}
PostStartBasicResponse(Status status, Map<String, String[]> acknowledgeMessages, String acknowledgeMessage) {
super(status != NEED_ACKNOWLEDGEMENT);
this.status = status;
this.acknowledgeMessages = acknowledgeMessages;
this.acknowledgeMessage = acknowledgeMessage;
}
public Status getStatus() {
return status;
}
@Override
public void readFrom(StreamInput in) throws IOException {
super.readFrom(in);
readAcknowledged(in);
status = in.readEnum(Status.class);
acknowledgeMessage = in.readOptionalString();
int size = in.readVInt();
Map<String, String[]> acknowledgeMessages = new HashMap<>(size);
for (int i = 0; i < size; i++) {
String feature = in.readString();
int nMessages = in.readVInt();
String[] messages = new String[nMessages];
for (int j = 0; j < nMessages; j++) {
messages[j] = in.readString();
}
acknowledgeMessages.put(feature, messages);
}
this.acknowledgeMessages = acknowledgeMessages;
}
@Override
public void writeTo(StreamOutput out) throws IOException {
super.writeTo(out);
writeAcknowledged(out);
out.writeEnum(status);
out.writeOptionalString(acknowledgeMessage);
out.writeVInt(acknowledgeMessages.size());
for (Map.Entry<String, String[]> entry : acknowledgeMessages.entrySet()) {
out.writeString(entry.getKey());
out.writeVInt(entry.getValue().length);
for (String message : entry.getValue()) {
out.writeString(message);
}
}
}
@Override
protected void addCustomFields(XContentBuilder builder, Params params) throws IOException {
if (status.isBasicStarted()) {
builder.field("basic_was_started", true);
} else {
builder.field("basic_was_started", false);
builder.field("error_message", status.getErrorMessage());
}
if (acknowledgeMessages.isEmpty() == false) {
builder.startObject("acknowledge");
builder.field("message", acknowledgeMessage);
for (Map.Entry<String, String[]> entry : acknowledgeMessages.entrySet()) {
builder.startArray(entry.getKey());
for (String message : entry.getValue()) {
builder.value(message);
}
builder.endArray();
}
builder.endObject();
}
}
}

View File

@ -0,0 +1,48 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.license;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.rest.BytesRestResponse;
import org.elasticsearch.rest.RestController;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.rest.RestResponse;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.rest.action.RestBuilderListener;
import org.elasticsearch.xpack.core.XPackClient;
import org.elasticsearch.xpack.core.rest.XPackRestHandler;
import java.io.IOException;
import static org.elasticsearch.rest.RestRequest.Method.GET;
public class RestGetBasicStatus extends XPackRestHandler {
RestGetBasicStatus(Settings settings, RestController controller) {
super(settings);
controller.registerHandler(GET, URI_BASE + "/license/basic_status", this);
}
@Override
protected RestChannelConsumer doPrepareRequest(RestRequest request, XPackClient client) throws IOException {
return channel -> client.licensing().prepareGetStartBasic().execute(
new RestBuilderListener<GetBasicStatusResponse>(channel) {
@Override
public RestResponse buildResponse(GetBasicStatusResponse response, XContentBuilder builder) throws Exception {
builder.startObject();
builder.field("eligible_to_start_basic", response.isEligibleToStartBasic());
builder.endObject();
return new BytesRestResponse(RestStatus.OK, builder);
}
});
}
@Override
public String getName() {
return "xpack_basic_status_action";
}
}

View File

@ -0,0 +1,50 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.license;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.rest.BytesRestResponse;
import org.elasticsearch.rest.RestController;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.rest.RestResponse;
import org.elasticsearch.rest.action.RestBuilderListener;
import org.elasticsearch.xpack.core.XPackClient;
import org.elasticsearch.xpack.core.rest.XPackRestHandler;
import java.io.IOException;
import static org.elasticsearch.rest.RestRequest.Method.POST;
public class RestPostStartBasicLicense extends XPackRestHandler {
RestPostStartBasicLicense(Settings settings, RestController controller) {
super(settings);
controller.registerHandler(POST, URI_BASE + "/license/start_basic", this);
}
@Override
protected RestChannelConsumer doPrepareRequest(RestRequest request, XPackClient client) throws IOException {
PostStartBasicRequest startBasicRequest = new PostStartBasicRequest();
startBasicRequest.acknowledge(request.paramAsBoolean("acknowledge", false));
startBasicRequest.timeout(request.paramAsTime("timeout", startBasicRequest.timeout()));
startBasicRequest.masterNodeTimeout(request.paramAsTime("master_timeout", startBasicRequest.masterNodeTimeout()));
return channel -> client.licensing().postStartBasic(startBasicRequest, new RestBuilderListener<PostStartBasicResponse>(channel) {
@Override
public RestResponse buildResponse(PostStartBasicResponse response, XContentBuilder builder) throws Exception {
PostStartBasicResponse.Status status = response.getStatus();
response.toXContent(builder, ToXContent.EMPTY_PARAMS);
return new BytesRestResponse(status.getRestStatus(), builder);
}
});
}
@Override
public String getName() {
return "xpack_start_basic_action";
}
}

View File

@ -29,7 +29,7 @@ public class RestPostStartTrialLicense extends XPackRestHandler {
@Override @Override
protected RestChannelConsumer doPrepareRequest(RestRequest request, XPackClient client) throws IOException { protected RestChannelConsumer doPrepareRequest(RestRequest request, XPackClient client) throws IOException {
return channel -> client.licensing().preparePutUpgradeToTrial().execute( return channel -> client.licensing().preparePostUpgradeToTrial().execute(
new RestBuilderListener<PostStartTrialResponse>(channel) { new RestBuilderListener<PostStartTrialResponse>(channel) {
@Override @Override
public RestResponse buildResponse(PostStartTrialResponse response, XContentBuilder builder) throws Exception { public RestResponse buildResponse(PostStartTrialResponse response, XContentBuilder builder) throws Exception {

View File

@ -0,0 +1,99 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.license;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.message.ParameterizedMessage;
import org.elasticsearch.Version;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.ClusterStateUpdateTask;
import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.common.Nullable;
import java.time.Clock;
import java.util.Collections;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicReference;
public class StartBasicClusterTask extends ClusterStateUpdateTask {
private static final String ACKNOWLEDGEMENT_HEADER = "This license update requires acknowledgement. To acknowledge the license, " +
"please read the following messages and call /start_basic again, this time with the \"acknowledge=true\" parameter:";
private final Logger logger;
private final String clusterName;
private final PostStartBasicRequest request;
private final ActionListener<PostStartBasicResponse> listener;
private final Clock clock;
private AtomicReference<Map<String, String[]>> ackMessages = new AtomicReference<>(Collections.emptyMap());
StartBasicClusterTask(Logger logger, String clusterName, Clock clock, PostStartBasicRequest request,
ActionListener<PostStartBasicResponse> listener) {
this.logger = logger;
this.clusterName = clusterName;
this.request = request;
this.listener = listener;
this.clock = clock;
}
@Override
public void clusterStateProcessed(String source, ClusterState oldState, ClusterState newState) {
LicensesMetaData oldLicensesMetaData = oldState.metaData().custom(LicensesMetaData.TYPE);
logger.debug("license prior to starting basic license: {}", oldLicensesMetaData);
License oldLicense = LicensesMetaData.extractLicense(oldLicensesMetaData);
Map<String, String[]> acknowledgeMessages = ackMessages.get();
if (acknowledgeMessages.isEmpty() == false) {
listener.onResponse(new PostStartBasicResponse(PostStartBasicResponse.Status.NEED_ACKNOWLEDGEMENT, acknowledgeMessages,
ACKNOWLEDGEMENT_HEADER));
} else if (oldLicense != null && oldLicense.type().equals("basic")) {
listener.onResponse(new PostStartBasicResponse(PostStartBasicResponse.Status.ALREADY_USING_BASIC));
} else {
listener.onResponse(new PostStartBasicResponse(PostStartBasicResponse.Status.GENERATED_BASIC));
}
}
@Override
public ClusterState execute(ClusterState currentState) throws Exception {
LicensesMetaData licensesMetaData = currentState.metaData().custom(LicensesMetaData.TYPE);
License currentLicense = LicensesMetaData.extractLicense(licensesMetaData);
if (currentLicense == null || currentLicense.type().equals("basic") == false) {
long issueDate = clock.millis();
MetaData.Builder mdBuilder = MetaData.builder(currentState.metaData());
License.Builder specBuilder = License.builder()
.uid(UUID.randomUUID().toString())
.issuedTo(clusterName)
.maxNodes(LicenseService.SELF_GENERATED_LICENSE_MAX_NODES)
.issueDate(issueDate)
.type("basic")
.expiryDate(issueDate + LicenseService.BASIC_SELF_GENERATED_LICENSE_EXPIRATION_MILLIS);
License selfGeneratedLicense = SelfGeneratedLicense.create(specBuilder);
if (request.isAcknowledged() == false && currentLicense != null) {
Map<String, String[]> ackMessages = LicenseService.getAckMessages(selfGeneratedLicense, currentLicense);
if (ackMessages.isEmpty() == false) {
this.ackMessages.set(ackMessages);
return currentState;
}
}
Version trialVersion = null;
if (licensesMetaData != null) {
trialVersion = licensesMetaData.getMostRecentTrialVersion();
}
LicensesMetaData newLicensesMetaData = new LicensesMetaData(selfGeneratedLicense, trialVersion);
mdBuilder.putCustom(LicensesMetaData.TYPE, newLicensesMetaData);
return ClusterState.builder(currentState).metaData(mdBuilder).build();
} else {
return currentState;
}
}
@Override
public void onFailure(String source, @Nullable Exception e) {
logger.error(new ParameterizedMessage("unexpected failure during [{}]", source), e);
listener.onFailure(e);
}
}

View File

@ -0,0 +1,58 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.license;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.support.ActionFilters;
import org.elasticsearch.action.support.master.TransportMasterNodeReadAction;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.block.ClusterBlockException;
import org.elasticsearch.cluster.block.ClusterBlockLevel;
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportService;
public class TransportGetBasicStatusAction extends TransportMasterNodeReadAction<GetBasicStatusRequest, GetBasicStatusResponse> {
@Inject
public TransportGetBasicStatusAction(Settings settings, TransportService transportService, ClusterService clusterService,
ThreadPool threadPool, ActionFilters actionFilters,
IndexNameExpressionResolver indexNameExpressionResolver) {
super(settings, GetBasicStatusAction.NAME, transportService, clusterService, threadPool, actionFilters,
GetBasicStatusRequest::new, indexNameExpressionResolver);
}
@Override
protected String executor() {
return ThreadPool.Names.SAME;
}
@Override
protected GetBasicStatusResponse newResponse() {
return new GetBasicStatusResponse();
}
@Override
protected void masterOperation(GetBasicStatusRequest request, ClusterState state,
ActionListener<GetBasicStatusResponse> listener) throws Exception {
LicensesMetaData licensesMetaData = state.metaData().custom(LicensesMetaData.TYPE);
if (licensesMetaData == null) {
listener.onResponse(new GetBasicStatusResponse(true));
} else {
License license = licensesMetaData.getLicense();
listener.onResponse(new GetBasicStatusResponse(license == null || license.type().equals("basic") == false));
}
}
@Override
protected ClusterBlockException checkBlock(GetBasicStatusRequest request, ClusterState state) {
return state.blocks().globalBlockedException(ClusterBlockLevel.METADATA_READ);
}
}

View File

@ -0,0 +1,54 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.license;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.support.ActionFilters;
import org.elasticsearch.action.support.master.TransportMasterNodeAction;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.block.ClusterBlockException;
import org.elasticsearch.cluster.block.ClusterBlockLevel;
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportService;
public class TransportPostStartBasicAction extends TransportMasterNodeAction<PostStartBasicRequest, PostStartBasicResponse> {
private final LicenseService licenseService;
@Inject
public TransportPostStartBasicAction(Settings settings, TransportService transportService, ClusterService clusterService,
LicenseService licenseService, ThreadPool threadPool, ActionFilters actionFilters,
IndexNameExpressionResolver indexNameExpressionResolver) {
super(settings, PostStartBasicAction.NAME, transportService, clusterService, threadPool, actionFilters,
indexNameExpressionResolver, PostStartBasicRequest::new);
this.licenseService = licenseService;
}
@Override
protected String executor() {
return ThreadPool.Names.SAME;
}
@Override
protected PostStartBasicResponse newResponse() {
return new PostStartBasicResponse();
}
@Override
protected void masterOperation(PostStartBasicRequest request, ClusterState state,
ActionListener<PostStartBasicResponse> listener) throws Exception {
licenseService.startBasicLicense(request, listener);
}
@Override
protected ClusterBlockException checkBlock(PostStartBasicRequest request, ClusterState state) {
return state.blocks().globalBlockedException(ClusterBlockLevel.METADATA_WRITE);
}
}

View File

@ -19,6 +19,7 @@ import org.elasticsearch.common.util.PageCacheRecycler;
import org.elasticsearch.common.xcontent.NamedXContentRegistry; import org.elasticsearch.common.xcontent.NamedXContentRegistry;
import org.elasticsearch.indices.breaker.CircuitBreakerService; import org.elasticsearch.indices.breaker.CircuitBreakerService;
import org.elasticsearch.license.DeleteLicenseAction; import org.elasticsearch.license.DeleteLicenseAction;
import org.elasticsearch.license.GetBasicStatusAction;
import org.elasticsearch.license.GetLicenseAction; import org.elasticsearch.license.GetLicenseAction;
import org.elasticsearch.license.GetTrialStatusAction; import org.elasticsearch.license.GetTrialStatusAction;
import org.elasticsearch.license.LicenseService; import org.elasticsearch.license.LicenseService;
@ -290,6 +291,7 @@ public class XPackClientPlugin extends Plugin implements ActionPlugin, NetworkPl
DeleteLicenseAction.INSTANCE, DeleteLicenseAction.INSTANCE,
PostStartTrialAction.INSTANCE, PostStartTrialAction.INSTANCE,
GetTrialStatusAction.INSTANCE, GetTrialStatusAction.INSTANCE,
GetBasicStatusAction.INSTANCE,
// x-pack // x-pack
XPackInfoAction.INSTANCE, XPackInfoAction.INSTANCE,
XPackUsageAction.INSTANCE, XPackUsageAction.INSTANCE,

View File

@ -17,7 +17,6 @@ import java.util.UUID;
import static org.elasticsearch.license.TestUtils.dateMath; import static org.elasticsearch.license.TestUtils.dateMath;
import static org.mockito.Matchers.any; import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;

View File

@ -0,0 +1,112 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.license;
import org.elasticsearch.client.Response;
import org.elasticsearch.client.ResponseException;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.common.io.Streams;
import org.elasticsearch.common.network.NetworkModule;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.transport.Netty4Plugin;
import org.elasticsearch.xpack.core.LocalStateCompositeXPackPlugin;
import org.elasticsearch.xpack.core.XPackClientPlugin;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collection;
import static org.elasticsearch.test.ESIntegTestCase.Scope.SUITE;
@ESIntegTestCase.ClusterScope(scope = SUITE)
public class StartBasicLicenseTests extends AbstractLicensesIntegrationTestCase {
@Override
protected Settings nodeSettings(int nodeOrdinal) {
return Settings.builder()
.put(super.nodeSettings(nodeOrdinal))
.put("node.data", true)
.put(LicenseService.SELF_GENERATED_LICENSE_TYPE.getKey(), "basic")
.put(NetworkModule.HTTP_ENABLED.getKey(), true).build();
}
@Override
protected Collection<Class<? extends Plugin>> nodePlugins() {
return Arrays.asList(LocalStateCompositeXPackPlugin.class, Netty4Plugin.class);
}
@Override
protected Collection<Class<? extends Plugin>> transportClientPlugins() {
return Arrays.asList(XPackClientPlugin.class, Netty4Plugin.class);
}
public void testStartBasicLicense() throws Exception {
LicensingClient licensingClient = new LicensingClient(client());
License license = TestUtils.generateSignedLicense("trial", License.VERSION_CURRENT, -1, TimeValue.timeValueHours(24));
licensingClient.preparePutLicense(license).get();
assertBusy(() -> {
GetLicenseResponse getLicenseResponse = licensingClient.prepareGetLicense().get();
assertEquals("trial", getLicenseResponse.license().type());
});
// Testing that you can start a basic license when you have no license
if (randomBoolean()) {
licensingClient.prepareDeleteLicense().get();
assertNull(licensingClient.prepareGetLicense().get().license());
}
RestClient restClient = getRestClient();
Response response = restClient.performRequest("GET", "/_xpack/license/basic_status");
String body = Streams.copyToString(new InputStreamReader(response.getEntity().getContent(), StandardCharsets.UTF_8));
assertEquals(200, response.getStatusLine().getStatusCode());
assertEquals("{\"eligible_to_start_basic\":true}", body);
Response response2 = restClient.performRequest("POST", "/_xpack/license/start_basic?acknowledge=true");
String body2 = Streams.copyToString(new InputStreamReader(response2.getEntity().getContent(), StandardCharsets.UTF_8));
assertEquals(200, response2.getStatusLine().getStatusCode());
assertTrue(body2.contains("\"acknowledged\":true"));
assertTrue(body2.contains("\"basic_was_started\":true"));
Response response3 = restClient.performRequest("GET", "/_xpack/license/basic_status");
String body3 = Streams.copyToString(new InputStreamReader(response3.getEntity().getContent(), StandardCharsets.UTF_8));
assertEquals(200, response3.getStatusLine().getStatusCode());
assertEquals("{\"eligible_to_start_basic\":false}", body3);
ResponseException ex = expectThrows(ResponseException.class,
() -> restClient.performRequest("POST", "/_xpack/license/start_basic"));
Response response4 = ex.getResponse();
String body4 = Streams.copyToString(new InputStreamReader(response4.getEntity().getContent(), StandardCharsets.UTF_8));
assertEquals(403, response4.getStatusLine().getStatusCode());
assertTrue(body4.contains("\"basic_was_started\":false"));
assertTrue(body4.contains("\"acknowledged\":true"));
assertTrue(body4.contains("\"error_message\":\"Operation failed: Current license is basic.\""));
}
public void testUnacknowledgedStartBasicLicense() throws Exception {
LicensingClient licensingClient = new LicensingClient(client());
License license = TestUtils.generateSignedLicense("trial", License.VERSION_CURRENT, -1, TimeValue.timeValueHours(24));
licensingClient.preparePutLicense(license).get();
assertBusy(() -> {
GetLicenseResponse getLicenseResponse = licensingClient.prepareGetLicense().get();
assertEquals("trial", getLicenseResponse.license().type());
});
Response response2 = getRestClient().performRequest("POST", "/_xpack/license/start_basic");
String body2 = Streams.copyToString(new InputStreamReader(response2.getEntity().getContent(), StandardCharsets.UTF_8));
assertEquals(200, response2.getStatusLine().getStatusCode());
assertTrue(body2.contains("\"acknowledged\":false"));
assertTrue(body2.contains("\"basic_was_started\":false"));
assertTrue(body2.contains("\"error_message\":\"Operation failed: Needs acknowledgement.\""));
assertTrue(body2.contains("\"message\":\"This license update requires acknowledgement. To acknowledge the license, " +
"please read the following messages and call /start_basic again, this time with the \\\"acknowledge=true\\\""));
}
}

View File

@ -25,7 +25,7 @@ import java.util.Collection;
import static org.elasticsearch.test.ESIntegTestCase.Scope.SUITE; import static org.elasticsearch.test.ESIntegTestCase.Scope.SUITE;
@ESIntegTestCase.ClusterScope(scope = SUITE) @ESIntegTestCase.ClusterScope(scope = SUITE)
public class UpgradeToTrialTests extends AbstractLicensesIntegrationTestCase { public class StartTrialLicenseTests extends AbstractLicensesIntegrationTestCase {
@Override @Override
protected Settings nodeSettings(int nodeOrdinal) { protected Settings nodeSettings(int nodeOrdinal) {

View File

@ -0,0 +1,15 @@
{
"xpack.license.get_basic_status": {
"documentation": "https://www.elastic.co/guide/en/x-pack/current/license-management.html",
"methods": ["GET"],
"url": {
"path": "/_xpack/license/basic_status",
"paths": ["/_xpack/license/basic_status"],
"parts" : {
},
"params": {
}
},
"body": null
}
}

View File

@ -0,0 +1,19 @@
{
"xpack.license.post_start_basic": {
"documentation": "https://www.elastic.co/guide/en/x-pack/current/license-management.html",
"methods": ["POST"],
"url": {
"path": "/_xpack/license/start_basic",
"paths": ["/_xpack/license/start_basic"],
"parts" : {
},
"params": {
"acknowledge": {
"type" : "boolean",
"description" : "whether the user has acknowledged acknowledge messages (default: false)"
}
}
},
"body": null
}
}

View File

@ -8,64 +8,63 @@ teardown:
--- ---
"Installing and getting license works": "Installing and getting license works":
## current license version ## current license version
- do: - do:
xpack.license.post: xpack.license.post:
acknowledge: true acknowledge: true
body: | body: |
{"license":{"uid":"893361dc-9749-4997-93cb-802e3d7fa4a8","type":"basic","issue_date_in_millis":1411948800000,"expiry_date_in_millis":1914278399999,"max_nodes":1,"issued_to":"issuedTo","issuer":"issuer","signature":"AAAAAgAAAA0lKPZ0a7aZquUltho/AAABmC9ZN0hjZDBGYnVyRXpCOW5Bb3FjZDAxOWpSbTVoMVZwUzRxVk1PSmkxakxZdW5IMlhlTHNoN1N2MXMvRFk4d3JTZEx3R3RRZ0pzU3lobWJKZnQvSEFva0ppTHBkWkprZWZSQi9iNmRQNkw1SlpLN0lDalZCS095MXRGN1lIZlpYcVVTTnFrcTE2dzhJZmZrdFQrN3JQeGwxb0U0MXZ0dDJHSERiZTVLOHNzSDByWnpoZEphZHBEZjUrTVBxRENNSXNsWWJjZllaODdzVmEzUjNiWktNWGM5TUhQV2plaUo4Q1JOUml4MXNuL0pSOEhQaVB2azhmUk9QVzhFeTFoM1Q0RnJXSG53MWk2K055c28zSmRnVkF1b2JSQkFLV2VXUmVHNDZ2R3o2VE1qbVNQS2lxOHN5bUErZlNIWkZSVmZIWEtaSU9wTTJENDVvT1NCYklacUYyK2FwRW9xa0t6dldMbmMzSGtQc3FWOTgzZ3ZUcXMvQkt2RUZwMFJnZzlvL2d2bDRWUzh6UG5pdENGWFRreXNKNkE9PQAAAQAALuQ44S3IG6SzolcXVJ6Z4CIXORDrYQ+wdLCeey0XdujTslAOj+k+vNgo6wauc7Uswi01esHu4lb5IgpvKy7RRCbh5bj/z2ubu2qMJqopp9BQyD7VQjVfqmG6seUMJwJ1a5Avvm9r41YPSPcrii3bKK2e1l6jK6N8ibCvnTyY/XkYGCJrBWTSJePDbg6ErbyodrZ37x1StLbPWcNAkmweyHjDJnvYnbeZZO7A3NmubXZjW7Ttf8/YwQyE00PqMcl7fVPY3hkKpAeHf8aaJbqkKYbqZuER3EWJX7ZvLVb1dNdNg8aXRn7YrkQcYwWgptYQpfV+D7yEJ4j5muAEoler"}} {"licenses":[{"uid":"894371dc-9t49-4997-93cb-8o2e3r7fa6a8","type":"trial","issue_date_in_millis":1411948800000,"expiry_date_in_millis":1916956799999,"max_nodes":1,"issued_to":"issuedTo","issuer":"issuer","signature":"AAAAAgAAAA0FWh0T9njItjQ2qammAAABmC9ZN0hjZDBGYnVyRXpCOW5Bb3FjZDAxOWpSbTVoMVZwUzRxVk1PSmkxakxZdW5IMlhlTHNoN1N2MXMvRFk4d3JTZEx3R3RRZ0pzU3lobWJKZnQvSEFva0ppTHBkWkprZWZSQi9iNmRQNkw1SlpLN0lDalZCS095MXRGN1lIZlpYcVVTTnFrcTE2dzhJZmZrdFQrN3JQeGwxb0U0MXZ0dDJHSERiZTVLOHNzSDByWnpoZEphZHBEZjUrTVBxRENNSXNsWWJjZllaODdzVmEzUjNiWktNWGM5TUhQV2plaUo4Q1JOUml4MXNuL0pSOEhQaVB2azhmUk9QVzhFeTFoM1Q0RnJXSG53MWk2K055c28zSmRnVkF1b2JSQkFLV2VXUmVHNDZ2R3o2VE1qbVNQS2lxOHN5bUErZlNIWkZSVmZIWEtaSU9wTTJENDVvT1NCYklacUYyK2FwRW9xa0t6dldMbmMzSGtQc3FWOTgzZ3ZUcXMvQkt2RUZwMFJnZzlvL2d2bDRWUzh6UG5pdENGWFRreXNKNkE9PQAAAQBZhvozA0trrxhUZ1QbaTsKTna9C5KVQ6pv8yg1pnsBpZXCl8kX1SrgoFn1bXq61IvJwfw5qnmYNiH3hRhTO9EyaCBqaLk8NXZQ6TrRkQSpEnnBwAYUkZeKXsIuBoOk4B4mzwC/r8aMAkzrTiEBtBbog+57cSaU9y37Gkdd+1jXCQrxP+jOEUf7gnXWZvE6oeRroLvCt1fYn09k0CF8kKTbrPTSjC6igZR3uvTHyee74XQ9PRavvHax73T4UOEdQZX/P1ibSQIWKbBRD5YQ1POYVjTayoltTnWLMxfEcAkkATJZLhpBEHST7kZWjrTS6J1dCReJc7a8Vsj/78HXvOIy"}]}
- match: { license_status: "valid" } - match: { license_status: "valid" }
- do: - do:
xpack.license.get: {} xpack.license.get: {}
## a license object has 11 attributes ## a license object has 11 attributes
- length: { license: 11 } - length: { license: 11 }
## bwc for licenses format ## bwc for licenses format
- do: - do:
xpack.license.post: xpack.license.post:
acknowledge: true acknowledge: true
body: | body: |
{"licenses":[{"uid":"893361dc-9749-4997-93cb-802e3d7fa4a8","type":"basic","issue_date_in_millis":1411948800000,"expiry_date_in_millis":1914278399999,"max_nodes":1,"issued_to":"issuedTo","issuer":"issuer","signature":"AAAAAgAAAA0lKPZ0a7aZquUltho/AAABmC9ZN0hjZDBGYnVyRXpCOW5Bb3FjZDAxOWpSbTVoMVZwUzRxVk1PSmkxakxZdW5IMlhlTHNoN1N2MXMvRFk4d3JTZEx3R3RRZ0pzU3lobWJKZnQvSEFva0ppTHBkWkprZWZSQi9iNmRQNkw1SlpLN0lDalZCS095MXRGN1lIZlpYcVVTTnFrcTE2dzhJZmZrdFQrN3JQeGwxb0U0MXZ0dDJHSERiZTVLOHNzSDByWnpoZEphZHBEZjUrTVBxRENNSXNsWWJjZllaODdzVmEzUjNiWktNWGM5TUhQV2plaUo4Q1JOUml4MXNuL0pSOEhQaVB2azhmUk9QVzhFeTFoM1Q0RnJXSG53MWk2K055c28zSmRnVkF1b2JSQkFLV2VXUmVHNDZ2R3o2VE1qbVNQS2lxOHN5bUErZlNIWkZSVmZIWEtaSU9wTTJENDVvT1NCYklacUYyK2FwRW9xa0t6dldMbmMzSGtQc3FWOTgzZ3ZUcXMvQkt2RUZwMFJnZzlvL2d2bDRWUzh6UG5pdENGWFRreXNKNkE9PQAAAQAALuQ44S3IG6SzolcXVJ6Z4CIXORDrYQ+wdLCeey0XdujTslAOj+k+vNgo6wauc7Uswi01esHu4lb5IgpvKy7RRCbh5bj/z2ubu2qMJqopp9BQyD7VQjVfqmG6seUMJwJ1a5Avvm9r41YPSPcrii3bKK2e1l6jK6N8ibCvnTyY/XkYGCJrBWTSJePDbg6ErbyodrZ37x1StLbPWcNAkmweyHjDJnvYnbeZZO7A3NmubXZjW7Ttf8/YwQyE00PqMcl7fVPY3hkKpAeHf8aaJbqkKYbqZuER3EWJX7ZvLVb1dNdNg8aXRn7YrkQcYwWgptYQpfV+D7yEJ4j5muAEoler"}]} {"licenses":[{"uid":"893361dc-9749-4997-93cb-802e3d7fa4a8","type":"basic","issue_date_in_millis":1411948800000,"expiry_date_in_millis":1914278399999,"max_nodes":1,"issued_to":"issuedTo","issuer":"issuer","signature":"AAAAAgAAAA0lKPZ0a7aZquUltho/AAABmC9ZN0hjZDBGYnVyRXpCOW5Bb3FjZDAxOWpSbTVoMVZwUzRxVk1PSmkxakxZdW5IMlhlTHNoN1N2MXMvRFk4d3JTZEx3R3RRZ0pzU3lobWJKZnQvSEFva0ppTHBkWkprZWZSQi9iNmRQNkw1SlpLN0lDalZCS095MXRGN1lIZlpYcVVTTnFrcTE2dzhJZmZrdFQrN3JQeGwxb0U0MXZ0dDJHSERiZTVLOHNzSDByWnpoZEphZHBEZjUrTVBxRENNSXNsWWJjZllaODdzVmEzUjNiWktNWGM5TUhQV2plaUo4Q1JOUml4MXNuL0pSOEhQaVB2azhmUk9QVzhFeTFoM1Q0RnJXSG53MWk2K055c28zSmRnVkF1b2JSQkFLV2VXUmVHNDZ2R3o2VE1qbVNQS2lxOHN5bUErZlNIWkZSVmZIWEtaSU9wTTJENDVvT1NCYklacUYyK2FwRW9xa0t6dldMbmMzSGtQc3FWOTgzZ3ZUcXMvQkt2RUZwMFJnZzlvL2d2bDRWUzh6UG5pdENGWFRreXNKNkE9PQAAAQAALuQ44S3IG6SzolcXVJ6Z4CIXORDrYQ+wdLCeey0XdujTslAOj+k+vNgo6wauc7Uswi01esHu4lb5IgpvKy7RRCbh5bj/z2ubu2qMJqopp9BQyD7VQjVfqmG6seUMJwJ1a5Avvm9r41YPSPcrii3bKK2e1l6jK6N8ibCvnTyY/XkYGCJrBWTSJePDbg6ErbyodrZ37x1StLbPWcNAkmweyHjDJnvYnbeZZO7A3NmubXZjW7Ttf8/YwQyE00PqMcl7fVPY3hkKpAeHf8aaJbqkKYbqZuER3EWJX7ZvLVb1dNdNg8aXRn7YrkQcYwWgptYQpfV+D7yEJ4j5muAEoler"}]}
- match: { license_status: "valid" } - match: { license_status: "valid" }
- do: - do:
xpack.license.get: {} xpack.license.get: {}
- length: { license: 11 } - length: { license: 11 }
## license version: 1.x ## license version: 1.x
- do: - do:
xpack.license.post: xpack.license.post:
acknowledge: true acknowledge: true
body: | body: |
{"licenses":[{"uid":"893361dc-9749-4997-93cb-802e3d7fa4a8","type":"subscription","subscription_type":"gold","issue_date_in_millis":1411948800000,"feature":"shield","expiry_date_in_millis":1914278399999,"max_nodes":1,"issued_to":"issuedTo","issuer":"issuer","signature":"AAAAAQAAAA0LVAywwpSH94cyXr4zAAABmC9ZN0hjZDBGYnVyRXpCOW5Bb3FjZDAxOWpSbTVoMVZwUzRxVk1PSmkxakxZdW5IMlhlTHNoN1N2MXMvRFk4d3JTZEx3R3RRZ0pzU3lobWJKZnQvSEFva0ppTHBkWkprZWZSQi9iNmRQNkw1SlpLN0lDalZCS095MXRGN1lIZlpYcVVTTnFrcTE2dzhJZmZrdFQrN3JQeGwxb0U0MXZ0dDJHSERiZTVLOHNzSDByWnpoZEphZHBEZjUrTVBxRENNSXNsWWJjZllaODdzVmEzUjNiWktNWGM5TUhQV2plaUo4Q1JOUml4MXNuL0pSOEhQaVB2azhmUk9QVzhFeTFoM1Q0RnJXSG53MWk2K055c28zSmRnVkF1b2JSQkFLV2VXUmVHNDZ2R3o2VE1qbVNQS2lxOHN5bUErZlNIWkZSVmZIWEtaSU9wTTJENDVvT1NCYklacUYyK2FwRW9xa0t6dldMbmMzSGtQc3FWOTgzZ3ZUcXMvQkt2RUZwMFJnZzlvL2d2bDRWUzh6UG5pdENGWFRreXNKNkE9PQAAAQA4qscc/URRZVdFoLwgy9dqybYEQLW8YLkiAyPV5XHHHdtk+dtZIepiNEDkUXhSX2waVJlsNRF8/4kqplDfwNoD2TUM8fTgiIfiSiZYGDTGST+yW/5eAveEU5J5v1liBN27bwkqL+V4YAa0Tcm7NKKwjScWKAHiTU3vF8chPkGfCHE0kQgVwPC9RE82pTw0s6/uR4PfLGNFfqPM0uiE5nucfVrtj89JQiO/KA/7ZyFbo7VTNXxZQt7T7rZWBCP9KIjptXzcWuk08Q5S+rSoJNYbFo3HGKtrCVsRz/55rceNtdwKKXu1IwnSeir4I1/KLduQTtFLy0+1th87VS8T88UT"}]} {"licenses":[{"uid":"893361dc-9749-4997-93cb-802e3d7fa4a8","type":"subscription","subscription_type":"gold","issue_date_in_millis":1411948800000,"feature":"shield","expiry_date_in_millis":1914278399999,"max_nodes":1,"issued_to":"issuedTo","issuer":"issuer","signature":"AAAAAQAAAA0LVAywwpSH94cyXr4zAAABmC9ZN0hjZDBGYnVyRXpCOW5Bb3FjZDAxOWpSbTVoMVZwUzRxVk1PSmkxakxZdW5IMlhlTHNoN1N2MXMvRFk4d3JTZEx3R3RRZ0pzU3lobWJKZnQvSEFva0ppTHBkWkprZWZSQi9iNmRQNkw1SlpLN0lDalZCS095MXRGN1lIZlpYcVVTTnFrcTE2dzhJZmZrdFQrN3JQeGwxb0U0MXZ0dDJHSERiZTVLOHNzSDByWnpoZEphZHBEZjUrTVBxRENNSXNsWWJjZllaODdzVmEzUjNiWktNWGM5TUhQV2plaUo4Q1JOUml4MXNuL0pSOEhQaVB2azhmUk9QVzhFeTFoM1Q0RnJXSG53MWk2K055c28zSmRnVkF1b2JSQkFLV2VXUmVHNDZ2R3o2VE1qbVNQS2lxOHN5bUErZlNIWkZSVmZIWEtaSU9wTTJENDVvT1NCYklacUYyK2FwRW9xa0t6dldMbmMzSGtQc3FWOTgzZ3ZUcXMvQkt2RUZwMFJnZzlvL2d2bDRWUzh6UG5pdENGWFRreXNKNkE9PQAAAQA4qscc/URRZVdFoLwgy9dqybYEQLW8YLkiAyPV5XHHHdtk+dtZIepiNEDkUXhSX2waVJlsNRF8/4kqplDfwNoD2TUM8fTgiIfiSiZYGDTGST+yW/5eAveEU5J5v1liBN27bwkqL+V4YAa0Tcm7NKKwjScWKAHiTU3vF8chPkGfCHE0kQgVwPC9RE82pTw0s6/uR4PfLGNFfqPM0uiE5nucfVrtj89JQiO/KA/7ZyFbo7VTNXxZQt7T7rZWBCP9KIjptXzcWuk08Q5S+rSoJNYbFo3HGKtrCVsRz/55rceNtdwKKXu1IwnSeir4I1/KLduQTtFLy0+1th87VS8T88UT"}]}
- match: { license_status: "valid" } - match: { license_status: "valid" }
- do: - do:
xpack.license.get: {} xpack.license.get: {}
- length: { license: 11 } - length: { license: 11 }
## multiple licenses version: 1.x ## multiple licenses version: 1.x
- do: - do:
xpack.license.post: xpack.license.post:
acknowledge: true acknowledge: true
body: | body: |
{"licenses":[{"uid":"893361dc-9749-4997-93cb-802e3d7fa4a8","type":"internal","subscription_type":"none","issue_date_in_millis":1411948800000,"feature":"shield","expiry_date_in_millis":1440892799999,"max_nodes":1,"issued_to":"issuedTo","issuer":"issuer","signature":"AAAAAQAAAA04Q4ky3rFyyWLFkytEAAABmC9ZN0hjZDBGYnVyRXpCOW5Bb3FjZDAxOWpSbTVoMVZwUzRxVk1PSmkxakxZdW5IMlhlTHNoN1N2MXMvRFk4d3JTZEx3R3RRZ0pzU3lobWJKZnQvSEFva0ppTHBkWkprZWZSQi9iNmRQNkw1SlpLN0lDalZCS095MXRGN1lIZlpYcVVTTnFrcTE2dzhJZmZrdFQrN3JQeGwxb0U0MXZ0dDJHSERiZTVLOHNzSDByWnpoZEphZHBEZjUrTVBxRENNSXNsWWJjZllaODdzVmEzUjNiWktNWGM5TUhQV2plaUo4Q1JOUml4MXNuL0pSOEhQaVB2azhmUk9QVzhFeTFoM1Q0RnJXSG53MWk2K055c28zSmRnVkF1b2JSQkFLV2VXUmVHNDZ2R3o2VE1qbVNQS2lxOHN5bUErZlNIWkZSVmZIWEtaSU9wTTJENDVvT1NCYklacUYyK2FwRW9xa0t6dldMbmMzSGtQc3FWOTgzZ3ZUcXMvQkt2RUZwMFJnZzlvL2d2bDRWUzh6UG5pdENGWFRreXNKNkE9PQAAAQBxMvUMn4h2E4R4TQMijahTxQj4LPQO4f1M79UxX/XkDlGcH+J5pRHx08OtTRPsFL1lED+h+PIXx307Vo+PNDsOxrWvoYZeYBkOLAO3ny9vhQga+52jYhMxIuFrT9xbcSCSNpMhGojgOIPU2WgiopVdVcimo1+Gk8VtklPB1wPwFzfOjOnPgp/Icx3WYpfkeAUUOyWUYiFIBAe4bnz84iF+xwLKbgYk6aHF25ECBtdb/Uruhcm9+jEFpoIEUtCouvvk9C+NJZ4OickV4xpRgaRG2x9PONH8ZN0QGhGYhJGbisoCxuDmlLsyVxqxfMu3n/r7/jdsEJScjAlSrsLDOu6H"},{"uid":"893361dc-9749-4997-93cb-802e3dofh7aa","type":"internal","subscription_type":"none","issue_date_in_millis":1443484800000,"feature":"watcher","expiry_date_in_millis":1914278399999,"max_nodes":1,"issued_to":"issuedTo","issuer":"issuer","signature":"AAAAAQAAAA0Sc90guRIaQEmgLvMnAAABmC9ZN0hjZDBGYnVyRXpCOW5Bb3FjZDAxOWpSbTVoMVZwUzRxVk1PSmkxakxZdW5IMlhlTHNoN1N2MXMvRFk4d3JTZEx3R3RRZ0pzU3lobWJKZnQvSEFva0ppTHBkWkprZWZSQi9iNmRQNkw1SlpLN0lDalZCS095MXRGN1lIZlpYcVVTTnFrcTE2dzhJZmZrdFQrN3JQeGwxb0U0MXZ0dDJHSERiZTVLOHNzSDByWnpoZEphZHBEZjUrTVBxRENNSXNsWWJjZllaODdzVmEzUjNiWktNWGM5TUhQV2plaUo4Q1JOUml4MXNuL0pSOEhQaVB2azhmUk9QVzhFeTFoM1Q0RnJXSG53MWk2K055c28zSmRnVkF1b2JSQkFLV2VXUmVHNDZ2R3o2VE1qbVNQS2lxOHN5bUErZlNIWkZSVmZIWEtaSU9wTTJENDVvT1NCYklacUYyK2FwRW9xa0t6dldMbmMzSGtQc3FWOTgzZ3ZUcXMvQkt2RUZwMFJnZzlvL2d2bDRWUzh6UG5pdENGWFRreXNKNkE9PQAAAQCQ94dju0pnDZR3Uuypi0ic3aQJ+nvVqe+U8u79Dga5n1qIjcHDh7HvIBJEkF+tnVPlo/PXV/x7BZSwVY1PVErit+6rYix1yuHEgqwxmx/VdRICjCaZM6tk0Ob4dZCPv6Ebn2Mmk89KHC/PwiLPqF6QfwV/Pkpa8k2A3ORJmvYSDvXhe6tCs8dqc4ebrsFxqrZjwWh5CZSpzqqZBFXlngDv2N0hHhpGlueRszD0JJ5dfEL5ZA1DDOrgO9OJVejSHyRqe1L5QRUNdXPVfS+EAG0Dd1cNdJ/sMpYCPnVjbw6iq2/YgM3cuztsXVBY7ij4WnoP3ce7Zjs9TwHn+IqzftC6"}]} {"licenses":[{"uid":"893361dc-9749-4997-93cb-802e3d7fa4a8","type":"internal","subscription_type":"none","issue_date_in_millis":1411948800000,"feature":"shield","expiry_date_in_millis":1440892799999,"max_nodes":1,"issued_to":"issuedTo","issuer":"issuer","signature":"AAAAAQAAAA04Q4ky3rFyyWLFkytEAAABmC9ZN0hjZDBGYnVyRXpCOW5Bb3FjZDAxOWpSbTVoMVZwUzRxVk1PSmkxakxZdW5IMlhlTHNoN1N2MXMvRFk4d3JTZEx3R3RRZ0pzU3lobWJKZnQvSEFva0ppTHBkWkprZWZSQi9iNmRQNkw1SlpLN0lDalZCS095MXRGN1lIZlpYcVVTTnFrcTE2dzhJZmZrdFQrN3JQeGwxb0U0MXZ0dDJHSERiZTVLOHNzSDByWnpoZEphZHBEZjUrTVBxRENNSXNsWWJjZllaODdzVmEzUjNiWktNWGM5TUhQV2plaUo4Q1JOUml4MXNuL0pSOEhQaVB2azhmUk9QVzhFeTFoM1Q0RnJXSG53MWk2K055c28zSmRnVkF1b2JSQkFLV2VXUmVHNDZ2R3o2VE1qbVNQS2lxOHN5bUErZlNIWkZSVmZIWEtaSU9wTTJENDVvT1NCYklacUYyK2FwRW9xa0t6dldMbmMzSGtQc3FWOTgzZ3ZUcXMvQkt2RUZwMFJnZzlvL2d2bDRWUzh6UG5pdENGWFRreXNKNkE9PQAAAQBxMvUMn4h2E4R4TQMijahTxQj4LPQO4f1M79UxX/XkDlGcH+J5pRHx08OtTRPsFL1lED+h+PIXx307Vo+PNDsOxrWvoYZeYBkOLAO3ny9vhQga+52jYhMxIuFrT9xbcSCSNpMhGojgOIPU2WgiopVdVcimo1+Gk8VtklPB1wPwFzfOjOnPgp/Icx3WYpfkeAUUOyWUYiFIBAe4bnz84iF+xwLKbgYk6aHF25ECBtdb/Uruhcm9+jEFpoIEUtCouvvk9C+NJZ4OickV4xpRgaRG2x9PONH8ZN0QGhGYhJGbisoCxuDmlLsyVxqxfMu3n/r7/jdsEJScjAlSrsLDOu6H"},{"uid":"893361dc-9749-4997-93cb-802e3dofh7aa","type":"internal","subscription_type":"none","issue_date_in_millis":1443484800000,"feature":"watcher","expiry_date_in_millis":1914278399999,"max_nodes":1,"issued_to":"issuedTo","issuer":"issuer","signature":"AAAAAQAAAA0Sc90guRIaQEmgLvMnAAABmC9ZN0hjZDBGYnVyRXpCOW5Bb3FjZDAxOWpSbTVoMVZwUzRxVk1PSmkxakxZdW5IMlhlTHNoN1N2MXMvRFk4d3JTZEx3R3RRZ0pzU3lobWJKZnQvSEFva0ppTHBkWkprZWZSQi9iNmRQNkw1SlpLN0lDalZCS095MXRGN1lIZlpYcVVTTnFrcTE2dzhJZmZrdFQrN3JQeGwxb0U0MXZ0dDJHSERiZTVLOHNzSDByWnpoZEphZHBEZjUrTVBxRENNSXNsWWJjZllaODdzVmEzUjNiWktNWGM5TUhQV2plaUo4Q1JOUml4MXNuL0pSOEhQaVB2azhmUk9QVzhFeTFoM1Q0RnJXSG53MWk2K055c28zSmRnVkF1b2JSQkFLV2VXUmVHNDZ2R3o2VE1qbVNQS2lxOHN5bUErZlNIWkZSVmZIWEtaSU9wTTJENDVvT1NCYklacUYyK2FwRW9xa0t6dldMbmMzSGtQc3FWOTgzZ3ZUcXMvQkt2RUZwMFJnZzlvL2d2bDRWUzh6UG5pdENGWFRreXNKNkE9PQAAAQCQ94dju0pnDZR3Uuypi0ic3aQJ+nvVqe+U8u79Dga5n1qIjcHDh7HvIBJEkF+tnVPlo/PXV/x7BZSwVY1PVErit+6rYix1yuHEgqwxmx/VdRICjCaZM6tk0Ob4dZCPv6Ebn2Mmk89KHC/PwiLPqF6QfwV/Pkpa8k2A3ORJmvYSDvXhe6tCs8dqc4ebrsFxqrZjwWh5CZSpzqqZBFXlngDv2N0hHhpGlueRszD0JJ5dfEL5ZA1DDOrgO9OJVejSHyRqe1L5QRUNdXPVfS+EAG0Dd1cNdJ/sMpYCPnVjbw6iq2/YgM3cuztsXVBY7ij4WnoP3ce7Zjs9TwHn+IqzftC6"}]}
- match: { license_status: "valid" } - match: { license_status: "valid" }
- do: - do:
xpack.license.get: {} xpack.license.get: {}
- length: { license: 11 }
- match: { license.uid: "893361dc-9749-4997-93cb-802e3dofh7aa" }
- length: { license: 11 }
- match: { license.uid: "893361dc-9749-4997-93cb-802e3dofh7aa" }
--- ---
"Should throw 404 after license deletion": "Should throw 404 after license deletion":
- do: - do:
@ -81,18 +80,18 @@ teardown:
"Should install a feature type license": "Should install a feature type license":
# VERSION_NO_FEATURE_TYPE license version # VERSION_NO_FEATURE_TYPE license version
- do: - do:
xpack.license.post: xpack.license.post:
acknowledge: true acknowledge: true
body: | body: |
{"license": {"uid":"893361dc-9749-4997-93cb-802e3d7fa4a8","type":"basic","issue_date_in_millis":1411948800000,"expiry_date_in_millis":1914278399999,"max_nodes":1,"issued_to":"issuedTo","issuer":"issuer","signature":"AAAAAgAAAA1JRPDxCvXkXtEVEB1OAAABmC9ZN0hjZDBGYnVyRXpCOW5Bb3FjZDAxOWpSbTVoMVZwUzRxVk1PSmkxakxZdW5IMlhlTHNoN1N2MXMvRFk4d3JTZEx3R3RRZ0pzU3lobWJKZnQvSEFva0ppTHBkWkprZWZSQi9iNmRQNkw1SlpLN0lDalZCS095MXRGN1lIZlpYcVVTTnFrcTE2dzhJZmZrdFQrN3JQeGwxb0U0MXZ0dDJHSERiZTVLOHNzSDByWnpoZEphZHBEZjUrTVBxRENNSXNsWWJjZllaODdzVmEzUjNiWktNWGM5TUhQV2plaUo4Q1JOUml4MXNuL0pSOEhQaVB2azhmUk9QVzhFeTFoM1Q0RnJXSG53MWk2K055c28zSmRnVkF1b2JSQkFLV2VXUmVHNDZ2R3o2VE1qbVNQS2lxOHN5bUErZlNIWkZSVmZIWEtaSU9wTTJENDVvT1NCYklacUYyK2FwRW9xa0t6dldMbmMzSGtQc3FWOTgzZ3ZUcXMvQkt2RUZwMFJnZzlvL2d2bDRWUzh6UG5pdENGWFRreXNKNkE9PQAAAQAALuQ44S3IG6SzolcXVJ6Z4CIXORDrYQ+wdLCeey0XdujTslAOj+k+vNgo6wauc7Uswi01esHu4lb5IgpvKy7RRCbh5bj/z2ubu2qMJqopp9BQyD7VQjVfqmG6seUMJwJ1a5Avvm9r41YPSPcrii3bKK2e1l6jK6N8ibCvnTyY/XkYGCJrBWTSJePDbg6ErbyodrZ37x1StLbPWcNAkmweyHjDJnvYnbeZZO7A3NmubXZjW7Ttf8/YwQyE00PqMcl7fVPY3hkKpAeHf8aaJbqkKYbqZuER3EWJX7ZvLVb1dNdNg8aXRn7YrkQcYwWgptYQpfV+D7yEJ4j5muAEoler"}} {"license": {"uid":"893361dc-9749-4997-93cb-802e3d7fa4a8","type":"basic","issue_date_in_millis":1411948800000,"expiry_date_in_millis":1914278399999,"max_nodes":1,"issued_to":"issuedTo","issuer":"issuer","signature":"AAAAAgAAAA1JRPDxCvXkXtEVEB1OAAABmC9ZN0hjZDBGYnVyRXpCOW5Bb3FjZDAxOWpSbTVoMVZwUzRxVk1PSmkxakxZdW5IMlhlTHNoN1N2MXMvRFk4d3JTZEx3R3RRZ0pzU3lobWJKZnQvSEFva0ppTHBkWkprZWZSQi9iNmRQNkw1SlpLN0lDalZCS095MXRGN1lIZlpYcVVTTnFrcTE2dzhJZmZrdFQrN3JQeGwxb0U0MXZ0dDJHSERiZTVLOHNzSDByWnpoZEphZHBEZjUrTVBxRENNSXNsWWJjZllaODdzVmEzUjNiWktNWGM5TUhQV2plaUo4Q1JOUml4MXNuL0pSOEhQaVB2azhmUk9QVzhFeTFoM1Q0RnJXSG53MWk2K055c28zSmRnVkF1b2JSQkFLV2VXUmVHNDZ2R3o2VE1qbVNQS2lxOHN5bUErZlNIWkZSVmZIWEtaSU9wTTJENDVvT1NCYklacUYyK2FwRW9xa0t6dldMbmMzSGtQc3FWOTgzZ3ZUcXMvQkt2RUZwMFJnZzlvL2d2bDRWUzh6UG5pdENGWFRreXNKNkE9PQAAAQAALuQ44S3IG6SzolcXVJ6Z4CIXORDrYQ+wdLCeey0XdujTslAOj+k+vNgo6wauc7Uswi01esHu4lb5IgpvKy7RRCbh5bj/z2ubu2qMJqopp9BQyD7VQjVfqmG6seUMJwJ1a5Avvm9r41YPSPcrii3bKK2e1l6jK6N8ibCvnTyY/XkYGCJrBWTSJePDbg6ErbyodrZ37x1StLbPWcNAkmweyHjDJnvYnbeZZO7A3NmubXZjW7Ttf8/YwQyE00PqMcl7fVPY3hkKpAeHf8aaJbqkKYbqZuER3EWJX7ZvLVb1dNdNg8aXRn7YrkQcYwWgptYQpfV+D7yEJ4j5muAEoler"}}
- match: { license_status: "valid" } - match: { license_status: "valid" }
- do: - do:
xpack.license.get: {} xpack.license.get: {}
- length: { license: 11 } - length: { license: 11 }
--- ---
"Should fail gracefully when body content is not provided": "Should fail gracefully when body content is not provided":
@ -102,3 +101,62 @@ teardown:
acknowledge: true acknowledge: true
- match: { error.root_cause.0.reason: 'The license must be provided in the request body' } - match: { error.root_cause.0.reason: 'The license must be provided in the request body' }
---
"Current license is trial means not eligle to start trial":
- do:
xpack.license.get_trial_status: {}
- match: { eligible_to_start_trial: false }
- do:
xpack.license.post_start_basic:
acknowledge: true
- match: { basic_was_started: true }
- do:
xpack.license.get_trial_status: {}
- match: { eligible_to_start_trial: false }
- do:
catch: forbidden
xpack.license.post_start_trial: {}
- match: { trial_was_started: false }
- match: { error_message: "Operation failed: Trial was already activated." }
---
"Can start basic license if do not already have basic":
- do:
xpack.license.get_basic_status: {}
- match: { eligible_to_start_basic: true }
- do:
xpack.license.post_start_basic:
acknowledge: true
- match: { basic_was_started: true }
- match: { acknowledged: true }
- do:
xpack.license.get_basic_status: {}
- match: { eligible_to_start_basic: false }
- do:
catch: forbidden
xpack.license.post_start_basic: {}
- match: { basic_was_started: false }
- match: { acknowledged: true }
- match: { error_message: "Operation failed: Current license is basic." }
---
"Must acknowledge to start basic":
- do:
xpack.license.post_start_basic: {}
- match: { basic_was_started: false }
- match: { acknowledged: false }
- match: { error_message: "Operation failed: Needs acknowledgement." }