Merge branch 'master' into feature/sql

Original commit: elastic/x-pack-elasticsearch@b3f6d3fd70
This commit is contained in:
Nik Everett 2017-09-25 09:55:17 -04:00
commit 216058035b
63 changed files with 1184 additions and 199 deletions

View File

@ -4,9 +4,24 @@
The Authenticate API enables you to submit a request with a basic auth header to The Authenticate API enables you to submit a request with a basic auth header to
authenticate a user and retrieve information about the authenticated user. authenticate a user and retrieve information about the authenticated user.
Returns a 401 status code if the user cannot be authenticated.
To authenticate a user, submit a GET request to the `_xpack/security/_authenticate` endpoint:
==== Request
`GET _xpack/security/_authenticate`
==== Description
A successful call returns a JSON structure that shows what roles are assigned
to the user as well as any assigned metadata.
If the user cannot be authenticated, this API returns a 401 status code.
==== Examples
To authenticate a user, submit a GET request to the
`_xpack/security/_authenticate` endpoint:
[source,js] [source,js]
-------------------------------------------------- --------------------------------------------------
@ -14,8 +29,7 @@ GET _xpack/security/_authenticate
-------------------------------------------------- --------------------------------------------------
// CONSOLE // CONSOLE
A successful call returns a JSON structure that shows what roles are assigned The following example output provides information about the "rdeniro" user:
to the user as well as any assigned metadata.
[source,js] [source,js]
-------------------------------------------------- --------------------------------------------------

View File

@ -3,11 +3,37 @@
=== Change Password API === Change Password API
The Change Password API enables you to submit a request to change the password The Change Password API enables you to submit a request to change the password
of a user. Every user can change their own password and users with the of a user.
`manage_security` privilege can change passwords of other users.
To change the password of the logged in user, submit a POST request to the ==== Request
`_xpack/security/user/_password` endpoint:
`POST _xpack/security/user/_password` +
`POST _xpack/security/user/<username>/_password`
==== Path Parameters
`username`::
(string) The user whose password you want to change. If you do not specify
this parameter, the password is changed for the current user.
==== Request Body
`password` (required)::
(string) The new password value.
==== Authorization
Every user can change their own password. Users with the `manage_security`
privilege can change passwords of other users.
==== Examples
The following example updates the password for the `elastic` user:
[source,js] [source,js]
-------------------------------------------------- --------------------------------------------------

View File

@ -5,6 +5,31 @@
The Clear Cache API evicts users from the user cache. You can completely clear The Clear Cache API evicts users from the user cache. You can completely clear
the cache or evict specific users. the cache or evict specific users.
==== Request
`POST _xpack/security/realm/<realms>/_clear_cache` +
`POST _xpack/security/realm/<realms>/_clear_cache?usernames=<usernames>`
==== Description
User credentials are cached in memory on each node to avoid connecting to a
remote authentication service or hitting the disk for every incoming request.
There are realm settings that you can use to configure the user cache. For more
information, see {xpack-ref}/controlling-user-cache.html[Controlling the User Cache].
==== Path Parameters
`realms` (required)::
(list) A comma-separated list of the realms to clear.
`usernames`::
(list) A comma-separated list of the users to clear from the cache. If you
do not specify this parameter, the API evicts all users from the user cache.
==== Examples
For example, to evict all users cached by the `file` realm: For example, to evict all users cached by the `file` realm:
[source,js] [source,js]
@ -29,6 +54,3 @@ list:
POST _xpack/security/realm/default_file,ldap1/_clear_cache POST _xpack/security/realm/default_file,ldap1/_clear_cache
------------------------------------------------------------ ------------------------------------------------------------
// CONSOLE // CONSOLE
For more information, see
{xpack-ref}/controlling-user-cache.html[Controlling the User Cache].

View File

@ -7,13 +7,41 @@
The `has_privileges` API allows you to determine whether the logged in user has The `has_privileges` API allows you to determine whether the logged in user has
a specified list of privileges. a specified list of privileges.
==== Request
`GET _xpack/security/user/_has_privileges`
==== Description
For a list of the privileges that you can specify in this API,
see {xpack-ref}/security-privileges.html[Security Privileges].
A successful call returns a JSON structure that shows whether each specified
privilege is assigned to the user.
==== Request Body
`cluster`:: (list) A list of the cluster privileges that you want to check.
`index`::
`names`::: (list) A list of indices.
`privileges`::: (list) A list of the privileges that you want to check for the
specified indices.
==== Authorization
All users can use this API, but only to determine their own privileges. All users can use this API, but only to determine their own privileges.
To check the privileges of other users, you must use the run as feature. For To check the privileges of other users, you must use the run as feature. For
more information, see more information, see
{xpack-ref}/run-as-privilege.html[Submitting Requests on Behalf of Other Users]. {xpack-ref}/run-as-privilege.html[Submitting Requests on Behalf of Other Users].
To check you privileges, submit a GET request to the
`_xpack/security/user/_has_privileges` endpoint: ==== Examples
The following example checks whether the current user has a specific set of
cluster and indices privileges:
[source,js] [source,js]
-------------------------------------------------- --------------------------------------------------
@ -34,8 +62,7 @@ GET _xpack/security/user/_has_privileges
-------------------------------------------------- --------------------------------------------------
// CONSOLE // CONSOLE
A successful call returns a JSON structure that shows whether each specified The following example output indicates which privileges the "rdeniro" user has:
privilege is assigned to the user
[source,js] [source,js]
-------------------------------------------------- --------------------------------------------------

View File

@ -2,15 +2,69 @@
[[security-api-role-mapping]] [[security-api-role-mapping]]
=== Role Mapping APIs === Role Mapping APIs
The Role Mapping API enables you to add, remove, and retrieve role-mappings. The Role Mapping API enables you to add, remove, and retrieve role mappings.
To use this API, you must have at least the `manage_security` cluster privilege.
NOTE: The API requires that each role-mapping have a distinct name. The name is ==== Request
`GET /_xpack/security/role_mapping` +
`GET /_xpack/security/role_mapping/<name>` +
`DELETE /_xpack/security/role_mapping/<name>` +
`POST /_xpack/security/role_mapping/<name>` +
`PUT /_xpack/security/role_mapping/<name>`
==== Description
NOTE: The API requires that each role mapping have a distinct name. The name is
used solely as an identifier to facilitate interaction via the API, and does used solely as an identifier to facilitate interaction via the API, and does
not affect the behavior of the mapping in any way. not affect the behavior of the mapping in any way.
For more information, see
{xpack-ref}/mapping-roles.html[Mapping Users and Groups to Roles].
==== Path Parameters
`name`::
(string) The distinct name that identifies the role mapping. If you do not
specify this parameter, the Get Role Mappings API returns information about all
role mappings.
==== Request Body
The following parameters can be specified in the body of a PUT or POST request
and pertain to adding a role mapping:
`enabled` (required)::
(boolean) Mappings that have `enabled` set to `false` are ignored when role
mapping is performed.
`metadata`::
(object) Additional metadata that helps define which roles are assigned to each
user. Within the `metadata` object, keys beginning with `_` are reserved for
system usage.
`roles` (required)::
(list) A list of roles that are granted to the users that match the role-mapping
rules.
`rules` (required)::
(object) The rules that determine which users should be matched by the mapping.
A rule is a logical condition that is expressed by using a JSON DSL.
==== Authorization
To use this API, you must have at least the `manage_security` cluster privilege.
==== Examples
[[security-api-put-role-mapping]] [[security-api-put-role-mapping]]
To add a role-mapping, submit a PUT or POST request to the `/_xpack/security/role_mapping/<name>` To add a role mapping, submit a PUT or POST request to the `/_xpack/security/role_mapping/<name>`
endpoint: endpoint:
[source,js] [source,js]
@ -28,14 +82,10 @@ POST /_xpack/security/role_mapping/administrators
} }
-------------------------------------------------- --------------------------------------------------
// CONSOLE // CONSOLE
<1> Mappings that have `enabled` set to `false` will be ignored when role-mapping <1> Mappings that have `enabled` set to `false` will be ignored when role mapping
is performed. is performed.
<2> Metadata is optional <2> Metadata is optional
The `roles`, `enabled`, and `rules` fields are required at the top-level.
Within the `metadata` object, keys beginning with `_` are reserved for system
usage.
A successful call returns a JSON structure that shows whether the mapping has A successful call returns a JSON structure that shows whether the mapping has
been created or updated. been created or updated.
@ -51,7 +101,7 @@ been created or updated.
<1> When an existing mapping is updated, `created` is set to false. <1> When an existing mapping is updated, `created` is set to false.
[[security-api-get-role-mapping]] [[security-api-get-role-mapping]]
To retrieve a role-mapping, issue a GET request to the To retrieve a role mapping, issue a GET request to the
`/_xpack/security/role_mapping/<name>` endpoint: `/_xpack/security/role_mapping/<name>` endpoint:
[source,js] [source,js]
@ -61,7 +111,7 @@ GET /_xpack/security/role_mapping/administrators
// CONSOLE // CONSOLE
// TEST[continued] // TEST[continued]
A successful call an object, where the keys are the A successful call retrieves an object, where the keys are the
names of the request mappings, and the values are names of the request mappings, and the values are
the JSON representation of those mappings. the JSON representation of those mappings.
If there is no mapping with the requested name, the If there is no mapping with the requested name, the
@ -107,7 +157,7 @@ GET /_xpack/security/role_mapping
// TEST[continued] // TEST[continued]
[[security-api-delete-role-mapping]] [[security-api-delete-role-mapping]]
To delete a role-mapping, submit a DELETE request to the To delete a role mapping, submit a DELETE request to the
`/_xpack/security/role_mapping/<name>` endpoint: `/_xpack/security/role_mapping/<name>` endpoint:
[source,js] [source,js]

View File

@ -3,10 +3,72 @@
=== Role Management APIs === Role Management APIs
The Roles API enables you to add, remove, and retrieve roles in the `native` The Roles API enables you to add, remove, and retrieve roles in the `native`
realm. To use this API, you must have at least the `manage_security` cluster realm.
==== Request
`GET /_xpack/security/role` +
`GET /_xpack/security/role/<name>` +
`POST /_xpack/security/role/<name>/_clear_cache` +
`POST /_xpack/security/role/<name>` +
`PUT /_xpack/security/role/<name>`
==== Description
The Roles API is generally the preferred way to manage roles, rather than using
file-based role management. For more information, see
{xpack-ref}/authorization.html[Configuring Role-based Access Control].
==== Path Parameters
`name`::
(string) The name of the role. If you do not specify this parameter, the
Get Roles API returns information about all roles.
==== Request Body
The following parameters can be specified in the body of a PUT or POST request
and pertain to adding a role:
`cluster`:: (list) A list of cluster privileges. These privileges define the
cluster level actions that users with this role are able to execute.
`indices`:: (list) A list of indices permissions entries.
`field_security`::: (list) The document fields that the owners of the role have
read access to. For more information, see
{xpack-ref}/field-and-document-access-control.html[Setting Up Field and Document Level Security].
`names` (required)::: (list) A list of indices (or index name patterns) to which the
permissions in this entry apply.
`privileges`(required)::: (list) The index level privileges that the owners of the role
have on the specified indices.
`query`::: A search query that defines the documents the owners of the role have
read access to. A document within the specified indices must match this query in
order for it to be accessible by the owners of the role.
`metadata`:: (object) Optional meta-data. Within the `metadata` object, keys
that begin with `_` are reserved for system usage.
`run_as`:: (list) A list of users that the owners of this role can impersonate.
For more information, see
{xpack-ref}/run-as-privilege.html[Submitting Requests on Behalf of Other Users].
For more information, see {xpack-ref}/defining-roles.html[Defining Roles].
==== Authorization
To use this API, you must have at least the `manage_security` cluster
privilege. privilege.
NOTE: The Roles API is now the preferred way to manage roles.
==== Examples
[[security-api-put-role]] [[security-api-put-role]]
To add a role, submit a PUT or POST request to the `/_xpack/security/role/<rolename>` To add a role, submit a PUT or POST request to the `/_xpack/security/role/<rolename>`
@ -35,15 +97,6 @@ POST /_xpack/security/role/my_admin_role
-------------------------------------------------- --------------------------------------------------
// CONSOLE // CONSOLE
The `name`, `cluster`, and `indices` fields are required at the top-level.
Within the `indices` array, the `names` and `privileges` fields are required.
Within the `metadata` object, keys beginning with `_` are reserved for system
usage.
The `field_security` and `query` fields are both optional. They are used to
implement field and document level security. For more information, see
{xpack-ref}/field-and-document-access-control.html[Setting Up Field and Document Level Security].
A successful call returns a JSON structure that shows whether the role has been A successful call returns a JSON structure that shows whether the role has been
created or updated. created or updated.

View File

