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:
parent
de10e61765
commit
7f7ac08447
|
@ -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/]
|
|
@ -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
|
|
@ -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[]
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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";
|
||||||
|
}
|
||||||
|
}
|
|
@ -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";
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 {
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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\\\""));
|
||||||
|
}
|
||||||
|
}
|
|
@ -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) {
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,7 +13,7 @@ teardown:
|
||||||
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" }
|
||||||
|
|
||||||
|
@ -65,7 +65,6 @@ teardown:
|
||||||
|
|
||||||
- length: { license: 11 }
|
- length: { license: 11 }
|
||||||
- match: { license.uid: "893361dc-9749-4997-93cb-802e3dofh7aa" }
|
- match: { license.uid: "893361dc-9749-4997-93cb-802e3dofh7aa" }
|
||||||
|
|
||||||
---
|
---
|
||||||
"Should throw 404 after license deletion":
|
"Should throw 404 after license deletion":
|
||||||
- do:
|
- do:
|
||||||
|
@ -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." }
|
||||||
|
|
Loading…
Reference in New Issue