@ -3,10 +3,54 @@
=== Token Management APIs === Token Management APIs
The `token` API enables you to create and invalidate bearer tokens for access The `token` API enables you to create and invalidate bearer tokens for access
without requiring basic authentication. The get token API takes the same without requiring basic authentication.
parameters as a typical OAuth 2.0 token API except for the use of a JSON
request body.
==== Request
`POST /_xpack/security/oauth2/token` +
`DELETE /_xpack/security/oauth2/token`
==== Description
The Get Token API takes the same parameters as a typical OAuth 2.0 token API
except for the use of a JSON request body.
A successful Get Token API call returns a JSON structure that contains the access
token, the amount of time (seconds) that the token expires in, the type, and the
scope if available.
The tokens returned by the Get Token API have a finite period of time for which
they are valid and after that time period, they can no longer be used. However,
if you want to invalidate a token immediately, you can do so by using the Delete
Token API.
==== Request Body
The following parameters can be specified in the body of a POST request and
pertain to creating a token:
`grant_type`::
(string) The type of grant. Currently only the `password` grant type is supported.
`password` (required)::
(string) The user's password.
`scope`::
(string) The scope of the token. Currently tokens are only issued for a scope of
`FULL` regardless of the value sent with the request.
`username` (required)::
(string) The username that identifies the user.
The following parameters can be specified in the body of a DELETE request and
pertain to deleting a token:
`token`::
(string) An access token.
==== Examples
[[security-api-get-token]] [[security-api-get-token]]
To obtain a token, submit a POST request to the `/_xpack/security/oauth2/token` To obtain a token, submit a POST request to the `/_xpack/security/oauth2/token`
endpoint. endpoint.
@ -22,22 +66,8 @@ POST /_xpack/security/oauth2/token
-------------------------------------------------- --------------------------------------------------
// CONSOLE // CONSOLE
.Token Request Fields The following example output contains the access token, the amount of time (in
[cols="4,^2,10"] seconds) that the token expires in, and the type:
|=======================
| Name | Required | Description
| `username` | yes | The username that identifies the user.
| `password` | yes | The user's password.
| `grant_type`| yes | The type of grant. Currently only the `password`
grant type is supported.
| `scope` | no | The scope of the token. Currently tokens are only
issued for a scope of `FULL` regardless of the value
sent with the request.
|=======================
A successful call returns a JSON structure that contains the access token, the
amount of time (seconds) that the token expires in, the type, and the scope if
available.
[source,js] [source,js]
-------------------------------------------------- --------------------------------------------------
@ -49,9 +79,6 @@ available.
-------------------------------------------------- --------------------------------------------------
// TESTRESPONSE[s/dGhpcyBpcyBub3QgYSByZWFsIHRva2VuIGJ1dCBpdCBpcyBvbmx5IHRlc3QgZGF0YS4gZG8gbm90IHRyeSB0byByZWFkIHRva2VuIQ==/$body.access_token/] // TESTRESPONSE[s/dGhpcyBpcyBub3QgYSByZWFsIHRva2VuIGJ1dCBpdCBpcyBvbmx5IHRlc3QgZGF0YS4gZG8gbm90IHRyeSB0byByZWFkIHRva2VuIQ==/$body.access_token/]
A successful call returns a JSON structure that shows whether the user has been
created or updated.
The token returned by this API can be used by sending a request with a The token returned by this API can be used by sending a request with a
`Authorization` header with a value having the prefix `Bearer ` followed `Authorization` header with a value having the prefix `Bearer ` followed
by the value of the `access_token`. by the value of the `access_token`.
@ -62,10 +89,8 @@ curl -H "Authorization: Bearer dGhpcyBpcyBub3QgYSByZWFsIHRva2VuIGJ1dCBpdCBpcyBvb
-------------------------------------------------- --------------------------------------------------
[[security-api-invalidate-token]] [[security-api-invalidate-token]]
The tokens returned from this API have a finite period of time for which they If a token must be invalidated immediately, you can do so by submitting a DELETE
are valid and after that time period, they can no longer be used. However, if request to `/_xpack/security/oauth2/token`. For example:
a token must be invalidated immediately, you can do so by submitting a DELETE
request to `/_xpack/security/oauth2/token`.
[source,js] [source,js]
-------------------------------------------------- --------------------------------------------------

View File

@ -4,18 +4,78 @@
The `user` API enables you to create, read, update, and delete users from the The `user` API enables you to create, read, update, and delete users from the
`native` realm. These users are commonly referred to as *native users*. `native` realm. These users are commonly referred to as *native users*.
==== Request
`GET /_xpack/security/user` +
`GET /_xpack/security/user/<username>` +
`DELETE /_xpack/security/user/<username>` +
`POST /_xpack/security/user/<username>` +
`PUT /_xpack/security/user/<username>` +
`PUT /_xpack/security/user/<username>/_disable` +
`PUT /_xpack/security/user/<username>/_enable` +
`PUT /_xpack/security/user/<username>/_password`
==== Description
You can use the PUT user API to create or update users. When updating a user,
you can update everything but its `username` and `password`. To change a user's
password, use the <<security-api-reset-user-password, reset password API>>.
[[username-validation]]
NOTE: Usernames must be at least 1 and no more than 1024 characters. They can
contain alphanumeric characters (`a-z`, `A-Z`, `0-9`), spaces, punctuation, and
printable symbols in the https://en.wikipedia.org/wiki/Basic_Latin_(Unicode_block)[Basic Latin (ASCII) block].
Leading or trailing whitespace is not allowed.
==== Path Parameters
`username`::
(string) An identifier for the user. If you omit this parameter from a Get
User API request, it retrieves information about all users.
==== Request Body
The following parameters can be specified in the body of a POST or PUT request
and pertain to creating a user:
`email`::
(string) The email of the user.
`full_name`::
(string) The full name of the user.
`metadata`::
(object) Arbitrary metadata that you want to associate with the user.
`password` (required)::
(string) The user's password. Passwords must be at least 6 characters long.
`roles` (required)::
(list) A set of roles the user has. The roles determine the user's access
permissions.
==== Authorization
To use this API, you must have at least the `manage_security` cluster privilege. To use this API, you must have at least the `manage_security` cluster privilege.
==== Examples
[[security-api-put-user]] [[security-api-put-user]]
To add a user, submit a PUT or POST request to the `/_xpack/security/user/<username>` To add a user, submit a PUT or POST request to the `/_xpack/security/user/<username>`
endpoint. endpoint.
[[username-validation]]
NOTE: Usernames must be at least 1 and no more than 1024 characters. They can
contain alphanumeric characters (`a-z`, `A-Z`, `0-9`), spaces,
punctuation, and printable symbols in the https://en.wikipedia.org/wiki/Basic_Latin_(Unicode_block)[Basic Latin (ASCII) block].
Leading or trailing whitespace is not allowed.
[source,js] [source,js]
-------------------------------------------------- --------------------------------------------------
POST /_xpack/security/user/jacknich POST /_xpack/security/user/jacknich
@ -31,20 +91,6 @@ POST /_xpack/security/user/jacknich
-------------------------------------------------- --------------------------------------------------
// CONSOLE // CONSOLE
.User Fields
[cols="4,^2,10"]
|=======================
| Name | Required | Description
| `password` | yes | The user's password. Passwords must be at least 6
characters long.
| `roles` | yes | A set of roles the user has. The roles determine
the user's access permissions
| `full_name` | no | The full name of the user
| `email` | no | The email of the user
| `metadata` | no | Arbitrary metadata that you want to associate with
the user.
|=======================
A successful call returns a JSON structure that shows whether the user has been A successful call returns a JSON structure that shows whether the user has been
created or updated. created or updated.
@ -59,11 +105,7 @@ created or updated.
// TESTRESPONSE // TESTRESPONSE
<1> When an existing user is updated, `created` is set to false. <1> When an existing user is updated, `created` is set to false.
NOTE: You also use the PUT user API to update users. When updating a user, you After you add a user through the Users API, requests from that user can be
can update everything but its `username` and `password`. To change a user's
password, use the <<security-api-reset-user-password, reset password API>>.
Once you add a user through the Users API, requests from that user can be
authenticated. authenticated.
[source,shell] [source,shell]

View File

@ -85,6 +85,9 @@ change between releases.
Grants the minimum privileges required for any user of {kib}. This role grants Grants the minimum privileges required for any user of {kib}. This role grants
access to the {kib} indices and grants monitoring privileges for the cluster. access to the {kib} indices and grants monitoring privileges for the cluster.
[[built-in-roles-logstash-admin]] `logstash_admin` ::
Grants access to the `.logstash*` indices for managing configurations.
[[built-in-roles-logstash-system]] `logstash_system` :: [[built-in-roles-logstash-system]] `logstash_system` ::
Grants access necessary for the Logstash system user to send system-level data Grants access necessary for the Logstash system user to send system-level data
(such as monitoring) to {es}. For more information, see (such as monitoring) to {es}. For more information, see

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 GetTrialStatusAction extends Action<GetTrialStatusRequest, GetTrialStatusResponse, GetTrialStatusRequestBuilder> {
public static final GetTrialStatusAction INSTANCE = new GetTrialStatusAction();
public static final String NAME = "cluster:admin/xpack/license/trial_status";
private GetTrialStatusAction() {
super(NAME);
}
@Override
public GetTrialStatusRequestBuilder newRequestBuilder(ElasticsearchClient client) {
return new GetTrialStatusRequestBuilder(client, this);
}
@Override
public GetTrialStatusResponse newResponse() {
return new GetTrialStatusResponse();
}
}

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 GetTrialStatusRequest extends MasterNodeReadRequest<GetTrialStatusRequest> {
public GetTrialStatusRequest() {
}
public GetTrialStatusRequest(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 GetTrialStatusRequestBuilder extends ActionRequestBuilder<GetTrialStatusRequest,
GetTrialStatusResponse, GetTrialStatusRequestBuilder> {
GetTrialStatusRequestBuilder(ElasticsearchClient client, GetTrialStatusAction action) {
super(client, action, new GetTrialStatusRequest());
}
}

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 GetTrialStatusResponse extends ActionResponse {
private boolean eligibleToStartTrial;
GetTrialStatusResponse() {
}
GetTrialStatusResponse(boolean eligibleToStartTrial) {
this.eligibleToStartTrial = eligibleToStartTrial;
}
boolean isEligibleToStartTrial() {
return eligibleToStartTrial;
}
@Override
public void readFrom(StreamInput in) throws IOException {
eligibleToStartTrial = in.readBoolean();
}
@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeBoolean(eligibleToStartTrial);
}
}

View File

@ -8,6 +8,7 @@ package org.elasticsearch.license;
import org.apache.logging.log4j.message.ParameterizedMessage; import org.apache.logging.log4j.message.ParameterizedMessage;
import org.apache.logging.log4j.util.Supplier; import org.apache.logging.log4j.util.Supplier;
import org.elasticsearch.ElasticsearchException; import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.Version;
import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.ActionListener;
import org.elasticsearch.cluster.AckedClusterStateUpdateTask; import org.elasticsearch.cluster.AckedClusterStateUpdateTask;
import org.elasticsearch.cluster.ClusterChangedEvent; import org.elasticsearch.cluster.ClusterChangedEvent;
@ -227,8 +228,14 @@ public class LicenseService extends AbstractLifecycleComponent implements Cluste
@Override @Override
public ClusterState execute(ClusterState currentState) throws Exception { public ClusterState execute(ClusterState currentState) throws Exception {
MetaData.Builder mdBuilder = MetaData.builder(currentState.metaData()); MetaData currentMetadata = currentState.metaData();
mdBuilder.putCustom(LicensesMetaData.TYPE, new LicensesMetaData(newLicense)); LicensesMetaData licensesMetaData = currentMetadata.custom(LicensesMetaData.TYPE);
Version trialVersion = null;
if (licensesMetaData != null) {
trialVersion = licensesMetaData.getMostRecentTrialVersion();
}
MetaData.Builder mdBuilder = MetaData.builder(currentMetadata);
mdBuilder.putCustom(LicensesMetaData.TYPE, new LicensesMetaData(newLicense, trialVersion));
return ClusterState.builder(currentState).metaData(mdBuilder).build(); return ClusterState.builder(currentState).metaData(mdBuilder).build();
} }
}); });
@ -237,7 +244,7 @@ public class LicenseService extends AbstractLifecycleComponent implements Cluste
} }
static TimeValue days(int days) { private static TimeValue days(int days) {
return TimeValue.timeValueHours(days * 24); return TimeValue.timeValueHours(days * 24);
} }
@ -273,7 +280,9 @@ public class LicenseService extends AbstractLifecycleComponent implements Cluste
final LicensesMetaData currentLicenses = metaData.custom(LicensesMetaData.TYPE); final LicensesMetaData currentLicenses = metaData.custom(LicensesMetaData.TYPE);
if (currentLicenses.getLicense() != LicensesMetaData.LICENSE_TOMBSTONE) { if (currentLicenses.getLicense() != LicensesMetaData.LICENSE_TOMBSTONE) {
MetaData.Builder mdBuilder = MetaData.builder(currentState.metaData()); MetaData.Builder mdBuilder = MetaData.builder(currentState.metaData());
mdBuilder.putCustom(LicensesMetaData.TYPE, new LicensesMetaData(LicensesMetaData.LICENSE_TOMBSTONE)); LicensesMetaData newMetadata = new LicensesMetaData(LicensesMetaData.LICENSE_TOMBSTONE,
currentLicenses.getMostRecentTrialVersion());
mdBuilder.putCustom(LicensesMetaData.TYPE, newMetadata);
return ClusterState.builder(currentState).metaData(mdBuilder).build(); return ClusterState.builder(currentState).metaData(mdBuilder).build();
} else { } else {
return currentState; return currentState;
@ -287,6 +296,40 @@ public class LicenseService extends AbstractLifecycleComponent implements Cluste
return license == LicensesMetaData.LICENSE_TOMBSTONE ? null : license; return license == LicensesMetaData.LICENSE_TOMBSTONE ? null : license;
} }
void upgradeSelfGeneratedLicense(final ActionListener<PostStartTrialResponse> listener) {
clusterService.submitStateUpdateTask("upgrade self generated license",
new ClusterStateUpdateTask() {
@Override
public void clusterStateProcessed(String source, ClusterState oldState, ClusterState newState) {
LicensesMetaData licensesMetaData = oldState.metaData().custom(LicensesMetaData.TYPE);
logger.debug("upgraded self generated license: {}", licensesMetaData);
if (licensesMetaData == null || licensesMetaData.isEligibleForTrial()) {
listener.onResponse(new PostStartTrialResponse(PostStartTrialResponse.STATUS.UPGRADED_TO_TRIAL));
} else {
listener.onResponse(new PostStartTrialResponse(PostStartTrialResponse.STATUS.TRIAL_ALREADY_ACTIVATED));
}
}
@Override
public ClusterState execute(ClusterState currentState) throws Exception {
LicensesMetaData licensesMetaData = currentState.metaData().custom(LicensesMetaData.TYPE);
if (licensesMetaData == null || licensesMetaData.isEligibleForTrial()) {
return updateWithLicense(currentState, "trial");
} else {
return currentState;
}
}
@Override
public void onFailure(String source, @Nullable Exception e) {
logger.error(new ParameterizedMessage("unexpected failure during [{}]", source), e);
listener.onFailure(e);
}
});
}
/** /**
* Master-only operation to generate a one-time global trial license. * Master-only operation to generate a one-time global trial license.
* The trial license is only generated and stored if the current cluster state metaData * The trial license is only generated and stored if the current cluster state metaData
@ -299,7 +342,7 @@ public class LicenseService extends AbstractLifecycleComponent implements Cluste
public void clusterStateProcessed(String source, ClusterState oldState, ClusterState newState) { public void clusterStateProcessed(String source, ClusterState oldState, ClusterState newState) {
LicensesMetaData licensesMetaData = newState.metaData().custom(LicensesMetaData.TYPE); LicensesMetaData licensesMetaData = newState.metaData().custom(LicensesMetaData.TYPE);
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("registered trial license: {}", licensesMetaData); logger.debug("registered self generated license: {}", licensesMetaData);
} }
} }
@ -307,28 +350,19 @@ public class LicenseService extends AbstractLifecycleComponent implements Cluste
public ClusterState execute(ClusterState currentState) throws Exception { public ClusterState execute(ClusterState currentState) throws Exception {
final MetaData metaData = currentState.metaData(); final MetaData metaData = currentState.metaData();
final LicensesMetaData currentLicensesMetaData = metaData.custom(LicensesMetaData.TYPE); final LicensesMetaData currentLicensesMetaData = metaData.custom(LicensesMetaData.TYPE);
MetaData.Builder mdBuilder = MetaData.builder(currentState.metaData());
// do not generate a trial license if any license is present // do not generate a trial license if any license is present
if (currentLicensesMetaData == null) { if (currentLicensesMetaData == null) {
long issueDate = clock.millis();
String type = SELF_GENERATED_LICENSE_TYPE.get(settings); String type = SELF_GENERATED_LICENSE_TYPE.get(settings);
if (validSelfGeneratedType(type) == false) { if (validSelfGeneratedType(type) == false) {
throw new IllegalArgumentException("Illegal self generated license type [" + type + throw new IllegalArgumentException("Illegal self generated license type [" + type +
"]. Must be trial or basic."); "]. Must be trial or basic.");
} }
License.Builder specBuilder = License.builder()
.uid(UUID.randomUUID().toString()) return updateWithLicense(currentState, type);
.issuedTo(clusterService.getClusterName().value()) } else {
.maxNodes(selfGeneratedLicenseMaxNodes)
.issueDate(issueDate)
.type(type)
.expiryDate(issueDate + SELF_GENERATED_LICENSE_DURATION.getMillis());
License selfGeneratedLicense = SelfGeneratedLicense.create(specBuilder);
mdBuilder.putCustom(LicensesMetaData.TYPE, new LicensesMetaData(selfGeneratedLicense));
return ClusterState.builder(currentState).metaData(mdBuilder).build();
}
return currentState; return currentState;
} }
}
@Override @Override
public void onFailure(String source, @Nullable Exception e) { public void onFailure(String source, @Nullable Exception e) {
@ -338,6 +372,27 @@ public class LicenseService extends AbstractLifecycleComponent implements Cluste
}); });
} }
private ClusterState updateWithLicense(ClusterState currentState, String type) {
long issueDate = clock.millis();
MetaData.Builder mdBuilder = MetaData.builder(currentState.metaData());
License.Builder specBuilder = License.builder()
.uid(UUID.randomUUID().toString())
.issuedTo(clusterService.getClusterName().value())
.maxNodes(selfGeneratedLicenseMaxNodes)
.issueDate(issueDate)
.type(type)
.expiryDate(issueDate + SELF_GENERATED_LICENSE_DURATION.getMillis());
License selfGeneratedLicense = SelfGeneratedLicense.create(specBuilder);
LicensesMetaData licensesMetaData;
if ("trial".equals(type)) {
licensesMetaData = new LicensesMetaData(selfGeneratedLicense, Version.CURRENT);
} else {
licensesMetaData = new LicensesMetaData(selfGeneratedLicense, null);
}
mdBuilder.putCustom(LicensesMetaData.TYPE, licensesMetaData);
return ClusterState.builder(currentState).metaData(mdBuilder).build();
}
@Override @Override
protected void doStart() throws ElasticsearchException { protected void doStart() throws ElasticsearchException {
clusterService.addListener(this); clusterService.addListener(this);
@ -436,7 +491,7 @@ public class LicenseService extends AbstractLifecycleComponent implements Cluste
* Additionally schedules license expiry notifications and event callbacks * Additionally schedules license expiry notifications and event callbacks
* relative to the current license's expiry * relative to the current license's expiry
*/ */
void onUpdate(final LicensesMetaData currentLicensesMetaData) { private void onUpdate(final LicensesMetaData currentLicensesMetaData) {
final License license = getLicense(currentLicensesMetaData); final License license = getLicense(currentLicensesMetaData);
// license can be null if the trial license is yet to be auto-generated // license can be null if the trial license is yet to be auto-generated
// in this case, it is a no-op // in this case, it is a no-op

View File

@ -5,15 +5,17 @@
*/ */
package org.elasticsearch.license; package org.elasticsearch.license;
import org.elasticsearch.Version;
import org.elasticsearch.cluster.AbstractNamedDiffable; import org.elasticsearch.cluster.AbstractNamedDiffable;
import org.elasticsearch.cluster.MergableCustomMetaData;
import org.elasticsearch.cluster.NamedDiff; import org.elasticsearch.cluster.NamedDiff;
import org.elasticsearch.cluster.metadata.MetaData; import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.common.inject.internal.Nullable;
import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.license.License.OperationMode; import org.elasticsearch.license.License.OperationMode;
import org.elasticsearch.cluster.MergableCustomMetaData;
import java.io.IOException; import java.io.IOException;
import java.util.EnumSet; import java.util.EnumSet;
@ -48,33 +50,56 @@ class LicensesMetaData extends AbstractNamedDiffable<MetaData.Custom> implements
private License license; private License license;
LicensesMetaData(License license) { // This field describes the version of x-pack for which this cluster has exercised a trial. If the field
// is null, then no trial has been exercised. We keep the version to leave open the possibility that we
// may eventually allow a cluster to exercise a trial every time they upgrade to a new major version.
@Nullable
private Version trialVersion;
LicensesMetaData(License license, Version trialVersion) {
this.license = license; this.license = license;
this.trialVersion = trialVersion;
} }
public License getLicense() { public License getLicense() {
return license; return license;
} }
boolean isEligibleForTrial() {
if (trialVersion == null) {
return true;
}
return Version.CURRENT.major > trialVersion.major;
}
Version getMostRecentTrialVersion() {
return trialVersion;
}
@Override @Override
public String toString() { public String toString() {
if (license != null) { return "LicensesMetaData{" +
return license.toString(); "license=" + license +
} ", trialVersion=" + trialVersion +
return ""; '}';
} }
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
LicensesMetaData that = (LicensesMetaData) o; LicensesMetaData that = (LicensesMetaData) o;
return !(license != null ? !license.equals(that.license) : that.license != null);
if (license != null ? !license.equals(that.license) : that.license != null) return false;
return trialVersion != null ? trialVersion.equals(that.trialVersion) : that.trialVersion == null;
} }
@Override @Override
public int hashCode() { public int hashCode() {
return license != null ? license.hashCode() : 0; int result = license != null ? license.hashCode() : 0;
result = 31 * result + (trialVersion != null ? trialVersion.hashCode() : 0);
return result;
} }
@Override @Override
@ -89,6 +114,7 @@ class LicensesMetaData extends AbstractNamedDiffable<MetaData.Custom> implements
public static LicensesMetaData fromXContent(XContentParser parser) throws IOException { public static LicensesMetaData fromXContent(XContentParser parser) throws IOException {
License license = LICENSE_TOMBSTONE; License license = LICENSE_TOMBSTONE;
Version trialLicense = null;
XContentParser.Token token; XContentParser.Token token;
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
if (token == XContentParser.Token.FIELD_NAME) { if (token == XContentParser.Token.FIELD_NAME) {
@ -101,11 +127,14 @@ class LicensesMetaData extends AbstractNamedDiffable<MetaData.Custom> implements
} else if (token == XContentParser.Token.VALUE_NULL) { } else if (token == XContentParser.Token.VALUE_NULL) {
license = LICENSE_TOMBSTONE; license = LICENSE_TOMBSTONE;
} }
} else if (fieldName.equals(Fields.TRIAL_LICENSE)) {
parser.nextToken();
trialLicense = Version.fromString(parser.text());
} }
} }
} }
} }
return new LicensesMetaData(license); return new LicensesMetaData(license, trialLicense);
} }
@Override @Override
@ -117,6 +146,9 @@ class LicensesMetaData extends AbstractNamedDiffable<MetaData.Custom> implements
license.toInnerXContent(builder, params); license.toInnerXContent(builder, params);
builder.endObject(); builder.endObject();
} }
if (trialVersion != null) {
builder.field(Fields.TRIAL_LICENSE, trialVersion.toString());
}
return builder; return builder;
} }
@ -128,6 +160,15 @@ class LicensesMetaData extends AbstractNamedDiffable<MetaData.Custom> implements
streamOutput.writeBoolean(true); // has a license streamOutput.writeBoolean(true); // has a license
license.writeTo(streamOutput); license.writeTo(streamOutput);
} }
// TODO Eventually this should be 6.0. But it is 7.0 temporarily for bwc
if (streamOutput.getVersion().onOrAfter(Version.V_7_0_0_alpha1)) {
if (trialVersion == null) {
streamOutput.writeBoolean(false);
} else {
streamOutput.writeBoolean(true);
Version.writeVersion(trialVersion, streamOutput);
}
}
} }
LicensesMetaData(StreamInput streamInput) throws IOException { LicensesMetaData(StreamInput streamInput) throws IOException {
@ -136,6 +177,13 @@ class LicensesMetaData extends AbstractNamedDiffable<MetaData.Custom> implements
} else { } else {
license = LICENSE_TOMBSTONE; license = LICENSE_TOMBSTONE;
} }
// TODO Eventually this should be 6.0. But it is 7.0 temporarily for bwc
if (streamInput.getVersion().onOrAfter(Version.V_7_0_0_alpha1)) {
boolean hasExercisedTrial = streamInput.readBoolean();
if (hasExercisedTrial) {
this.trialVersion = Version.readVersion(streamInput);
}
}
} }
public static NamedDiff<MetaData.Custom> readDiffFrom(StreamInput streamInput) throws IOException { public static NamedDiff<MetaData.Custom> readDiffFrom(StreamInput streamInput) throws IOException {
@ -155,5 +203,6 @@ class LicensesMetaData extends AbstractNamedDiffable<MetaData.Custom> implements
private static final class Fields { private static final class Fields {
private static final String LICENSE = "license"; private static final String LICENSE = "license";
private static final String TRIAL_LICENSE = "trial_license";
} }
} }

View File

@ -36,7 +36,7 @@ public class Licensing implements ActionPlugin {
public static final String NAME = "license"; public static final String NAME = "license";
protected final Settings settings; protected final Settings settings;
protected final boolean isTransportClient; private final boolean isTransportClient;
private final boolean isTribeNode; private final boolean isTribeNode;
public List<NamedWriteableRegistry.Entry> getNamedWriteables() { public List<NamedWriteableRegistry.Entry> getNamedWriteables() {
@ -53,6 +53,7 @@ public class Licensing implements ActionPlugin {
LicensesMetaData::fromXContent)); LicensesMetaData::fromXContent));
return entries; return entries;
} }
public Licensing(Settings settings) { public Licensing(Settings settings) {
this.settings = settings; this.settings = settings;
isTransportClient = transportClientMode(settings); isTransportClient = transportClientMode(settings);
@ -66,7 +67,9 @@ public class Licensing implements ActionPlugin {
} }
return Arrays.asList(new ActionHandler<>(PutLicenseAction.INSTANCE, TransportPutLicenseAction.class), return Arrays.asList(new ActionHandler<>(PutLicenseAction.INSTANCE, TransportPutLicenseAction.class),
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<>(GetTrialStatusAction.INSTANCE, TransportGetTrialStatusAction.class));
} }
@Override @Override
@ -78,6 +81,8 @@ public class Licensing implements ActionPlugin {
if (false == isTribeNode) { if (false == isTribeNode) {
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 RestPostStartTrialLicense(settings, restController));
} }
return handlers; return handlers;
} }

View File

@ -39,4 +39,16 @@ public class LicensingClient {
public void deleteLicense(DeleteLicenseRequest request, ActionListener<DeleteLicenseResponse> listener) { public void deleteLicense(DeleteLicenseRequest request, ActionListener<DeleteLicenseResponse> listener) {
client.execute(DeleteLicenseAction.INSTANCE, request, listener); client.execute(DeleteLicenseAction.INSTANCE, request, listener);
} }
public PostStartTrialRequestBuilder preparePutUpgradeToTrial() {
return new PostStartTrialRequestBuilder(client, PostStartTrialAction.INSTANCE);
}
public GetTrialStatusRequestBuilder prepareGetUpgradeToTrial() {
return new GetTrialStatusRequestBuilder(client, GetTrialStatusAction.INSTANCE);
}
public void putUpgradeToTrial(PostStartTrialRequest request, ActionListener<PostStartTrialResponse> listener) {
client.execute(PostStartTrialAction.INSTANCE, request, listener);
}
} }

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 PostStartTrialAction extends Action<PostStartTrialRequest, PostStartTrialResponse, PostStartTrialRequestBuilder> {
public static final PostStartTrialAction INSTANCE = new PostStartTrialAction();
public static final String NAME = "cluster:admin/xpack/license/start_trial";
private PostStartTrialAction() {
super(NAME);
}
@Override
public PostStartTrialRequestBuilder newRequestBuilder(ElasticsearchClient client) {
return new PostStartTrialRequestBuilder(client, this);
}
@Override
public PostStartTrialResponse newResponse() {
return new PostStartTrialResponse();
}
}

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.ActionRequestValidationException;
import org.elasticsearch.action.support.master.MasterNodeRequest;
public class PostStartTrialRequest extends MasterNodeRequest<PostStartTrialRequest> {
@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 PostStartTrialRequestBuilder extends ActionRequestBuilder<PostStartTrialRequest,
PostStartTrialResponse, PostStartTrialRequestBuilder> {
PostStartTrialRequestBuilder(ElasticsearchClient client, PostStartTrialAction action) {
super(client, action, new PostStartTrialRequest());
}
}

View File

@ -0,0 +1,43 @@
/*
* 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 PostStartTrialResponse extends ActionResponse {
enum STATUS {
UPGRADED_TO_TRIAL,
TRIAL_ALREADY_ACTIVATED
}
private STATUS status;
PostStartTrialResponse() {
}
PostStartTrialResponse(STATUS status) {
this.status = status;
}
public STATUS getStatus() {
return status;
}
@Override
public void readFrom(StreamInput in) throws IOException {
status = in.readEnum(STATUS.class);
}
@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeEnum(status);
}
}

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.XPackClient;
import org.elasticsearch.xpack.rest.XPackRestHandler;
import java.io.IOException;
import static org.elasticsearch.rest.RestRequest.Method.GET;
public class RestGetTrialStatus extends XPackRestHandler {
RestGetTrialStatus(Settings settings, RestController controller) {
super(settings);
controller.registerHandler(GET, URI_BASE + "/license/trial_status", this);
}
@Override
protected RestChannelConsumer doPrepareRequest(RestRequest request, XPackClient client) throws IOException {
return channel -> client.licensing().prepareGetUpgradeToTrial().execute(
new RestBuilderListener<GetTrialStatusResponse>(channel) {
@Override
public RestResponse buildResponse(GetTrialStatusResponse response, XContentBuilder builder) throws Exception {
builder.startObject();
builder.field("eligible_to_start_trial", response.isEligibleToStartTrial());
builder.endObject();
return new BytesRestResponse(RestStatus.OK, builder);
}
});
}
@Override
public String getName() {
return "xpack_trial_status_action";
}
}

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.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.XPackClient;
import org.elasticsearch.xpack.rest.XPackRestHandler;
import java.io.IOException;
import static org.elasticsearch.rest.RestRequest.Method.POST;
import static org.elasticsearch.rest.RestRequest.Method.PUT;
public class RestPostStartTrialLicense extends XPackRestHandler {
RestPostStartTrialLicense(Settings settings, RestController controller) {
super(settings);
controller.registerHandler(POST, URI_BASE + "/license/start_trial", this);
}
@Override
protected RestChannelConsumer doPrepareRequest(RestRequest request, XPackClient client) throws IOException {
return channel -> client.licensing().preparePutUpgradeToTrial().execute(
new RestBuilderListener<PostStartTrialResponse>(channel) {
@Override
public RestResponse buildResponse(PostStartTrialResponse response, XContentBuilder builder) throws Exception {
PostStartTrialResponse.STATUS status = response.getStatus();
if (status == PostStartTrialResponse.STATUS.TRIAL_ALREADY_ACTIVATED) {
builder.startObject()
.field("trial_was_started", false)
.field("error_message", "Operation failed: Trial was already activated.")
.endObject();
return new BytesRestResponse(RestStatus.FORBIDDEN, builder);
} else if (status == PostStartTrialResponse.STATUS.UPGRADED_TO_TRIAL) {
builder.startObject().field("trial_was_started", true).endObject();
return new BytesRestResponse(RestStatus.OK, builder);
} else {
throw new IllegalArgumentException("Unexpected status for PostStartTrialResponse: [" + status + "]");
}
}
});
}
@Override
public String getName() {
return "xpack_upgrade_to_trial_action";
}
}

View File

@ -0,0 +1,53 @@
/*
* 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 TransportGetTrialStatusAction extends TransportMasterNodeReadAction<GetTrialStatusRequest, GetTrialStatusResponse> {
@Inject
public TransportGetTrialStatusAction(Settings settings, TransportService transportService, ClusterService clusterService,
ThreadPool threadPool, ActionFilters actionFilters,
IndexNameExpressionResolver indexNameExpressionResolver) {
super(settings, GetTrialStatusAction.NAME, transportService, clusterService, threadPool, actionFilters,
GetTrialStatusRequest::new, indexNameExpressionResolver);
}
@Override
protected String executor() {
return ThreadPool.Names.SAME;
}
@Override
protected GetTrialStatusResponse newResponse() {
return new GetTrialStatusResponse();
}
@Override
protected void masterOperation(GetTrialStatusRequest request, ClusterState state,
ActionListener<GetTrialStatusResponse> listener) throws Exception {
LicensesMetaData licensesMetaData = state.metaData().custom(LicensesMetaData.TYPE);
listener.onResponse(new GetTrialStatusResponse(licensesMetaData == null || licensesMetaData.isEligibleForTrial()));
}
@Override
protected ClusterBlockException checkBlock(GetTrialStatusRequest 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 TransportPostStartTrialAction extends TransportMasterNodeAction<PostStartTrialRequest, PostStartTrialResponse> {
private final LicenseService licenseService;
@Inject
public TransportPostStartTrialAction(Settings settings, TransportService transportService, ClusterService clusterService,
LicenseService licenseService, ThreadPool threadPool, ActionFilters actionFilters,
IndexNameExpressionResolver indexNameExpressionResolver) {
super(settings, PostStartTrialAction.NAME, transportService, clusterService, threadPool, actionFilters,
indexNameExpressionResolver, PostStartTrialRequest::new);
this.licenseService = licenseService;
}
@Override
protected String executor() {
return ThreadPool.Names.SAME;
}
@Override
protected PostStartTrialResponse newResponse() {
return new PostStartTrialResponse();
}
@Override
protected void masterOperation(PostStartTrialRequest request, ClusterState state,
ActionListener<PostStartTrialResponse> listener) throws Exception {
licenseService.upgradeSelfGeneratedLicense(listener);
}
@Override
protected ClusterBlockException checkBlock(PostStartTrialRequest request, ClusterState state) {
return state.blocks().globalBlockedException(ClusterBlockLevel.METADATA_WRITE);
}
}

View File

@ -13,8 +13,8 @@ public enum MonitoredSystem {
ES("es"), ES("es"),
KIBANA("kibana"), KIBANA("kibana"),
// TODO: when "BEATS" is re-added, add it to tests where we randomly select "LOGSTASH"
LOGSTASH("logstash"), LOGSTASH("logstash"),
BEATS("beats"),
UNKNOWN("unknown"); UNKNOWN("unknown");
private final String system; private final String system;
@ -35,8 +35,6 @@ public enum MonitoredSystem {
return KIBANA; return KIBANA;
case "logstash": case "logstash":
return LOGSTASH; return LOGSTASH;
case "beats":
return BEATS;
default: default:
// Return an "unknown" monitored system // Return an "unknown" monitored system
// that can easily be filtered out if // that can easily be filtered out if

View File

@ -41,7 +41,7 @@ public final class MonitoringTemplateUtils {
/** /**
* IDs of templates that can be used with {@linkplain #loadTemplate(String) loadTemplate}. * IDs of templates that can be used with {@linkplain #loadTemplate(String) loadTemplate}.
*/ */
public static final String[] TEMPLATE_IDS = { "alerts", "es", "kibana", "logstash", "beats" }; public static final String[] TEMPLATE_IDS = { "alerts", "es", "kibana", "logstash" };
/** /**
* IDs of templates that can be used with {@linkplain #createEmptyTemplate(String) createEmptyTemplate} that are not managed by a * IDs of templates that can be used with {@linkplain #createEmptyTemplate(String) createEmptyTemplate} that are not managed by a

View File

@ -56,8 +56,7 @@ public class RestMonitoringBulkAction extends MonitoringRestHandler {
final Map<MonitoredSystem, List<String>> versionsMap = new HashMap<>(); final Map<MonitoredSystem, List<String>> versionsMap = new HashMap<>();
versionsMap.put(MonitoredSystem.KIBANA, allVersions); versionsMap.put(MonitoredSystem.KIBANA, allVersions);
versionsMap.put(MonitoredSystem.LOGSTASH, allVersions); versionsMap.put(MonitoredSystem.LOGSTASH, allVersions);
// Beats did not report data in the 5.x timeline, so it should never send the original version // Beats did not report data in the 5.x timeline, so it should never send the original version [when we add it!]
versionsMap.put(MonitoredSystem.BEATS, Collections.singletonList(MonitoringTemplateUtils.TEMPLATE_VERSION));
supportedApiVersions = Collections.unmodifiableMap(versionsMap); supportedApiVersions = Collections.unmodifiableMap(versionsMap);
} }

View File

@ -9,6 +9,10 @@ import org.elasticsearch.common.Booleans;
import org.elasticsearch.common.Strings; import org.elasticsearch.common.Strings;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.settings.SettingsException; import org.elasticsearch.common.settings.SettingsException;
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.xpack.common.http.HttpClient; import org.elasticsearch.xpack.common.http.HttpClient;
import org.elasticsearch.xpack.common.http.HttpMethod; import org.elasticsearch.xpack.common.http.HttpMethod;
import org.elasticsearch.xpack.common.http.HttpProxy; import org.elasticsearch.xpack.common.http.HttpProxy;
@ -18,6 +22,7 @@ import org.elasticsearch.xpack.common.http.Scheme;
import org.elasticsearch.xpack.common.http.auth.basic.BasicAuth; import org.elasticsearch.xpack.common.http.auth.basic.BasicAuth;
import java.io.IOException; import java.io.IOException;
import java.io.UncheckedIOException;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.util.Collections; import java.util.Collections;
@ -68,7 +73,15 @@ public class JiraAccount {
if (Strings.isEmpty(this.password)) { if (Strings.isEmpty(this.password)) {
throw requiredSettingException(name, PASSWORD_SETTING); throw requiredSettingException(name, PASSWORD_SETTING);
} }
this.issueDefaults = Collections.unmodifiableMap(settings.getAsSettings(ISSUE_DEFAULTS_SETTING).getAsStructuredMap()); try (XContentBuilder builder = XContentBuilder.builder(XContentType.JSON.xContent())) {
builder.startObject();
settings.getAsSettings(ISSUE_DEFAULTS_SETTING).toXContent(builder, ToXContent.EMPTY_PARAMS);
builder.endObject();
this.issueDefaults = Collections.unmodifiableMap(XContentType.JSON.xContent()
.createParser(new NamedXContentRegistry(Collections.emptyList()), builder.bytes()).map());
} catch (IOException ex) {
throw new UncheckedIOException(ex);
}
} }
public String getName() { public String getName() {

View File

@ -32,6 +32,7 @@ import org.elasticsearch.action.ActionListener;
import org.elasticsearch.bootstrap.BootstrapCheck; import org.elasticsearch.bootstrap.BootstrapCheck;
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.settings.SettingsException;
import org.elasticsearch.env.Environment; import org.elasticsearch.env.Environment;
import org.elasticsearch.watcher.FileChangesListener; import org.elasticsearch.watcher.FileChangesListener;
import org.elasticsearch.watcher.FileWatcher; import org.elasticsearch.watcher.FileWatcher;
@ -127,8 +128,8 @@ public class DnRoleMapper implements UserRoleMapper {
} }
} }
try (InputStream in = Files.newInputStream(path)) { try {
Settings settings = Settings.builder().loadFromStream(path.toString(), in).build(); Settings settings = Settings.builder().loadFromPath(path).build();
Map<DN, Set<String>> dnToRoles = new HashMap<>(); Map<DN, Set<String>> dnToRoles = new HashMap<>();
Set<String> roles = settings.names(); Set<String> roles = settings.names();
@ -163,7 +164,7 @@ public class DnRoleMapper implements UserRoleMapper {
logger.debug("[{}] role mappings found in file [{}] for realm [{}/{}]", dnToRoles.size(), path.toAbsolutePath(), realmType, logger.debug("[{}] role mappings found in file [{}] for realm [{}/{}]", dnToRoles.size(), path.toAbsolutePath(), realmType,
realmName); realmName);
return unmodifiableMap(dnToRoles); return unmodifiableMap(dnToRoles);
} catch (IOException | YAMLException e) { } catch (IOException | SettingsException e) {
throw new ElasticsearchException("could not read realm [" + realmType + "/" + realmName + "] role mappings file [" + throw new ElasticsearchException("could not read realm [" + realmType + "/" + realmName + "] role mappings file [" +
path.toAbsolutePath() + "]", e); path.toAbsolutePath() + "]", e);
} }

View File

@ -22,7 +22,8 @@ public final class SystemPrivilege extends Privilege {
"cluster:admin/reroute", // added for DiskThresholdDecider.DiskListener "cluster:admin/reroute", // added for DiskThresholdDecider.DiskListener
"indices:admin/mapping/put", // needed for recovery and shrink api "indices:admin/mapping/put", // needed for recovery and shrink api
"indices:admin/template/put", // needed for the TemplateUpgradeService "indices:admin/template/put", // needed for the TemplateUpgradeService
"indices:admin/template/delete" // needed for the TemplateUpgradeService "indices:admin/template/delete", // needed for the TemplateUpgradeService
"indices:admin/seq_no/global_checkpoint_sync*" // needed for global checkpoint syncs
), Automatons.patterns("internal:transport/proxy/*"))); // no proxy actions for system user! ), Automatons.patterns("internal:transport/proxy/*"))); // no proxy actions for system user!
private SystemPrivilege() { private SystemPrivilege() {

View File

@ -83,10 +83,8 @@ public final class RestrictedTrustConfig extends TrustConfig {
} }
private CertificateTrustRestrictions readTrustGroup(Path path) throws IOException { private CertificateTrustRestrictions readTrustGroup(Path path) throws IOException {
try (InputStream in = Files.newInputStream(path)) { Settings settings = Settings.builder().loadFromPath(path).build();
Settings settings = Settings.builder().loadFromStream(path.toString(), in).build();
final String[] trustNodeNames = settings.getAsArray(RESTRICTIONS_KEY_SUBJECT_NAME); final String[] trustNodeNames = settings.getAsArray(RESTRICTIONS_KEY_SUBJECT_NAME);
return new CertificateTrustRestrictions(Arrays.asList(trustNodeNames)); return new CertificateTrustRestrictions(Arrays.asList(trustNodeNames));
} }
} }
}

View File

@ -586,7 +586,7 @@ public class DocumentLevelSecurityTests extends SecurityIntegTestCase {
public void testChildrenAggregation() throws Exception { public void testChildrenAggregation() throws Exception {
assertAcked(client().admin().indices().prepareCreate("test") assertAcked(client().admin().indices().prepareCreate("test")
.setSettings("index.version.created", Version.V_5_6_0.id) .setSettings(Settings.builder().put("index.version.created", Version.V_5_6_0.id))
.addMapping("type1", "field1", "type=text", "field2", "type=text") .addMapping("type1", "field1", "type=text", "field2", "type=text")
.addMapping("type2", "_parent", "type=type1", "field3", "type=text,fielddata=true") .addMapping("type2", "_parent", "type=type1", "field3", "type=text,fielddata=true")
); );
@ -643,7 +643,7 @@ public class DocumentLevelSecurityTests extends SecurityIntegTestCase {
public void testParentChild_parentField() { public void testParentChild_parentField() {
assertAcked(prepareCreate("test") assertAcked(prepareCreate("test")
.setSettings("index.version.created", Version.V_5_6_0.id) .setSettings(Settings.builder().put("index.version.created", Version.V_5_6_0.id))
.addMapping("parent") .addMapping("parent")
.addMapping("child", "_parent", "type=parent", "field1", "type=text", "field2", "type=text", "field3", "type=text")); .addMapping("child", "_parent", "type=parent", "field1", "type=text", "field2", "type=text", "field3", "type=text"));
ensureGreen(); ensureGreen();

View File

@ -1221,7 +1221,7 @@ public class FieldLevelSecurityTests extends SecurityIntegTestCase {
public void testParentChild_parentField() { public void testParentChild_parentField() {
assertAcked(prepareCreate("test") assertAcked(prepareCreate("test")
.setSettings("index.version.created", Version.V_5_6_0.id) .setSettings(Settings.builder().put("index.version.created", Version.V_5_6_0.id))
.addMapping("parent") .addMapping("parent")
.addMapping("child", "_parent", "type=parent")); .addMapping("child", "_parent", "type=parent"));
ensureGreen(); ensureGreen();

View File

@ -49,16 +49,20 @@ public abstract class AbstractLicenseServiceTestCase extends ESTestCase {
} }
protected void setInitialState(License license, XPackLicenseState licenseState, Settings settings) { protected void setInitialState(License license, XPackLicenseState licenseState, Settings settings) {
setInitialState(license, licenseState, settings, randomBoolean() ? "trial" : "basic");
}
protected void setInitialState(License license, XPackLicenseState licenseState, Settings settings, String selfGeneratedType) {
Path tempDir = createTempDir(); Path tempDir = createTempDir();
when(environment.configFile()).thenReturn(tempDir); when(environment.configFile()).thenReturn(tempDir);
licenseType = randomBoolean() ? "trial" : "basic"; licenseType = selfGeneratedType;
settings = Settings.builder().put(settings).put(LicenseService.SELF_GENERATED_LICENSE_TYPE.getKey(), licenseType).build(); settings = Settings.builder().put(settings).put(LicenseService.SELF_GENERATED_LICENSE_TYPE.getKey(), licenseType).build();
licenseService = new LicenseService(settings, clusterService, clock, environment, resourceWatcherService, licenseState); licenseService = new LicenseService(settings, clusterService, clock, environment, resourceWatcherService, licenseState);
ClusterState state = mock(ClusterState.class); ClusterState state = mock(ClusterState.class);
final ClusterBlocks noBlock = ClusterBlocks.builder().build(); final ClusterBlocks noBlock = ClusterBlocks.builder().build();
when(state.blocks()).thenReturn(noBlock); when(state.blocks()).thenReturn(noBlock);
MetaData metaData = mock(MetaData.class); MetaData metaData = mock(MetaData.class);
when(metaData.custom(LicensesMetaData.TYPE)).thenReturn(new LicensesMetaData(license)); when(metaData.custom(LicensesMetaData.TYPE)).thenReturn(new LicensesMetaData(license, null));
when(state.metaData()).thenReturn(metaData); when(state.metaData()).thenReturn(metaData);
final DiscoveryNode mockNode = new DiscoveryNode("b", buildNewFakeTransportAddress(), emptyMap(), emptySet(), Version.CURRENT); final DiscoveryNode mockNode = new DiscoveryNode("b", buildNewFakeTransportAddress(), emptyMap(), emptySet(), Version.CURRENT);
when(discoveryNodes.getMasterNode()).thenReturn(mockNode); when(discoveryNodes.getMasterNode()).thenReturn(mockNode);

View File

@ -65,7 +65,7 @@ public abstract class AbstractLicensesIntegrationTestCase extends ESIntegTestCas
@Override @Override
public ClusterState execute(ClusterState currentState) throws Exception { public ClusterState execute(ClusterState currentState) throws Exception {
MetaData.Builder mdBuilder = MetaData.builder(currentState.metaData()); MetaData.Builder mdBuilder = MetaData.builder(currentState.metaData());
mdBuilder.putCustom(LicensesMetaData.TYPE, new LicensesMetaData(license)); mdBuilder.putCustom(LicensesMetaData.TYPE, new LicensesMetaData(license, null));
return ClusterState.builder(currentState).metaData(mdBuilder).build(); return ClusterState.builder(currentState).metaData(mdBuilder).build();
} }

View File

@ -47,7 +47,7 @@ public class LicenseClusterChangeTests extends AbstractLicenseServiceTestCase {
public void testNotificationOnNewLicense() throws Exception { public void testNotificationOnNewLicense() throws Exception {
ClusterState oldState = ClusterState.builder(new ClusterName("a")).build(); ClusterState oldState = ClusterState.builder(new ClusterName("a")).build();
final License license = TestUtils.generateSignedLicense(TimeValue.timeValueHours(24)); final License license = TestUtils.generateSignedLicense(TimeValue.timeValueHours(24));
MetaData metaData = MetaData.builder().putCustom(LicensesMetaData.TYPE, new LicensesMetaData(license)).build(); MetaData metaData = MetaData.builder().putCustom(LicensesMetaData.TYPE, new LicensesMetaData(license, null)).build();
ClusterState newState = ClusterState.builder(new ClusterName("a")).metaData(metaData).build(); ClusterState newState = ClusterState.builder(new ClusterName("a")).metaData(metaData).build();
licenseService.clusterChanged(new ClusterChangedEvent("simulated", newState, oldState)); licenseService.clusterChanged(new ClusterChangedEvent("simulated", newState, oldState));
assertThat(licenseState.activeUpdates.size(), equalTo(1)); assertThat(licenseState.activeUpdates.size(), equalTo(1));
@ -56,7 +56,7 @@ public class LicenseClusterChangeTests extends AbstractLicenseServiceTestCase {
public void testNoNotificationOnExistingLicense() throws Exception { public void testNoNotificationOnExistingLicense() throws Exception {
final License license = TestUtils.generateSignedLicense(TimeValue.timeValueHours(24)); final License license = TestUtils.generateSignedLicense(TimeValue.timeValueHours(24));
MetaData metaData = MetaData.builder().putCustom(LicensesMetaData.TYPE, new LicensesMetaData(license)).build(); MetaData metaData = MetaData.builder().putCustom(LicensesMetaData.TYPE, new LicensesMetaData(license, null)).build();
ClusterState newState = ClusterState.builder(new ClusterName("a")).metaData(metaData).build(); ClusterState newState = ClusterState.builder(new ClusterName("a")).metaData(metaData).build();
ClusterState oldState = ClusterState.builder(newState).build(); ClusterState oldState = ClusterState.builder(newState).build();
licenseService.clusterChanged(new ClusterChangedEvent("simulated", newState, oldState)); licenseService.clusterChanged(new ClusterChangedEvent("simulated", newState, oldState));

View File

@ -18,9 +18,9 @@ import static org.mockito.Mockito.when;
public class LicenseRegistrationTests extends AbstractLicenseServiceTestCase { public class LicenseRegistrationTests extends AbstractLicenseServiceTestCase {
public void testTrialLicenseRequestOnEmptyLicenseState() throws Exception { public void testSelfGeneratedTrialLicense() throws Exception {
XPackLicenseState licenseState = new XPackLicenseState(); XPackLicenseState licenseState = new XPackLicenseState();
setInitialState(null, licenseState, Settings.EMPTY); setInitialState(null, licenseState, Settings.EMPTY, "trial");
when(discoveryNodes.isLocalNodeElectedMaster()).thenReturn(true); when(discoveryNodes.isLocalNodeElectedMaster()).thenReturn(true);
licenseService.start(); licenseService.start();
@ -31,6 +31,26 @@ public class LicenseRegistrationTests extends AbstractLicenseServiceTestCase {
LicensesMetaData licenseMetaData = stateWithLicense.metaData().custom(LicensesMetaData.TYPE); LicensesMetaData licenseMetaData = stateWithLicense.metaData().custom(LicensesMetaData.TYPE);
assertNotNull(licenseMetaData); assertNotNull(licenseMetaData);
assertNotNull(licenseMetaData.getLicense()); assertNotNull(licenseMetaData.getLicense());
assertFalse(licenseMetaData.isEligibleForTrial());
assertEquals("trial", licenseMetaData.getLicense().type());
assertEquals(clock.millis() + LicenseService.SELF_GENERATED_LICENSE_DURATION.millis(), licenseMetaData.getLicense().expiryDate());
}
public void testSelfGeneratedBasicLicense() throws Exception {
XPackLicenseState licenseState = new XPackLicenseState();
setInitialState(null, licenseState, Settings.EMPTY, "basic");
when(discoveryNodes.isLocalNodeElectedMaster()).thenReturn(true);
licenseService.start();
ClusterState state = ClusterState.builder(new ClusterName("a")).build();
ArgumentCaptor<ClusterStateUpdateTask> stateUpdater = ArgumentCaptor.forClass(ClusterStateUpdateTask.class);
verify(clusterService, Mockito.times(1)).submitStateUpdateTask(any(), stateUpdater.capture());
ClusterState stateWithLicense = stateUpdater.getValue().execute(state);
LicensesMetaData licenseMetaData = stateWithLicense.metaData().custom(LicensesMetaData.TYPE);
assertNotNull(licenseMetaData);
assertNotNull(licenseMetaData.getLicense());
assertTrue(licenseMetaData.isEligibleForTrial());
assertEquals("basic", licenseMetaData.getLicense().type());
assertEquals(clock.millis() + LicenseService.SELF_GENERATED_LICENSE_DURATION.millis(), licenseMetaData.getLicense().expiryDate()); assertEquals(clock.millis() + LicenseService.SELF_GENERATED_LICENSE_DURATION.millis(), licenseMetaData.getLicense().expiryDate());
} }
} }

View File

@ -5,6 +5,7 @@
*/ */
package org.elasticsearch.license; package org.elasticsearch.license;
import org.elasticsearch.Version;
import org.elasticsearch.cluster.ClusterModule; import org.elasticsearch.cluster.ClusterModule;
import org.elasticsearch.cluster.metadata.MetaData; import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.cluster.metadata.RepositoriesMetaData; import org.elasticsearch.cluster.metadata.RepositoriesMetaData;
@ -29,9 +30,10 @@ import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue; import static org.hamcrest.Matchers.nullValue;
public class LicensesMetaDataSerializationTests extends ESTestCase { public class LicensesMetaDataSerializationTests extends ESTestCase {
public void testXContentSerializationOneSignedLicense() throws Exception { public void testXContentSerializationOneSignedLicense() throws Exception {
License license = TestUtils.generateSignedLicense(TimeValue.timeValueHours(2)); License license = TestUtils.generateSignedLicense(TimeValue.timeValueHours(2));
LicensesMetaData licensesMetaData = new LicensesMetaData(license); LicensesMetaData licensesMetaData = new LicensesMetaData(license, null);
XContentBuilder builder = XContentFactory.jsonBuilder(); XContentBuilder builder = XContentFactory.jsonBuilder();
builder.startObject(); builder.startObject();
builder.startObject("licenses"); builder.startObject("licenses");
@ -40,12 +42,27 @@ public class LicensesMetaDataSerializationTests extends ESTestCase {
builder.endObject(); builder.endObject();
LicensesMetaData licensesMetaDataFromXContent = getLicensesMetaDataFromXContent(createParser(builder)); LicensesMetaData licensesMetaDataFromXContent = getLicensesMetaDataFromXContent(createParser(builder));
assertThat(licensesMetaDataFromXContent.getLicense(), equalTo(license)); assertThat(licensesMetaDataFromXContent.getLicense(), equalTo(license));
assertNull(licensesMetaDataFromXContent.getMostRecentTrialVersion());
}
public void testXContentSerializationOneSignedLicenseWithUsedTrial() throws Exception {
License license = TestUtils.generateSignedLicense(TimeValue.timeValueHours(2));
LicensesMetaData licensesMetaData = new LicensesMetaData(license, Version.CURRENT);
XContentBuilder builder = XContentFactory.jsonBuilder();
builder.startObject();
builder.startObject("licenses");
licensesMetaData.toXContent(builder, ToXContent.EMPTY_PARAMS);
builder.endObject();
builder.endObject();
LicensesMetaData licensesMetaDataFromXContent = getLicensesMetaDataFromXContent(createParser(builder));
assertThat(licensesMetaDataFromXContent.getLicense(), equalTo(license));
assertEquals(licensesMetaDataFromXContent.getMostRecentTrialVersion(), Version.CURRENT);
} }
public void testLicenseMetadataParsingDoesNotSwallowOtherMetaData() throws Exception { public void testLicenseMetadataParsingDoesNotSwallowOtherMetaData() throws Exception {
new Licensing(Settings.EMPTY); // makes sure LicensePlugin is registered in Custom MetaData new Licensing(Settings.EMPTY); // makes sure LicensePlugin is registered in Custom MetaData
License license = TestUtils.generateSignedLicense(TimeValue.timeValueHours(2)); License license = TestUtils.generateSignedLicense(TimeValue.timeValueHours(2));
LicensesMetaData licensesMetaData = new LicensesMetaData(license); LicensesMetaData licensesMetaData = new LicensesMetaData(license, Version.CURRENT);
RepositoryMetaData repositoryMetaData = new RepositoryMetaData("repo", "fs", Settings.EMPTY); RepositoryMetaData repositoryMetaData = new RepositoryMetaData("repo", "fs", Settings.EMPTY);
RepositoriesMetaData repositoriesMetaData = new RepositoriesMetaData(repositoryMetaData); RepositoriesMetaData repositoriesMetaData = new RepositoriesMetaData(repositoryMetaData);
final MetaData.Builder metaDataBuilder = MetaData.builder(); final MetaData.Builder metaDataBuilder = MetaData.builder();
@ -79,7 +96,7 @@ public class LicensesMetaDataSerializationTests extends ESTestCase {
.type(randomBoolean() ? "trial" : "basic") .type(randomBoolean() ? "trial" : "basic")
.expiryDate(issueDate + TimeValue.timeValueHours(2).getMillis()); .expiryDate(issueDate + TimeValue.timeValueHours(2).getMillis());
final License trialLicense = SelfGeneratedLicense.create(specBuilder); final License trialLicense = SelfGeneratedLicense.create(specBuilder);
LicensesMetaData licensesMetaData = new LicensesMetaData(trialLicense); LicensesMetaData licensesMetaData = new LicensesMetaData(trialLicense, Version.CURRENT);
XContentBuilder builder = XContentFactory.jsonBuilder(); XContentBuilder builder = XContentFactory.jsonBuilder();
builder.startObject(); builder.startObject();
builder.startObject("licenses"); builder.startObject("licenses");
@ -88,6 +105,7 @@ public class LicensesMetaDataSerializationTests extends ESTestCase {
builder.endObject(); builder.endObject();
LicensesMetaData licensesMetaDataFromXContent = getLicensesMetaDataFromXContent(createParser(builder)); LicensesMetaData licensesMetaDataFromXContent = getLicensesMetaDataFromXContent(createParser(builder));
assertThat(licensesMetaDataFromXContent.getLicense(), equalTo(trialLicense)); assertThat(licensesMetaDataFromXContent.getLicense(), equalTo(trialLicense));
assertEquals(licensesMetaDataFromXContent.getMostRecentTrialVersion(), Version.CURRENT);
} }
public void testLicenseTombstoneFromXContext() throws Exception { public void testLicenseTombstoneFromXContext() throws Exception {
@ -101,6 +119,19 @@ public class LicensesMetaDataSerializationTests extends ESTestCase {
assertThat(metaDataFromXContent.getLicense(), equalTo(LicensesMetaData.LICENSE_TOMBSTONE)); assertThat(metaDataFromXContent.getLicense(), equalTo(LicensesMetaData.LICENSE_TOMBSTONE));
} }
public void testLicenseTombstoneWithUsedTrialFromXContext() throws Exception {
final XContentBuilder builder = XContentFactory.jsonBuilder();
builder.startObject();
builder.startObject("licenses");
builder.nullField("license");
builder.field("trial_license", Version.CURRENT.toString());
builder.endObject();
builder.endObject();
LicensesMetaData metaDataFromXContent = getLicensesMetaDataFromXContent(createParser(builder));
assertThat(metaDataFromXContent.getLicense(), equalTo(LicensesMetaData.LICENSE_TOMBSTONE));
assertEquals(metaDataFromXContent.getMostRecentTrialVersion(), Version.CURRENT);
}
private static LicensesMetaData getLicensesMetaDataFromXContent(XContentParser parser) throws Exception { private static LicensesMetaData getLicensesMetaDataFromXContent(XContentParser parser) throws Exception {
parser.nextToken(); // consume null parser.nextToken(); // consume null
parser.nextToken(); // consume "licenses" parser.nextToken(); // consume "licenses"

View File

@ -348,6 +348,6 @@ public class TestUtils {
} }
public static void putLicense(MetaData.Builder builder, License license) { public static void putLicense(MetaData.Builder builder, License license) {
builder.putCustom(LicensesMetaData.TYPE, new LicensesMetaData(license)); builder.putCustom(LicensesMetaData.TYPE, new LicensesMetaData(license, null));
} }
} }

View File

@ -0,0 +1,78 @@
/*
* 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.plugins.Plugin;
import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.transport.Netty4Plugin;
import org.elasticsearch.xpack.XPackPlugin;
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 UpgradeToTrialTests 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(XPackPlugin.class, Netty4Plugin.class);
}
@Override
protected Collection<Class<? extends Plugin>> transportClientPlugins() {
return nodePlugins();
}
public void testUpgradeToTrial() throws Exception {
LicensingClient licensingClient = new LicensingClient(client());
GetLicenseResponse getLicenseResponse = licensingClient.prepareGetLicense().get();
assertEquals("basic", getLicenseResponse.license().type());
RestClient restClient = getRestClient();
Response response = restClient.performRequest("GET", "/_xpack/license/trial_status");
String body = Streams.copyToString(new InputStreamReader(response.getEntity().getContent(), StandardCharsets.UTF_8));
assertEquals(200, response.getStatusLine().getStatusCode());
assertEquals("{\"eligible_to_start_trial\":true}", body);
Response response2 = restClient.performRequest("POST", "/_xpack/license/start_trial");
String body2 = Streams.copyToString(new InputStreamReader(response2.getEntity().getContent(), StandardCharsets.UTF_8));
assertEquals(200, response2.getStatusLine().getStatusCode());
assertEquals("{\"trial_was_started\":true}", body2);
Response response3 = restClient.performRequest("GET", "/_xpack/license/trial_status");
String body3 = Streams.copyToString(new InputStreamReader(response3.getEntity().getContent(), StandardCharsets.UTF_8));
assertEquals(200, response3.getStatusLine().getStatusCode());
assertEquals("{\"eligible_to_start_trial\":false}", body3);
ResponseException ex = expectThrows(ResponseException.class,
() -> restClient.performRequest("POST", "/_xpack/license/start_trial"));
Response response4 = ex.getResponse();
String body4 = Streams.copyToString(new InputStreamReader(response4.getEntity().getContent(), StandardCharsets.UTF_8));
assertEquals(403, response4.getStatusLine().getStatusCode());
assertTrue(body4.contains("\"trial_was_started\":false"));
assertTrue(body4.contains("\"error_message\":\"Operation failed: Trial was already activated.\""));
}
}

View File

@ -214,7 +214,7 @@ public abstract class SecurityIntegTestCase extends ESIntegTestCase {
// Disable native ML autodetect_process as the c++ controller won't be available // Disable native ML autodetect_process as the c++ controller won't be available
.put(MachineLearning.AUTODETECT_PROCESS.getKey(), false); .put(MachineLearning.AUTODETECT_PROCESS.getKey(), false);
Settings customSettings = customSecuritySettingsSource.nodeSettings(nodeOrdinal); Settings customSettings = customSecuritySettingsSource.nodeSettings(nodeOrdinal);
builder.put(customSettings.getAsMap()); // handle secure settings separately builder.put(customSettings, false); // handle secure settings separately
Settings.Builder customBuilder = Settings.builder().put(customSettings); Settings.Builder customBuilder = Settings.builder().put(customSettings);
if (customBuilder.getSecureSettings() != null) { if (customBuilder.getSecureSettings() != null) {
SecuritySettingsSource.addSecureSettings(builder, secureSettings -> SecuritySettingsSource.addSecureSettings(builder, secureSettings ->

View File

@ -79,7 +79,7 @@ public class GraphTests extends XPackSingleNodeTestCase {
public void setUp() throws Exception { public void setUp() throws Exception {
super.setUp(); super.setUp();
assertAcked(client().admin().indices().prepareCreate("test") assertAcked(client().admin().indices().prepareCreate("test")
.setSettings(SETTING_NUMBER_OF_SHARDS, 2, SETTING_NUMBER_OF_REPLICAS, 0) .setSettings(Settings.builder().put(SETTING_NUMBER_OF_SHARDS, 2).put(SETTING_NUMBER_OF_REPLICAS, 0))
.addMapping("type", .addMapping("type",
"decade", "type=keyword", "decade", "type=keyword",
"people", "type=keyword", "people", "type=keyword",

View File

@ -92,16 +92,12 @@ public class MonitoringSettingsIntegTests extends MonitoringIntegTestCase {
MonitoringSettings.JOB_STATS_TIMEOUT}; MonitoringSettings.JOB_STATS_TIMEOUT};
for (Setting<?> setting : monitoringSettings) { for (Setting<?> setting : monitoringSettings) {
if (setting.isDynamic()) { if (setting.isDynamic()) {
Object updated = null;
if (setting.get(Settings.EMPTY) instanceof TimeValue) { if (setting.get(Settings.EMPTY) instanceof TimeValue) {
updated = newRandomTimeValue(); transientSettings.put(setting.getKey(), newRandomTimeValue().toString());
transientSettings.put(setting.getKey(), updated);
} else if (setting.get(Settings.EMPTY) instanceof Boolean) { } else if (setting.get(Settings.EMPTY) instanceof Boolean) {
updated = randomBoolean(); transientSettings.put(setting.getKey(), randomBoolean());
transientSettings.put(setting.getKey(), updated);
} else if (setting.get(Settings.EMPTY) instanceof List) { } else if (setting.get(Settings.EMPTY) instanceof List) {
updated = randomStringArray(); transientSettings.putArray(setting.getKey(), randomStringArray());
transientSettings.putArray(setting.getKey(), (String[]) updated);
} else { } else {
fail("unknown dynamic setting [" + setting + "]"); fail("unknown dynamic setting [" + setting + "]");
} }

View File

@ -131,7 +131,7 @@ public class TransportMonitoringBulkActionTests extends ESTestCase {
final MonitoringBulkRequest request = new MonitoringBulkRequest(); final MonitoringBulkRequest request = new MonitoringBulkRequest();
final MonitoredSystem system = randomFrom(MonitoredSystem.KIBANA, MonitoredSystem.BEATS, MonitoredSystem.LOGSTASH); final MonitoredSystem system = randomFrom(MonitoredSystem.KIBANA, MonitoredSystem.LOGSTASH);
final String type = randomAlphaOfLength(5); final String type = randomAlphaOfLength(5);
final String id = randomBoolean() ? randomAlphaOfLength(5) : null; final String id = randomBoolean() ? randomAlphaOfLength(5) : null;
final long timestamp = randomNonNegativeLong(); final long timestamp = randomNonNegativeLong();
@ -198,7 +198,7 @@ public class TransportMonitoringBulkActionTests extends ESTestCase {
public void testAsyncActionCreateMonitoringDocs() throws Exception { public void testAsyncActionCreateMonitoringDocs() throws Exception {
final List<MonitoringBulkDoc> docs = new ArrayList<>(); final List<MonitoringBulkDoc> docs = new ArrayList<>();
final MonitoredSystem system = randomFrom(MonitoredSystem.KIBANA, MonitoredSystem.BEATS, MonitoredSystem.LOGSTASH); final MonitoredSystem system = randomFrom(MonitoredSystem.KIBANA, MonitoredSystem.LOGSTASH);
final String type = randomAlphaOfLength(5); final String type = randomAlphaOfLength(5);
final String id = randomBoolean() ? randomAlphaOfLength(5) : null; final String id = randomBoolean() ? randomAlphaOfLength(5) : null;
final long timestamp = randomBoolean() ? randomNonNegativeLong() : 0L; final long timestamp = randomBoolean() ? randomNonNegativeLong() : 0L;
@ -235,7 +235,7 @@ public class TransportMonitoringBulkActionTests extends ESTestCase {
public void testAsyncActionCreateMonitoringDocWithNoTimestamp() throws Exception { public void testAsyncActionCreateMonitoringDocWithNoTimestamp() throws Exception {
final MonitoringBulkDoc monitoringBulkDoc = final MonitoringBulkDoc monitoringBulkDoc =
new MonitoringBulkDoc(MonitoredSystem.BEATS, "_type", "_id", 0L, 0L, BytesArray.EMPTY, XContentType.JSON); new MonitoringBulkDoc(MonitoredSystem.LOGSTASH, "_type", "_id", 0L, 0L, BytesArray.EMPTY, XContentType.JSON);
final MonitoringDoc monitoringDoc = final MonitoringDoc monitoringDoc =
new TransportMonitoringBulkAction.AsyncAction(null, null, null, "", 456L, null).createMonitoringDoc(monitoringBulkDoc); new TransportMonitoringBulkAction.AsyncAction(null, null, null, "", 456L, null).createMonitoringDoc(monitoringBulkDoc);

View File

@ -96,8 +96,6 @@ public class MonitoringTemplateUtilsTests extends ESTestCase {
DateTimeFormatter formatter = DateTimeFormat.forPattern("YYYY.MM.dd").withZoneUTC(); DateTimeFormatter formatter = DateTimeFormat.forPattern("YYYY.MM.dd").withZoneUTC();
assertThat(indexName(formatter, MonitoredSystem.ES, timestamp), assertThat(indexName(formatter, MonitoredSystem.ES, timestamp),
equalTo(".monitoring-es-" + TEMPLATE_VERSION + "-2017.08.03")); equalTo(".monitoring-es-" + TEMPLATE_VERSION + "-2017.08.03"));
assertThat(indexName(formatter, MonitoredSystem.BEATS, timestamp),
equalTo(".monitoring-beats-" + TEMPLATE_VERSION + "-2017.08.03"));
assertThat(indexName(formatter, MonitoredSystem.KIBANA, timestamp), assertThat(indexName(formatter, MonitoredSystem.KIBANA, timestamp),
equalTo(".monitoring-kibana-" + TEMPLATE_VERSION + "-2017.08.03")); equalTo(".monitoring-kibana-" + TEMPLATE_VERSION + "-2017.08.03"));
assertThat(indexName(formatter, MonitoredSystem.LOGSTASH, timestamp), assertThat(indexName(formatter, MonitoredSystem.LOGSTASH, timestamp),
@ -106,8 +104,6 @@ public class MonitoringTemplateUtilsTests extends ESTestCase {
formatter = DateTimeFormat.forPattern("YYYY-dd-MM-HH.mm.ss").withZoneUTC(); formatter = DateTimeFormat.forPattern("YYYY-dd-MM-HH.mm.ss").withZoneUTC();
assertThat(indexName(formatter, MonitoredSystem.ES, timestamp), assertThat(indexName(formatter, MonitoredSystem.ES, timestamp),
equalTo(".monitoring-es-" + TEMPLATE_VERSION + "-2017-03-08-13.47.58")); equalTo(".monitoring-es-" + TEMPLATE_VERSION + "-2017-03-08-13.47.58"));
assertThat(indexName(formatter, MonitoredSystem.BEATS, timestamp),
equalTo(".monitoring-beats-" + TEMPLATE_VERSION + "-2017-03-08-13.47.58"));
assertThat(indexName(formatter, MonitoredSystem.KIBANA, timestamp), assertThat(indexName(formatter, MonitoredSystem.KIBANA, timestamp),
equalTo(".monitoring-kibana-" + TEMPLATE_VERSION + "-2017-03-08-13.47.58")); equalTo(".monitoring-kibana-" + TEMPLATE_VERSION + "-2017-03-08-13.47.58"));
assertThat(indexName(formatter, MonitoredSystem.LOGSTASH, timestamp), assertThat(indexName(formatter, MonitoredSystem.LOGSTASH, timestamp),

View File

@ -61,9 +61,9 @@ public class HttpExporterResourceTests extends AbstractPublishableHttpResourceTe
private final boolean createOldTemplates = randomBoolean(); private final boolean createOldTemplates = randomBoolean();
/** /**
* kibana, logstash, beats * kibana, logstash (and beats in the future)
*/ */
private final int EXPECTED_TEMPLATES = 5 + (createOldTemplates ? OLD_TEMPLATE_IDS.length : 0); private final int EXPECTED_TEMPLATES = TEMPLATE_IDS.length + (createOldTemplates ? OLD_TEMPLATE_IDS.length : 0);
private final int EXPECTED_PIPELINES = PIPELINE_IDS.length; private final int EXPECTED_PIPELINES = PIPELINE_IDS.length;
private final int EXPECTED_WATCHES = ClusterAlertsUtil.WATCH_IDS.length; private final int EXPECTED_WATCHES = ClusterAlertsUtil.WATCH_IDS.length;

View File

@ -37,6 +37,7 @@ import java.util.stream.Collectors;
import static org.elasticsearch.xpack.monitoring.exporter.MonitoringTemplateUtils.OLD_TEMPLATE_IDS; import static org.elasticsearch.xpack.monitoring.exporter.MonitoringTemplateUtils.OLD_TEMPLATE_IDS;
import static org.elasticsearch.xpack.monitoring.exporter.MonitoringTemplateUtils.PIPELINE_IDS; import static org.elasticsearch.xpack.monitoring.exporter.MonitoringTemplateUtils.PIPELINE_IDS;
import static org.elasticsearch.xpack.monitoring.exporter.MonitoringTemplateUtils.TEMPLATE_IDS;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.not;
@ -347,7 +348,7 @@ public class HttpExporterTests extends ESTestCase {
assertThat(multiResource.getResources().size(), assertThat(multiResource.getResources().size(),
equalTo(version + templates.size() + pipelines.size() + watcherCheck.size())); equalTo(version + templates.size() + pipelines.size() + watcherCheck.size()));
assertThat(version, equalTo(1)); assertThat(version, equalTo(1));
assertThat(templates, hasSize(createOldTemplates ? 5 + OLD_TEMPLATE_IDS.length : 5)); assertThat(templates, hasSize(createOldTemplates ? TEMPLATE_IDS.length + OLD_TEMPLATE_IDS.length : TEMPLATE_IDS.length));
assertThat(pipelines, hasSize(useIngest ? PIPELINE_IDS.length : 0)); assertThat(pipelines, hasSize(useIngest ? PIPELINE_IDS.length : 0));
assertThat(watcherCheck, hasSize(clusterAlertManagement ? 1 : 0)); assertThat(watcherCheck, hasSize(clusterAlertManagement ? 1 : 0));
assertThat(watches, hasSize(clusterAlertManagement ? ClusterAlertsUtil.WATCH_IDS.length : 0)); assertThat(watches, hasSize(clusterAlertManagement ? ClusterAlertsUtil.WATCH_IDS.length : 0));

View File

@ -55,7 +55,6 @@ import java.util.stream.Collectors;
import static org.elasticsearch.search.aggregations.AggregationBuilders.max; import static org.elasticsearch.search.aggregations.AggregationBuilders.max;
import static org.elasticsearch.search.aggregations.AggregationBuilders.terms; import static org.elasticsearch.search.aggregations.AggregationBuilders.terms;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
import static org.elasticsearch.xpack.monitoring.MonitoredSystem.BEATS;
import static org.elasticsearch.xpack.monitoring.MonitoredSystem.KIBANA; import static org.elasticsearch.xpack.monitoring.MonitoredSystem.KIBANA;
import static org.elasticsearch.xpack.monitoring.MonitoredSystem.LOGSTASH; import static org.elasticsearch.xpack.monitoring.MonitoredSystem.LOGSTASH;
import static org.elasticsearch.xpack.monitoring.exporter.MonitoringTemplateUtils.PIPELINE_IDS; import static org.elasticsearch.xpack.monitoring.exporter.MonitoringTemplateUtils.PIPELINE_IDS;
@ -231,12 +230,9 @@ public class LocalExporterIntegTests extends LocalExporterIntegTestCase {
templates.add(".monitoring-es"); templates.add(".monitoring-es");
templates.add(".monitoring-kibana"); templates.add(".monitoring-kibana");
templates.add(".monitoring-logstash"); templates.add(".monitoring-logstash");
templates.add(".monitoring-beats");
GetIndexTemplatesResponse response = GetIndexTemplatesResponse response = client().admin().indices().prepareGetTemplates(".monitoring-*").get();
client().admin().indices().prepareGetTemplates(".monitoring-*").get(); Set<String> actualTemplates = response.getIndexTemplates().stream().map(IndexTemplateMetaData::getName).collect(Collectors.toSet());
Set<String> actualTemplates = response.getIndexTemplates().stream()
.map(IndexTemplateMetaData::getName).collect(Collectors.toSet());
assertEquals(templates, actualTemplates); assertEquals(templates, actualTemplates);
} }
@ -330,7 +326,7 @@ public class LocalExporterIntegTests extends LocalExporterIntegTestCase {
} }
private static MonitoringBulkDoc createMonitoringBulkDoc() throws IOException { private static MonitoringBulkDoc createMonitoringBulkDoc() throws IOException {
final MonitoredSystem system = randomFrom(BEATS, KIBANA, LOGSTASH); final MonitoredSystem system = randomFrom(KIBANA, LOGSTASH);
final XContentType xContentType = randomFrom(XContentType.values()); final XContentType xContentType = randomFrom(XContentType.values());
final BytesReference source; final BytesReference source;

View File

@ -11,6 +11,7 @@ import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity; import org.apache.http.entity.StringEntity;
import org.apache.http.nio.entity.NStringEntity; import org.apache.http.nio.entity.NStringEntity;
import org.apache.lucene.util.Constants; import org.apache.lucene.util.Constants;
import org.apache.lucene.util.LuceneTestCase;
import org.elasticsearch.ElasticsearchException; import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.Version; import org.elasticsearch.Version;
import org.elasticsearch.client.Response; import org.elasticsearch.client.Response;
@ -63,6 +64,7 @@ import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue; import static org.hamcrest.Matchers.nullValue;
@LuceneTestCase.AwaitsFix(bugUrl = "https://github.com/elastic/x-pack-elasticsearch/issues/2609")
public class MonitoringIT extends ESRestTestCase { public class MonitoringIT extends ESRestTestCase {
private static final String BASIC_AUTH_VALUE = basicAuthHeaderValue("x_pack_rest_user", TEST_PASSWORD_SECURE_STRING); private static final String BASIC_AUTH_VALUE = basicAuthHeaderValue("x_pack_rest_user", TEST_PASSWORD_SECURE_STRING);
@ -410,7 +412,7 @@ public class MonitoringIT extends ESRestTestCase {
assertEquals(5, source.size()); assertEquals(5, source.size());
final Map<String, Object> nodeStats = (Map<String, Object>) source.get(NodeStatsMonitoringDoc.TYPE); final Map<String, Object> nodeStats = (Map<String, Object>) source.get(NodeStatsMonitoringDoc.TYPE);
assertEquals(9, nodeStats.size()); assertEquals(Constants.WINDOWS ? 8 : 9, nodeStats.size());
NodeStatsMonitoringDoc.XCONTENT_FILTERS.forEach(filter -> { NodeStatsMonitoringDoc.XCONTENT_FILTERS.forEach(filter -> {
if (Constants.WINDOWS && filter.startsWith("node_stats.os.cpu.load_average")) { if (Constants.WINDOWS && filter.startsWith("node_stats.os.cpu.load_average")) {
@ -650,6 +652,6 @@ public class MonitoringIT extends ESRestTestCase {
* Returns a {@link MonitoredSystem} supported by the Monitoring Bulk API * Returns a {@link MonitoredSystem} supported by the Monitoring Bulk API
*/ */
private static MonitoredSystem randomSystem() { private static MonitoredSystem randomSystem() {
return randomFrom(MonitoredSystem.LOGSTASH, MonitoredSystem.KIBANA, MonitoredSystem.BEATS); return randomFrom(MonitoredSystem.LOGSTASH, MonitoredSystem.KIBANA);
} }
} }

View File

@ -216,7 +216,7 @@ public class JiraAccountTests extends ESTestCase {
for (Map.Entry<String, Object> setting : defaults.entrySet()) { for (Map.Entry<String, Object> setting : defaults.entrySet()) {
String key = "xpack.notification.jira.account." + name + "." + JiraAccount.ISSUE_DEFAULTS_SETTING + "." + setting.getKey(); String key = "xpack.notification.jira.account." + name + "." + JiraAccount.ISSUE_DEFAULTS_SETTING + "." + setting.getKey();
if (setting.getValue() instanceof String) { if (setting.getValue() instanceof String) {
builder.put(key, setting.getValue()); builder.put(key, setting.getValue().toString());
} else if (setting.getValue() instanceof Map) { } else if (setting.getValue() instanceof Map) {
builder.putProperties((Map) setting.getValue(), s -> key + "." + s); builder.putProperties((Map) setting.getValue(), s -> key + "." + s);
} }

View File

@ -226,17 +226,19 @@ public class SecurityTribeIT extends NativeRealmIntegTestCase {
} }
}; };
final Settings settingsTemplate = cluster2SettingsSource.nodeSettings(0); final Settings settingsTemplate = cluster2SettingsSource.nodeSettings(0);
Map<String, String> asMap = new HashMap<>(settingsTemplate.getAsMap());
asMap.remove(NodeEnvironment.MAX_LOCAL_STORAGE_NODES_SETTING.getKey());
Settings.Builder tribe1Defaults = Settings.builder(); Settings.Builder tribe1Defaults = Settings.builder();
Settings.Builder tribe2Defaults = Settings.builder(); Settings.Builder tribe2Defaults = Settings.builder();
for (Map.Entry<String, String> entry : asMap.entrySet()) { Settings tribeSettings = settingsTemplate.filter(k -> {
if (entry.getKey().startsWith("path.")) { if (k.equals(NodeEnvironment.MAX_LOCAL_STORAGE_NODES_SETTING.getKey())) {
continue; return false;
} else if (entry.getKey().equals("transport.tcp.port")) { } if (k.startsWith("path.")) {
continue; return false;
} else if (k.equals("transport.tcp.port")) {
return false;
} }
return true;
});
for (Map.Entry<String, String> entry : tribeSettings.getAsMap().entrySet()) {
tribe1Defaults.put("tribe.t1." + entry.getKey(), entry.getValue()); tribe1Defaults.put("tribe.t1." + entry.getKey(), entry.getValue());
tribe2Defaults.put("tribe.t2." + entry.getKey(), entry.getValue()); tribe2Defaults.put("tribe.t2." + entry.getKey(), entry.getValue());
} }
@ -255,7 +257,7 @@ public class SecurityTribeIT extends NativeRealmIntegTestCase {
Settings merged = Settings.builder() Settings merged = Settings.builder()
.put(internalCluster().getDefaultSettings()) .put(internalCluster().getDefaultSettings())
.put(asMap) .put(tribeSettings, false)
.put("tribe.t1.cluster.name", internalCluster().getClusterName()) .put("tribe.t1.cluster.name", internalCluster().getClusterName())
.put("tribe.t2.cluster.name", cluster2.getClusterName()) .put("tribe.t2.cluster.name", cluster2.getClusterName())
.put("tribe.blocks.write", false) .put("tribe.blocks.write", false)

View File

@ -123,5 +123,8 @@ public class PrivilegeTests extends ESTestCase {
assertThat(predicate.test("indices:admin/mapping/put"), is(true)); assertThat(predicate.test("indices:admin/mapping/put"), is(true));
assertThat(predicate.test("indices:admin/mapping/whatever"), is(false)); assertThat(predicate.test("indices:admin/mapping/whatever"), is(false));
assertThat(predicate.test("internal:transport/proxy/indices:data/read/query"), is(false)); assertThat(predicate.test("internal:transport/proxy/indices:data/read/query"), is(false));
assertThat(predicate.test("indices:admin/seq_no/global_checkpoint_sync"), is(true));
assertThat(predicate.test("indices:admin/seq_no/global_checkpoint_sync[p]"), is(true));
assertThat(predicate.test("indices:admin/seq_no/global_checkpoint_sync[r]"), is(true));
} }
} }

View File

@ -102,7 +102,6 @@ public class ServerTransportFilterIntegrationTests extends SecurityIntegTestCase
// test that starting up a node works // test that starting up a node works
Settings.Builder nodeSettings = Settings.builder() Settings.Builder nodeSettings = Settings.builder()
.put()
.put("node.name", "my-test-node") .put("node.name", "my-test-node")
.put("network.host", "localhost") .put("network.host", "localhost")
.put("cluster.name", internalCluster().getClusterName()) .put("cluster.name", internalCluster().getClusterName())

View File

@ -95,7 +95,7 @@ public class DNSOnlyHostnameVerificationTests extends SecurityIntegTestCase {
public Settings nodeSettings(int nodeOrdinal) { public Settings nodeSettings(int nodeOrdinal) {
Settings defaultSettings = super.nodeSettings(nodeOrdinal); Settings defaultSettings = super.nodeSettings(nodeOrdinal);
Settings.Builder builder = Settings.builder() Settings.Builder builder = Settings.builder()
.put(defaultSettings.filter((s) -> s.startsWith("xpack.ssl.") == false).getAsMap()) .put(defaultSettings.filter((s) -> s.startsWith("xpack.ssl.") == false), false)
.put("transport.host", hostName); .put("transport.host", hostName);
Path keystorePath = nodeConfigPath(nodeOrdinal).resolve("keystore.jks"); Path keystorePath = nodeConfigPath(nodeOrdinal).resolve("keystore.jks");
try (OutputStream os = Files.newOutputStream(keystorePath)) { try (OutputStream os = Files.newOutputStream(keystorePath)) {

View File

@ -31,7 +31,7 @@ public class IPHostnameVerificationTests extends SecurityIntegTestCase {
protected Settings nodeSettings(int nodeOrdinal) { protected Settings nodeSettings(int nodeOrdinal) {
Settings settings = super.nodeSettings(nodeOrdinal); Settings settings = super.nodeSettings(nodeOrdinal);
Settings.Builder builder = Settings.builder() Settings.Builder builder = Settings.builder()
.put(settings.filter((s) -> s.startsWith("xpack.ssl.") == false).getAsMap()); .put(settings.filter((s) -> s.startsWith("xpack.ssl.") == false), false);
settings = builder.build(); settings = builder.build();
// The default Unicast test behavior is to use 'localhost' with the port number. For this test we need to use IP // The default Unicast test behavior is to use 'localhost' with the port number. For this test we need to use IP

View File

@ -162,3 +162,5 @@ indices:data/write/delete/byquery
indices:data/write/reindex indices:data/write/reindex
cluster:admin/xpack/deprecation/info cluster:admin/xpack/deprecation/info
cluster:admin/xpack/ml/job/forecast cluster:admin/xpack/ml/job/forecast
cluster:admin/xpack/license/start_trial
cluster:admin/xpack/license/trial_status

View File

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

View File

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

View File

@ -161,7 +161,7 @@
- do: - do:
xpack.monitoring.bulk: xpack.monitoring.bulk:
system_id: "beats" system_id: "logstash"
system_api_version: "6" system_api_version: "6"
interval: "5s" interval: "5s"
body: body:
@ -183,17 +183,17 @@
- do: - do:
search: search:
index: .monitoring-beats-* index: .monitoring-logstash-*
- match: { hits.total: 2 } - match: { hits.total: 2 }
- do: - do:
indices.close: indices.close:
index: .monitoring-beats-* index: .monitoring-logstash-*
- do: - do:
catch: /export_exception/ catch: /export_exception/
xpack.monitoring.bulk: xpack.monitoring.bulk:
system_id: "beats" system_id: "logstash"
system_api_version: "6" system_api_version: "6"
interval: "5s" interval: "5s"
body: body:

View File

@ -38,7 +38,7 @@ public class CustomRealmIT extends ESIntegTestCase {
protected Settings externalClusterClientSettings() { protected Settings externalClusterClientSettings() {
return Settings.builder() return Settings.builder()
.put(ThreadContext.PREFIX + "." + CustomRealm.USER_HEADER, CustomRealm.KNOWN_USER) .put(ThreadContext.PREFIX + "." + CustomRealm.USER_HEADER, CustomRealm.KNOWN_USER)
.put(ThreadContext.PREFIX + "." + CustomRealm.PW_HEADER, CustomRealm.KNOWN_PW) .put(ThreadContext.PREFIX + "." + CustomRealm.PW_HEADER, CustomRealm.KNOWN_PW.toString())
.put(NetworkModule.TRANSPORT_TYPE_KEY, "security4") .put(NetworkModule.TRANSPORT_TYPE_KEY, "security4")
.build(); .build();
} }
@ -78,7 +78,7 @@ public class CustomRealmIT extends ESIntegTestCase {
.put("cluster.name", clusterName) .put("cluster.name", clusterName)
.put(Environment.PATH_HOME_SETTING.getKey(), createTempDir().toAbsolutePath().toString()) .put(Environment.PATH_HOME_SETTING.getKey(), createTempDir().toAbsolutePath().toString())
.put(ThreadContext.PREFIX + "." + CustomRealm.USER_HEADER, CustomRealm.KNOWN_USER) .put(ThreadContext.PREFIX + "." + CustomRealm.USER_HEADER, CustomRealm.KNOWN_USER)
.put(ThreadContext.PREFIX + "." + CustomRealm.PW_HEADER, CustomRealm.KNOWN_PW) .put(ThreadContext.PREFIX + "." + CustomRealm.PW_HEADER, CustomRealm.KNOWN_PW.toString())
.build(); .build();
try (TransportClient client = new PreBuiltXPackTransportClient(settings)) { try (TransportClient client = new PreBuiltXPackTransportClient(settings)) {
client.addTransportAddress(publishAddress); client.addTransportAddress(publishAddress);
@ -98,7 +98,7 @@ public class CustomRealmIT extends ESIntegTestCase {
.put("cluster.name", clusterName) .put("cluster.name", clusterName)
.put(Environment.PATH_HOME_SETTING.getKey(), createTempDir().toAbsolutePath().toString()) .put(Environment.PATH_HOME_SETTING.getKey(), createTempDir().toAbsolutePath().toString())
.put(ThreadContext.PREFIX + "." + CustomRealm.USER_HEADER, CustomRealm.KNOWN_USER + randomAlphaOfLength(1)) .put(ThreadContext.PREFIX + "." + CustomRealm.USER_HEADER, CustomRealm.KNOWN_USER + randomAlphaOfLength(1))
.put(ThreadContext.PREFIX + "." + CustomRealm.PW_HEADER, CustomRealm.KNOWN_PW) .put(ThreadContext.PREFIX + "." + CustomRealm.PW_HEADER, CustomRealm.KNOWN_PW.toString())
.build(); .build();
try (TransportClient client = new PreBuiltXPackTransportClient(settings)) { try (TransportClient client = new PreBuiltXPackTransportClient(settings)) {
client.addTransportAddress(publishAddress); client.addTransportAddress(publishAddress);

View File

@ -40,7 +40,7 @@ public class CustomRolesProviderIT extends ESIntegTestCase {
protected Settings externalClusterClientSettings() { protected Settings externalClusterClientSettings() {
return Settings.builder() return Settings.builder()
.put(ThreadContext.PREFIX + "." + CustomRealm.USER_HEADER, CustomRealm.KNOWN_USER) .put(ThreadContext.PREFIX + "." + CustomRealm.USER_HEADER, CustomRealm.KNOWN_USER)
.put(ThreadContext.PREFIX + "." + CustomRealm.PW_HEADER, CustomRealm.KNOWN_PW) .put(ThreadContext.PREFIX + "." + CustomRealm.PW_HEADER, CustomRealm.KNOWN_PW.toString())
.put(NetworkModule.TRANSPORT_TYPE_KEY, "security4") .put(NetworkModule.TRANSPORT_TYPE_KEY, "security4")
.build(); .build();
} }

View File

@ -5,6 +5,7 @@
*/ */
package org.elasticsearch.test; package org.elasticsearch.test;
import org.elasticsearch.Build;
import org.elasticsearch.common.bytes.BytesArray; import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.TransportAddress; import org.elasticsearch.common.transport.TransportAddress;
@ -101,6 +102,7 @@ public class LicensingTribeIT extends ESIntegTestCase {
} }
public void testLicensePropagateToTribeNode() throws Exception { public void testLicensePropagateToTribeNode() throws Exception {
assumeTrue("License is only valid when tested against snapshot/test keys", Build.CURRENT.isSnapshot());
// test that auto-generated trial license propagates to tribe // test that auto-generated trial license propagates to tribe
assertBusy(() -> { assertBusy(() -> {
GetLicenseResponse getLicenseResponse = new LicensingClient(tribeNode.client()).prepareGetLicense().get(); GetLicenseResponse getLicenseResponse = new LicensingClient(tribeNode.client()).prepareGetLicense().get();