From 3a396027f669803e1a3143237578973fb1ab20d0 Mon Sep 17 00:00:00 2001 From: Chris Roberson Date: Fri, 20 Mar 2020 14:02:15 -0400 Subject: [PATCH 01/31] [Monitoring] Migrate server to NP (#56675) * First pass * First pass * Add new routes * Getting closer * Remove legacy server code, and other fixes * Register the plugin with xpack * Pass a legacy client to telemetry * Suport callWithInternalUser * Remove this * More NP work * Fix some tests * Fix broken test * Move over new telemetry changes, and fix other issues * Fix TODO item * Reuse the same schema as elasticsearch module * Use a singular config definition here * Disable this for now * Use the right method * Use custom config again * Tweak the config to make this optional * Remove these * Remove these unnecessary files * Fix jest test * Fix some linting issues * Fix type issue * Fix localization issues * Use the elasticsearch config * Remove todos * Fix this check * Move kibana alerting over * PR feedback * Use new metrics core service * Change config for xpack_api_polling_frequency_millis * Make sure this is disabled for now * Disable both * Update this to the new function * Tighten up legacy api needs * Check for existence * Fix jest tests * Cleaning up the plugin definition * Create custom type in our plugin * Revert this change * Fix CI issues * Add these tests back * Just use a different collector type * Handle errors better * Use custom type * PR feedback * Fix type issues * PR feedback --- .../telemetry/server/collection_manager.ts | 12 +- src/legacy/server/status/constants.js | 2 +- x-pack/.i18nrc.json | 2 +- x-pack/legacy/plugins/monitoring/config.js | 8 +- x-pack/legacy/plugins/monitoring/index.js | 59 +++ x-pack/legacy/plugins/monitoring/index.ts | 141 ------- .../public/views/cluster/listing/index.js | 1 + .../server/__tests__/check_license.js | 87 ---- .../es_client/__tests__/fixture_read_file.txt | 1 - .../es_client/__tests__/instantiate_client.js | 145 ------- .../parse_elasticsearch_config.test.mocks.ts | 15 - .../parse_elasticsearch_config.test.ts | 181 --------- .../es_client/parse_elasticsearch_config.ts | 114 ------ .../server/init_monitoring_xpack_info.js | 44 -- .../collectors/get_ops_stats_collector.js | 95 ----- .../ops_buffer/__tests__/event_roller.js | 124 ------ .../ops_buffer/__tests__/map_requests.js | 43 -- .../__tests__/map_response_times.js | 57 --- .../collectors/ops_buffer/event_roller.js | 87 ---- .../collectors/ops_buffer/map_requests.js | 19 - .../ops_buffer/map_response_times.js | 25 -- .../collectors/ops_buffer/ops_buffer.js | 55 --- .../lib/get_kibana_info_for_stats.js | 33 -- .../shards/__tests__/fixtures/index.js | 10 - .../plugins/monitoring/server/plugin.js | 189 --------- .../register_monitoring_collection.ts | 21 - .../server/routes/api/v1/settings.js | 22 +- x-pack/plugins/infra/server/index.ts | 4 +- .../__tests__/format_timestamp_to_duration.js | 128 ++++++ .../monitoring/common/cancel_promise.ts | 70 ++++ x-pack/plugins/monitoring/common/constants.ts | 264 ++++++++++++ .../common/format_timestamp_to_duration.js | 54 +++ .../plugins/monitoring/common/formatting.js | 33 ++ .../monitoring/common}/index.js | 2 +- x-pack/plugins/monitoring/kibana.json | 10 + .../server}/__tests__/deprecations.js | 37 +- .../server/alerts/license_expiration.test.ts | 85 ++-- .../server/alerts/license_expiration.ts | 18 +- .../monitoring/server/alerts/types.d.ts | 2 +- .../monitoring/server/cloud/__tests__/aws.js | 0 .../server/cloud/__tests__/azure.js | 0 .../server/cloud/__tests__/cloud_detector.js | 0 .../server/cloud/__tests__/cloud_response.js | 0 .../server/cloud/__tests__/cloud_service.js | 0 .../server/cloud/__tests__/cloud_services.js | 0 .../monitoring/server/cloud/__tests__/gcp.js | 0 .../plugins/monitoring/server/cloud/aws.js | 0 .../plugins/monitoring/server/cloud/azure.js | 0 .../monitoring/server/cloud/cloud_detector.js | 0 .../monitoring/server/cloud/cloud_response.js | 0 .../monitoring/server/cloud/cloud_service.js | 0 .../monitoring/server/cloud/cloud_services.js | 0 .../plugins/monitoring/server/cloud/gcp.js | 0 .../plugins/monitoring/server/cloud/index.js | 0 .../__tests__/alerts_cluster_search.js | 1 + .../__tests__/alerts_clusters_aggregation.js | 0 .../cluster_alerts/__tests__/check_license.js | 0 .../__tests__/fixtures/create_stubs.js | 27 +- .../__tests__/verify_monitoring_license.js | 0 .../cluster_alerts/alerts_cluster_search.js | 0 .../alerts_clusters_aggregation.js | 0 .../server/cluster_alerts/check_license.js | 0 .../verify_monitoring_license.js | 7 +- x-pack/plugins/monitoring/server/config.ts | 230 +++++++++++ .../monitoring/server/deprecations.ts} | 49 +-- .../monitoring/server/es_client/README.md | 0 .../es_client/__tests__/instantiate_client.js | 125 ++++++ .../server/es_client/instantiate_client.ts} | 25 +- x-pack/plugins/monitoring/server/index.ts | 17 + .../__tests__/bulk_uploader.js | 0 .../server/kibana_monitoring/bulk_uploader.js | 63 ++- .../__tests__/check_for_email_value.js | 0 .../__tests__/get_default_admin_email.js | 0 .../collectors/get_kibana_usage_collector.ts} | 16 +- .../collectors/get_ops_stats_collector.ts | 37 ++ .../collectors/get_settings_collector.ts} | 27 +- .../kibana_monitoring/collectors/index.ts} | 17 +- .../server/kibana_monitoring/index.js | 0 .../server/kibana_monitoring/init.js | 2 +- .../server/kibana_monitoring/lib/index.js | 1 - .../kibana_monitoring/lib/monitoring_bulk.js | 0 .../lib/send_bulk_payload.js | 4 +- .../server/lib/__tests__/calculate_auto.js | 0 .../lib/__tests__/calculate_availabiilty.js | 0 .../lib/__tests__/calculate_overall_status.js | 0 .../server/lib/__tests__/calculate_rate.js | 0 .../calculate_timeseries_interval.js | 0 .../server/lib/__tests__/ccs_utils.js | 19 +- .../server/lib/__tests__/create_query.js | 0 .../server/lib/__tests__/helpers.js | 0 .../lib/__tests__/process_version_string.js | 0 .../lib/alerts/fetch_available_ccs.test.ts | 0 .../server/lib/alerts/fetch_available_ccs.ts | 0 .../server/lib/alerts/fetch_clusters.test.ts | 0 .../server/lib/alerts/fetch_clusters.ts | 0 .../fetch_default_email_address.test.ts | 2 +- .../lib/alerts/fetch_default_email_address.ts | 0 .../server/lib/alerts/fetch_licenses.test.ts | 0 .../server/lib/alerts/fetch_licenses.ts | 0 .../server/lib/alerts/fetch_status.ts | 0 .../lib/alerts/get_ccs_index_pattern.test.ts | 0 .../lib/alerts/get_ccs_index_pattern.ts | 0 .../lib/alerts/license_expiration.lib.test.ts | 0 .../lib/alerts/license_expiration.lib.ts | 2 +- .../server/lib/apm/__tests__/get_apms.js | 0 .../monitoring/server/lib/apm/_apm_stats.js | 0 .../server/lib/apm/_get_time_of_last_event.js | 0 .../server/lib/apm/create_apm_query.js | 0 .../monitoring/server/lib/apm/get_apm_info.js | 0 .../monitoring/server/lib/apm/get_apms.js | 0 .../server/lib/apm/get_apms_for_clusters.js | 0 .../monitoring/server/lib/apm/get_stats.js | 0 .../monitoring/server/lib/apm/index.js | 0 .../lib/beats/__tests__/create_beats_query.js | 0 .../fixtures/get_listing_response.js | 178 +++++---- .../lib/beats/__tests__/get_beat_summary.js | 0 .../server/lib/beats/__tests__/get_beats.js | 0 .../beats/__tests__/get_beats_for_clusters.js | 0 .../lib/beats/__tests__/get_latest_stats.js | 0 .../server/lib/beats/__tests__/get_stats.js | 0 .../server/lib/beats/_beats_stats.js | 0 .../server/lib/beats/create_beats_query.js | 0 .../server/lib/beats/get_beat_summary.js | 0 .../monitoring/server/lib/beats/get_beats.js | 0 .../lib/beats/get_beats_for_clusters.js | 0 .../server/lib/beats/get_latest_stats.js | 0 .../monitoring/server/lib/beats/get_stats.js | 0 .../monitoring/server/lib/beats/index.js | 0 .../monitoring/server/lib/calculate_auto.js | 0 .../server/lib/calculate_availability.js | 0 .../server/lib/calculate_overall_status.js | 0 .../monitoring/server/lib/calculate_rate.js | 0 .../lib/calculate_timeseries_interval.js | 0 .../monitoring/server/lib/ccs_utils.js | 10 +- .../get_clusters_summary.test.js.snap | 0 .../cluster/__test__/fixtures/clusters.json | 0 .../__test__/get_clusters_summary.test.js | 0 .../__tests__/flag_supported_clusters.js | 0 .../cluster/__tests__/get_cluster_status.js | 0 .../cluster/__tests__/get_clusters_state.js | 0 .../cluster/__tests__/get_clusters_stats.js | 0 .../lib/cluster/flag_supported_clusters.js | 4 +- .../server/lib/cluster/get_cluster_license.js | 0 .../server/lib/cluster/get_cluster_stats.js | 0 .../server/lib/cluster/get_cluster_status.js | 0 .../lib/cluster/get_clusters_from_request.js | 0 .../server/lib/cluster/get_clusters_state.js | 0 .../server/lib/cluster/get_clusters_stats.js | 0 .../lib/cluster/get_clusters_summary.js | 0 .../server/lib/cluster/get_index_patterns.js | 0 .../server/lib/cluster/is_in_code_path.js | 0 .../monitoring/server/lib/create_query.js | 0 .../__snapshots__/get_metrics.test.js.snap | 0 .../fixtures/agg_metrics_buckets.json | 0 .../fixtures/deriv_metrics_buckets.json | 0 .../fixtures/non_deriv_metrics_buckets.json | 0 .../lib/details/__test__/get_metrics.test.js | 0 .../server/lib/details/get_metrics.js | 0 .../server/lib/details/get_series.js | 0 .../__tests__/get_last_recovery.js | 0 .../elasticsearch/__tests__/get_ml_jobs.js | 0 .../server/lib/elasticsearch/ccr.js | 0 .../lib/elasticsearch/convert_metric_names.js | 0 .../lib/elasticsearch/get_last_recovery.js | 4 +- .../server/lib/elasticsearch/get_ml_jobs.js | 0 .../server/lib/elasticsearch/index.js | 0 .../indices/__tests__/get_index_summary.js | 0 .../indices/__tests__/get_indices.js | 0 .../indices/get_index_summary.js | 0 .../lib/elasticsearch/indices/get_indices.js | 0 .../server/lib/elasticsearch/indices/index.js | 0 .../nodes/__tests__/calculate_node_type.js | 0 .../nodes/__tests__/get_node_summary.js | 0 .../__tests__/get_node_type_class_label.js | 0 .../elasticsearch/nodes/__tests__/lookups.js | 0 .../nodes/calculate_node_type.js | 0 .../nodes/get_default_node_from_id.js | 0 .../elasticsearch/nodes/get_node_summary.js | 0 .../nodes/get_node_type_class_label.js | 0 .../get_metric_aggs.test.js.snap | 0 .../handle_response.test.js.snap | 0 .../__snapshots__/map_nodes_info.test.js.snap | 0 .../map_nodes_metrics.test.js.snap | 0 .../__test__/fixtures/cluster_data.json | 0 .../__test__/get_metric_aggs.test.js | 0 .../get_nodes/__test__/get_node_ids.test.js | 2 +- .../__test__/get_paginated_nodes.test.js | 0 .../__test__/handle_response.test.js | 0 .../get_nodes/__test__/map_nodes_info.test.js | 0 .../__test__/map_nodes_metrics.test.js | 0 .../nodes/get_nodes/get_live_nodes.js | 0 .../nodes/get_nodes/get_metric_aggs.js | 0 .../nodes/get_nodes/get_node_ids.js | 0 .../nodes/get_nodes/get_nodes.js | 0 .../nodes/get_nodes/get_paginated_nodes.js | 0 .../nodes/get_nodes/handle_response.js | 0 .../elasticsearch/nodes/get_nodes/index.js | 0 .../nodes/get_nodes/map_nodes_info.js | 0 .../nodes/get_nodes/map_nodes_metrics.js | 0 .../nodes/get_nodes/nodes_listing_metrics.js | 0 .../nodes/get_nodes/sort_nodes.js | 2 +- .../server/lib/elasticsearch/nodes/index.js | 0 .../server/lib/elasticsearch/nodes/lookups.js | 0 .../shards/__tests__/fixtures/cluster.json | 0 .../shards/__tests__/fixtures/index.js | 10 + .../__tests__/fixtures/shard_stats.json | 0 .../shards/__tests__/get_shard_stats.js | 0 .../__tests__/normalize_shard_objects.js | 0 .../calculate_shard_stat_indices_totals.js | 0 .../get_indices_unassigned_shard_stats.js | 0 ...get_indices_unassigned_shard_stats.test.js | 0 .../shards/get_nodes_shard_count.js | 0 .../shards/get_nodes_shard_count.test.js | 0 .../shards/get_shard_allocation.js | 0 .../shards/get_shard_allocation.test.js | 0 .../shards/get_shard_stat_aggs.js | 0 .../elasticsearch/shards/get_shard_stats.js | 0 .../shards/get_unassigned_shards.js | 0 .../server/lib/elasticsearch/shards/index.js | 0 .../shards/normalize_shard_objects.js | 0 .../elasticsearch/verify_ccs_availability.js | 0 .../elasticsearch/verify_monitoring_auth.js | 4 +- .../__tests__/cluster.js | 0 .../__tests__/find_reason.js | 0 .../elasticsearch_settings/__tests__/nodes.js | 0 .../lib/elasticsearch_settings/cluster.js | 0 .../lib/elasticsearch_settings/find_reason.js | 0 .../lib/elasticsearch_settings/index.js | 0 .../lib/elasticsearch_settings/nodes.js | 0 .../set/collection_disabled.js | 0 .../set/collection_enabled.js | 0 .../set/collection_interval.js | 0 .../server/lib/error_missing_required.js | 0 .../lib/errors/__tests__/auth_errors.js | 0 .../lib/errors/__tests__/known_errors.js | 0 .../server/lib/errors/auth_errors.js | 0 .../server/lib/errors/custom_errors.js | 0 .../server/lib/errors/handle_error.js | 3 +- .../lib/errors/handle_settings_error.js | 0 .../monitoring/server/lib/errors/index.js | 0 .../server/lib/errors/known_errors.js | 0 .../server/lib/filter_partial_buckets.js | 0 .../monitoring/server/lib/format_timezone.js | 0 .../monitoring/server/lib/get_timezone.js | 0 .../lib/kibana/__tests__/get_kibana_info.js | 0 .../server/lib/kibana/get_kibana_info.js | 0 .../server/lib/kibana/get_kibanas.js | 0 .../lib/kibana/get_kibanas_for_clusters.js | 0 .../monitoring/server/lib/kibana/index.js | 0 .../server/lib/logs/detect_reason.js | 0 .../lib/logs/detect_reason_from_exception.js | 0 .../server/lib/logs/get_log_types.js | 0 .../monitoring/server/lib/logs/get_logs.js | 0 .../monitoring/server/lib/logs/index.js | 0 .../server/lib/logs/init_infra_source.ts} | 11 +- .../lib/logstash/__tests__/get_node_info.js | 0 .../lib/logstash/__tests__/get_pipeline.js | 0 .../server/lib/logstash/get_cluster_status.js | 0 .../lib/logstash/get_logstash_for_clusters.js | 0 .../server/lib/logstash/get_node_info.js | 0 .../server/lib/logstash/get_nodes.js | 0 .../lib/logstash/get_paginated_pipelines.js | 0 .../server/lib/logstash/get_pipeline.js | 0 .../server/lib/logstash/get_pipeline_ids.js | 0 .../logstash/get_pipeline_state_document.js | 0 .../get_pipeline_stats_aggregation.js | 0 .../lib/logstash/get_pipeline_versions.js | 0 .../lib/logstash/get_pipeline_vertex.js | 0 .../get_pipeline_vertex_stats_aggregation.js | 0 .../monitoring/server/lib/logstash/index.js | 0 .../server/lib/logstash/sort_pipelines.js | 0 .../__snapshots__/metrics.test.js.snap | 0 .../lib/metrics/__test__/metrics.test.js | 0 .../server/lib/metrics/apm/classes.js | 0 .../server/lib/metrics/apm/metrics.js | 0 .../cpu_utilization_calculation.test.js | 0 .../server/lib/metrics/beats/classes.js | 0 .../server/lib/metrics/beats/metrics.js | 0 .../latency_metric_calculation.test.js | 0 .../__test__/quota_metric_calculation.test.js | 0 .../lib/metrics/classes/cluster_metric.js | 0 .../server/lib/metrics/classes/index.js | 0 .../server/lib/metrics/classes/metric.js | 0 .../lib/metrics/classes/quota_metric.js | 0 .../__test__/latency_calculation.test.js | 0 .../lib/metrics/elasticsearch/classes.js | 0 .../lib/metrics/elasticsearch/metrics.js | 0 .../monitoring/server/lib/metrics/index.js | 0 .../server/lib/metrics/kibana/classes.js | 0 .../server/lib/metrics/kibana/metrics.js | 0 .../server/lib/metrics/logstash/classes.js | 0 .../server/lib/metrics/logstash/metrics.js | 0 .../monitoring/server/lib/metrics/metrics.js | 0 .../server/lib/normalize_version_string.js | 0 .../server/lib/pagination/filter.js | 0 .../server/lib/pagination/paginate.js | 0 .../__test__/get_collection_status.test.js | 0 .../setup/collection/get_collection_status.js | 8 +- .../server/lib/setup/collection/index.js | 0 .../get_standalone_cluster_definition.js | 0 .../has_standalone_clusters.js | 0 .../server/lib/standalone_clusters/index.js | 0 .../standalone_cluster_query_filter.js | 0 .../monitoring/server/license_service.ts | 59 +++ x-pack/plugins/monitoring/server/plugin.ts | 378 ++++++++++++++++++ .../server/routes/api/v1/alerts/alerts.js | 8 +- .../server/routes/api/v1/alerts/index.js | 0 .../routes/api/v1/alerts/legacy_alerts.js | 18 +- .../api/v1/apm/_get_apm_cluster_status.js | 0 .../server/routes/api/v1/apm/index.js | 0 .../server/routes/api/v1/apm/instance.js | 20 +- .../server/routes/api/v1/apm/instances.js | 18 +- .../routes/api/v1/apm/metric_set_instance.js | 0 .../routes/api/v1/apm/metric_set_overview.js | 0 .../server/routes/api/v1/apm/overview.js | 18 +- .../server/routes/api/v1/beats/beat_detail.js | 20 +- .../server/routes/api/v1/beats/beats.js | 18 +- .../server/routes/api/v1/beats/index.js | 0 .../routes/api/v1/beats/metric_set_detail.js | 0 .../api/v1/beats/metric_set_overview.js | 0 .../server/routes/api/v1/beats/overview.js | 18 +- .../api/v1/check_access/check_access.js | 0 .../routes/api/v1/check_access/index.js | 0 .../server/routes/api/v1/cluster/cluster.js | 24 +- .../server/routes/api/v1/cluster/clusters.js | 18 +- .../server/routes/api/v1/cluster/index.js | 0 .../server/routes/api/v1/elasticsearch/ccr.js | 18 +- .../routes/api/v1/elasticsearch/ccr_shard.js | 22 +- .../routes/api/v1/elasticsearch/index.js | 0 .../api/v1/elasticsearch/index_detail.js | 24 +- .../routes/api/v1/elasticsearch/indices.js | 22 +- .../elasticsearch/metric_set_index_detail.js | 0 .../elasticsearch/metric_set_node_detail.js | 0 .../v1/elasticsearch/metric_set_overview.js | 0 .../routes/api/v1/elasticsearch/ml_jobs.js | 18 +- .../api/v1/elasticsearch/node_detail.js | 24 +- .../routes/api/v1/elasticsearch/nodes.js | 39 +- .../routes/api/v1/elasticsearch/overview.js | 18 +- .../elasticsearch_settings/check/cluster.js | 0 .../v1/elasticsearch_settings/check/nodes.js | 0 .../api/v1/elasticsearch_settings/index.js | 0 .../set/collection_enabled.js | 0 .../set/collection_interval.js | 0 .../v1/kibana/_get_kibana_cluster_status.js | 0 .../server/routes/api/v1/kibana/index.js | 0 .../server/routes/api/v1/kibana/instance.js | 20 +- .../server/routes/api/v1/kibana/instances.js | 18 +- .../api/v1/kibana/metric_set_instance.js | 0 .../api/v1/kibana/metric_set_overview.js | 0 .../server/routes/api/v1/kibana/overview.js | 18 +- .../server/routes/api/v1/logstash/index.js | 0 .../routes/api/v1/logstash/metric_set_node.js | 0 .../api/v1/logstash/metric_set_overview.js | 0 .../server/routes/api/v1/logstash/node.js | 22 +- .../server/routes/api/v1/logstash/nodes.js | 18 +- .../server/routes/api/v1/logstash/overview.js | 18 +- .../server/routes/api/v1/logstash/pipeline.js | 16 +- .../pipelines/cluster_pipeline_ids.js | 18 +- .../logstash/pipelines/cluster_pipelines.js | 41 +- .../v1/logstash/pipelines/node_pipelines.js | 43 +- .../api/v1/setup/cluster_setup_status.js | 26 +- ...sable_elasticsearch_internal_collection.js | 6 +- .../server/routes/api/v1/setup/index.js | 0 .../routes/api/v1/setup/node_setup_status.js | 28 +- .../monitoring/server/routes/api/v1/ui.js | 0 .../plugins/monitoring/server/routes/index.js | 0 .../fixtures/beats_stats_results.json | 0 .../telemetry_collection/create_query.test.ts | 0 .../telemetry_collection/create_query.ts | 0 .../get_all_stats.test.ts | 0 .../telemetry_collection/get_all_stats.ts | 0 .../get_beats_stats.test.ts | 0 .../telemetry_collection/get_beats_stats.ts | 0 .../get_cluster_uuids.test.ts | 0 .../telemetry_collection/get_cluster_uuids.ts | 4 +- .../telemetry_collection/get_es_stats.test.ts | 0 .../telemetry_collection/get_es_stats.ts | 0 .../get_high_level_stats.test.ts | 0 .../get_high_level_stats.ts | 0 .../get_kibana_stats.test.ts | 0 .../telemetry_collection/get_kibana_stats.ts | 0 .../telemetry_collection/get_licenses.test.ts | 0 .../telemetry_collection/get_licenses.ts | 0 .../server/telemetry_collection/index.ts | 0 .../register_monitoring_collection.ts | 33 ++ x-pack/plugins/monitoring/server/types.ts | 21 + .../apis/monitoring/common/mappings_exist.js | 10 +- 387 files changed, 2234 insertions(+), 2134 deletions(-) create mode 100644 x-pack/legacy/plugins/monitoring/index.js delete mode 100644 x-pack/legacy/plugins/monitoring/index.ts delete mode 100644 x-pack/legacy/plugins/monitoring/server/__tests__/check_license.js delete mode 100644 x-pack/legacy/plugins/monitoring/server/es_client/__tests__/fixture_read_file.txt delete mode 100644 x-pack/legacy/plugins/monitoring/server/es_client/__tests__/instantiate_client.js delete mode 100644 x-pack/legacy/plugins/monitoring/server/es_client/parse_elasticsearch_config.test.mocks.ts delete mode 100644 x-pack/legacy/plugins/monitoring/server/es_client/parse_elasticsearch_config.test.ts delete mode 100644 x-pack/legacy/plugins/monitoring/server/es_client/parse_elasticsearch_config.ts delete mode 100644 x-pack/legacy/plugins/monitoring/server/init_monitoring_xpack_info.js delete mode 100644 x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/get_ops_stats_collector.js delete mode 100644 x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/ops_buffer/__tests__/event_roller.js delete mode 100644 x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/ops_buffer/__tests__/map_requests.js delete mode 100644 x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/ops_buffer/__tests__/map_response_times.js delete mode 100644 x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/ops_buffer/event_roller.js delete mode 100644 x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/ops_buffer/map_requests.js delete mode 100644 x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/ops_buffer/map_response_times.js delete mode 100644 x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/ops_buffer/ops_buffer.js delete mode 100644 x-pack/legacy/plugins/monitoring/server/kibana_monitoring/lib/get_kibana_info_for_stats.js delete mode 100644 x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/shards/__tests__/fixtures/index.js delete mode 100644 x-pack/legacy/plugins/monitoring/server/plugin.js delete mode 100644 x-pack/legacy/plugins/monitoring/server/telemetry_collection/register_monitoring_collection.ts create mode 100644 x-pack/plugins/monitoring/common/__tests__/format_timestamp_to_duration.js create mode 100644 x-pack/plugins/monitoring/common/cancel_promise.ts create mode 100644 x-pack/plugins/monitoring/common/constants.ts create mode 100644 x-pack/plugins/monitoring/common/format_timestamp_to_duration.js create mode 100644 x-pack/plugins/monitoring/common/formatting.js rename x-pack/{legacy/plugins/monitoring/server/kibana_monitoring/collectors/ops_buffer => plugins/monitoring/common}/index.js (76%) create mode 100644 x-pack/plugins/monitoring/kibana.json rename x-pack/{legacy/plugins/monitoring => plugins/monitoring/server}/__tests__/deprecations.js (75%) rename x-pack/{legacy => }/plugins/monitoring/server/alerts/license_expiration.test.ts (89%) rename x-pack/{legacy => }/plugins/monitoring/server/alerts/license_expiration.ts (91%) rename x-pack/{legacy => }/plugins/monitoring/server/alerts/types.d.ts (92%) rename x-pack/{legacy => }/plugins/monitoring/server/cloud/__tests__/aws.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/cloud/__tests__/azure.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/cloud/__tests__/cloud_detector.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/cloud/__tests__/cloud_response.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/cloud/__tests__/cloud_service.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/cloud/__tests__/cloud_services.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/cloud/__tests__/gcp.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/cloud/aws.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/cloud/azure.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/cloud/cloud_detector.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/cloud/cloud_response.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/cloud/cloud_service.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/cloud/cloud_services.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/cloud/gcp.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/cloud/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/cluster_alerts/__tests__/alerts_cluster_search.js (99%) rename x-pack/{legacy => }/plugins/monitoring/server/cluster_alerts/__tests__/alerts_clusters_aggregation.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/cluster_alerts/__tests__/check_license.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/cluster_alerts/__tests__/fixtures/create_stubs.js (51%) rename x-pack/{legacy => }/plugins/monitoring/server/cluster_alerts/__tests__/verify_monitoring_license.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/cluster_alerts/alerts_cluster_search.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/cluster_alerts/alerts_clusters_aggregation.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/cluster_alerts/check_license.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/cluster_alerts/verify_monitoring_license.js (88%) create mode 100644 x-pack/plugins/monitoring/server/config.ts rename x-pack/{legacy/plugins/monitoring/deprecations.js => plugins/monitoring/server/deprecations.ts} (54%) rename x-pack/{legacy => }/plugins/monitoring/server/es_client/README.md (100%) create mode 100644 x-pack/plugins/monitoring/server/es_client/__tests__/instantiate_client.js rename x-pack/{legacy/plugins/monitoring/server/es_client/instantiate_client.js => plugins/monitoring/server/es_client/instantiate_client.ts} (60%) create mode 100644 x-pack/plugins/monitoring/server/index.ts rename x-pack/{legacy => }/plugins/monitoring/server/kibana_monitoring/__tests__/bulk_uploader.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/kibana_monitoring/bulk_uploader.js (82%) rename x-pack/{legacy => }/plugins/monitoring/server/kibana_monitoring/collectors/__tests__/check_for_email_value.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/kibana_monitoring/collectors/__tests__/get_default_admin_email.js (100%) rename x-pack/{legacy/plugins/monitoring/server/kibana_monitoring/collectors/get_kibana_usage_collector.js => plugins/monitoring/server/kibana_monitoring/collectors/get_kibana_usage_collector.ts} (83%) create mode 100644 x-pack/plugins/monitoring/server/kibana_monitoring/collectors/get_ops_stats_collector.ts rename x-pack/{legacy/plugins/monitoring/server/kibana_monitoring/collectors/get_settings_collector.js => plugins/monitoring/server/kibana_monitoring/collectors/get_settings_collector.ts} (74%) rename x-pack/{legacy/plugins/monitoring/server/kibana_monitoring/collectors/index.js => plugins/monitoring/server/kibana_monitoring/collectors/index.ts} (66%) rename x-pack/{legacy => }/plugins/monitoring/server/kibana_monitoring/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/kibana_monitoring/init.js (91%) rename x-pack/{legacy => }/plugins/monitoring/server/kibana_monitoring/lib/index.js (83%) rename x-pack/{legacy => }/plugins/monitoring/server/kibana_monitoring/lib/monitoring_bulk.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/kibana_monitoring/lib/send_bulk_payload.js (94%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/__tests__/calculate_auto.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/__tests__/calculate_availabiilty.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/__tests__/calculate_overall_status.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/__tests__/calculate_rate.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/__tests__/calculate_timeseries_interval.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/__tests__/ccs_utils.js (79%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/__tests__/create_query.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/__tests__/helpers.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/__tests__/process_version_string.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/alerts/fetch_available_ccs.test.ts (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/alerts/fetch_available_ccs.ts (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/alerts/fetch_clusters.test.ts (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/alerts/fetch_clusters.ts (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/alerts/fetch_default_email_address.test.ts (88%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/alerts/fetch_default_email_address.ts (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/alerts/fetch_licenses.test.ts (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/alerts/fetch_licenses.ts (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/alerts/fetch_status.ts (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/alerts/get_ccs_index_pattern.test.ts (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/alerts/get_ccs_index_pattern.ts (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/alerts/license_expiration.lib.test.ts (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/alerts/license_expiration.lib.ts (96%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/apm/__tests__/get_apms.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/apm/_apm_stats.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/apm/_get_time_of_last_event.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/apm/create_apm_query.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/apm/get_apm_info.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/apm/get_apms.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/apm/get_apms_for_clusters.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/apm/get_stats.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/apm/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/beats/__tests__/create_beats_query.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/beats/__tests__/fixtures/get_listing_response.js (61%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/beats/__tests__/get_beat_summary.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/beats/__tests__/get_beats.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/beats/__tests__/get_beats_for_clusters.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/beats/__tests__/get_latest_stats.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/beats/__tests__/get_stats.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/beats/_beats_stats.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/beats/create_beats_query.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/beats/get_beat_summary.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/beats/get_beats.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/beats/get_beats_for_clusters.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/beats/get_latest_stats.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/beats/get_stats.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/beats/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/calculate_auto.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/calculate_availability.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/calculate_overall_status.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/calculate_rate.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/calculate_timeseries_interval.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/ccs_utils.js (88%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/cluster/__test__/__snapshots__/get_clusters_summary.test.js.snap (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/cluster/__test__/fixtures/clusters.json (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/cluster/__test__/get_clusters_summary.test.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/cluster/__tests__/flag_supported_clusters.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/cluster/__tests__/get_cluster_status.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/cluster/__tests__/get_clusters_state.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/cluster/__tests__/get_clusters_stats.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/cluster/flag_supported_clusters.js (96%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/cluster/get_cluster_license.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/cluster/get_cluster_stats.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/cluster/get_cluster_status.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/cluster/get_clusters_from_request.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/cluster/get_clusters_state.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/cluster/get_clusters_stats.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/cluster/get_clusters_summary.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/cluster/get_index_patterns.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/cluster/is_in_code_path.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/create_query.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/details/__test__/__snapshots__/get_metrics.test.js.snap (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/details/__test__/fixtures/agg_metrics_buckets.json (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/details/__test__/fixtures/deriv_metrics_buckets.json (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/details/__test__/fixtures/non_deriv_metrics_buckets.json (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/details/__test__/get_metrics.test.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/details/get_metrics.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/details/get_series.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/__tests__/get_last_recovery.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/__tests__/get_ml_jobs.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/ccr.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/convert_metric_names.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/get_last_recovery.js (96%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/get_ml_jobs.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/indices/__tests__/get_index_summary.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/indices/__tests__/get_indices.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/indices/get_index_summary.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/indices/get_indices.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/indices/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/nodes/__tests__/calculate_node_type.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/nodes/__tests__/get_node_summary.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/nodes/__tests__/get_node_type_class_label.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/nodes/__tests__/lookups.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/nodes/calculate_node_type.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/nodes/get_default_node_from_id.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/nodes/get_node_summary.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/nodes/get_node_type_class_label.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/__snapshots__/get_metric_aggs.test.js.snap (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/__snapshots__/handle_response.test.js.snap (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/__snapshots__/map_nodes_info.test.js.snap (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/__snapshots__/map_nodes_metrics.test.js.snap (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/fixtures/cluster_data.json (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/get_metric_aggs.test.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/get_node_ids.test.js (93%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/get_paginated_nodes.test.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/handle_response.test.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/map_nodes_info.test.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/map_nodes_metrics.test.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_live_nodes.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_metric_aggs.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_node_ids.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_nodes.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_paginated_nodes.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/handle_response.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/map_nodes_info.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/map_nodes_metrics.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/nodes_listing_metrics.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/sort_nodes.js (93%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/nodes/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/nodes/lookups.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/shards/__tests__/fixtures/cluster.json (100%) create mode 100644 x-pack/plugins/monitoring/server/lib/elasticsearch/shards/__tests__/fixtures/index.js rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/shards/__tests__/fixtures/shard_stats.json (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/shards/__tests__/get_shard_stats.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/shards/__tests__/normalize_shard_objects.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/shards/calculate_shard_stat_indices_totals.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/shards/get_indices_unassigned_shard_stats.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/shards/get_indices_unassigned_shard_stats.test.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/shards/get_nodes_shard_count.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/shards/get_nodes_shard_count.test.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_allocation.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_allocation.test.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_stat_aggs.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_stats.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/shards/get_unassigned_shards.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/shards/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/shards/normalize_shard_objects.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/verify_ccs_availability.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch/verify_monitoring_auth.js (95%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch_settings/__tests__/cluster.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch_settings/__tests__/find_reason.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch_settings/__tests__/nodes.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch_settings/cluster.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch_settings/find_reason.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch_settings/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch_settings/nodes.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch_settings/set/collection_disabled.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch_settings/set/collection_enabled.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/elasticsearch_settings/set/collection_interval.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/error_missing_required.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/errors/__tests__/auth_errors.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/errors/__tests__/known_errors.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/errors/auth_errors.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/errors/custom_errors.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/errors/handle_error.js (91%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/errors/handle_settings_error.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/errors/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/errors/known_errors.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/filter_partial_buckets.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/format_timezone.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/get_timezone.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/kibana/__tests__/get_kibana_info.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/kibana/get_kibana_info.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/kibana/get_kibanas.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/kibana/get_kibanas_for_clusters.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/kibana/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/logs/detect_reason.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/logs/detect_reason_from_exception.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/logs/get_log_types.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/logs/get_logs.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/logs/index.js (100%) rename x-pack/{legacy/plugins/monitoring/server/lib/logs/init_infra_source.js => plugins/monitoring/server/lib/logs/init_infra_source.ts} (63%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/logstash/__tests__/get_node_info.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/logstash/__tests__/get_pipeline.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/logstash/get_cluster_status.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/logstash/get_logstash_for_clusters.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/logstash/get_node_info.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/logstash/get_nodes.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/logstash/get_paginated_pipelines.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/logstash/get_pipeline.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/logstash/get_pipeline_ids.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/logstash/get_pipeline_state_document.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/logstash/get_pipeline_stats_aggregation.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/logstash/get_pipeline_versions.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/logstash/get_pipeline_vertex.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/logstash/get_pipeline_vertex_stats_aggregation.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/logstash/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/logstash/sort_pipelines.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/metrics/__test__/__snapshots__/metrics.test.js.snap (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/metrics/__test__/metrics.test.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/metrics/apm/classes.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/metrics/apm/metrics.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/metrics/beats/__test__/cpu_utilization_calculation.test.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/metrics/beats/classes.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/metrics/beats/metrics.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/metrics/classes/__test__/latency_metric_calculation.test.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/metrics/classes/__test__/quota_metric_calculation.test.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/metrics/classes/cluster_metric.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/metrics/classes/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/metrics/classes/metric.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/metrics/classes/quota_metric.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/metrics/elasticsearch/__test__/latency_calculation.test.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/metrics/elasticsearch/classes.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/metrics/elasticsearch/metrics.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/metrics/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/metrics/kibana/classes.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/metrics/kibana/metrics.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/metrics/logstash/classes.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/metrics/logstash/metrics.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/metrics/metrics.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/normalize_version_string.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/pagination/filter.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/pagination/paginate.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/setup/collection/__test__/get_collection_status.test.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/setup/collection/get_collection_status.js (98%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/setup/collection/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/standalone_clusters/get_standalone_cluster_definition.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/standalone_clusters/has_standalone_clusters.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/standalone_clusters/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/lib/standalone_clusters/standalone_cluster_query_filter.js (100%) create mode 100644 x-pack/plugins/monitoring/server/license_service.ts create mode 100644 x-pack/plugins/monitoring/server/plugin.ts rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/alerts/alerts.js (93%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/alerts/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/alerts/legacy_alerts.js (83%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/apm/_get_apm_cluster_status.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/apm/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/apm/instance.js (81%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/apm/instances.js (80%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/apm/metric_set_instance.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/apm/metric_set_overview.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/apm/overview.js (81%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/beats/beat_detail.js (82%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/beats/beats.js (80%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/beats/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/beats/metric_set_detail.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/beats/metric_set_overview.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/beats/overview.js (82%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/check_access/check_access.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/check_access/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/cluster/cluster.js (77%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/cluster/clusters.js (85%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/cluster/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr.js (96%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr_shard.js (90%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/elasticsearch/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/elasticsearch/index_detail.js (90%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/elasticsearch/indices.js (83%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/elasticsearch/metric_set_index_detail.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/elasticsearch/metric_set_node_detail.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/elasticsearch/metric_set_overview.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/elasticsearch/ml_jobs.js (85%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/elasticsearch/node_detail.js (89%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/elasticsearch/nodes.js (79%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/elasticsearch/overview.js (88%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/elasticsearch_settings/check/cluster.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/elasticsearch_settings/check/nodes.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/elasticsearch_settings/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/elasticsearch_settings/set/collection_enabled.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/elasticsearch_settings/set/collection_interval.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/kibana/_get_kibana_cluster_status.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/kibana/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/kibana/instance.js (82%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/kibana/instances.js (82%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/kibana/metric_set_instance.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/kibana/metric_set_overview.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/kibana/overview.js (82%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/logstash/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/logstash/metric_set_node.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/logstash/metric_set_overview.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/logstash/node.js (85%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/logstash/nodes.js (83%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/logstash/overview.js (84%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/logstash/pipeline.js (88%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/logstash/pipelines/cluster_pipeline_ids.js (80%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/logstash/pipelines/cluster_pipelines.js (74%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/logstash/pipelines/node_pipelines.js (73%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/setup/cluster_setup_status.js (80%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/setup/disable_elasticsearch_internal_collection.js (91%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/setup/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/setup/node_setup_status.js (81%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/api/v1/ui.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/routes/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/server/telemetry_collection/__mocks__/fixtures/beats_stats_results.json (100%) rename x-pack/{legacy => }/plugins/monitoring/server/telemetry_collection/create_query.test.ts (100%) rename x-pack/{legacy => }/plugins/monitoring/server/telemetry_collection/create_query.ts (100%) rename x-pack/{legacy => }/plugins/monitoring/server/telemetry_collection/get_all_stats.test.ts (100%) rename x-pack/{legacy => }/plugins/monitoring/server/telemetry_collection/get_all_stats.ts (100%) rename x-pack/{legacy => }/plugins/monitoring/server/telemetry_collection/get_beats_stats.test.ts (100%) rename x-pack/{legacy => }/plugins/monitoring/server/telemetry_collection/get_beats_stats.ts (100%) rename x-pack/{legacy => }/plugins/monitoring/server/telemetry_collection/get_cluster_uuids.test.ts (100%) rename x-pack/{legacy => }/plugins/monitoring/server/telemetry_collection/get_cluster_uuids.ts (91%) rename x-pack/{legacy => }/plugins/monitoring/server/telemetry_collection/get_es_stats.test.ts (100%) rename x-pack/{legacy => }/plugins/monitoring/server/telemetry_collection/get_es_stats.ts (100%) rename x-pack/{legacy => }/plugins/monitoring/server/telemetry_collection/get_high_level_stats.test.ts (100%) rename x-pack/{legacy => }/plugins/monitoring/server/telemetry_collection/get_high_level_stats.ts (100%) rename x-pack/{legacy => }/plugins/monitoring/server/telemetry_collection/get_kibana_stats.test.ts (100%) rename x-pack/{legacy => }/plugins/monitoring/server/telemetry_collection/get_kibana_stats.ts (100%) rename x-pack/{legacy => }/plugins/monitoring/server/telemetry_collection/get_licenses.test.ts (100%) rename x-pack/{legacy => }/plugins/monitoring/server/telemetry_collection/get_licenses.ts (100%) rename x-pack/{legacy => }/plugins/monitoring/server/telemetry_collection/index.ts (100%) create mode 100644 x-pack/plugins/monitoring/server/telemetry_collection/register_monitoring_collection.ts create mode 100644 x-pack/plugins/monitoring/server/types.ts diff --git a/src/legacy/core_plugins/telemetry/server/collection_manager.ts b/src/legacy/core_plugins/telemetry/server/collection_manager.ts index 715ca56e290a2..ebac4bede85bb 100644 --- a/src/legacy/core_plugins/telemetry/server/collection_manager.ts +++ b/src/legacy/core_plugins/telemetry/server/collection_manager.ts @@ -20,6 +20,7 @@ import { encryptTelemetry } from './collectors'; import { CallCluster } from '../../elasticsearch'; import { UsageCollectionSetup } from '../../../../plugins/usage_collection/server'; +import { Cluster } from '../../elasticsearch'; import { ESLicense } from './telemetry_collection/get_local_license'; export type EncryptedStatsGetterConfig = { unencrypted: false } & { @@ -70,7 +71,7 @@ export type LicenseGetter = ( interface CollectionConfig { title: string; priority: number; - esCluster: string; + esCluster: string | Cluster; statsGetter: StatsGetter; clusterDetailsGetter: ClusterDetailsGetter; licenseGetter: LicenseGetter; @@ -79,7 +80,7 @@ interface Collection { statsGetter: StatsGetter; licenseGetter: LicenseGetter; clusterDetailsGetter: ClusterDetailsGetter; - esCluster: string; + esCluster: string | Cluster; title: string; } @@ -135,9 +136,10 @@ export class TelemetryCollectionManager { ): Promise => { const { start, end } = config; const server = config.unencrypted ? config.req.server : config.server; - const { callWithRequest, callWithInternalUser } = server.plugins.elasticsearch.getCluster( - collection.esCluster - ); + const { callWithRequest, callWithInternalUser } = + typeof collection.esCluster === 'string' + ? server.plugins.elasticsearch.getCluster(collection.esCluster) + : collection.esCluster; const callCluster = config.unencrypted ? (...args: any[]) => callWithRequest(config.req, ...args) : callWithInternalUser; diff --git a/src/legacy/server/status/constants.js b/src/legacy/server/status/constants.js index d16e46008acc8..3bb23749bae87 100644 --- a/src/legacy/server/status/constants.js +++ b/src/legacy/server/status/constants.js @@ -17,4 +17,4 @@ * under the License. */ -export const KIBANA_STATS_TYPE = 'kibana_stats'; // kibana stats per 5s intervals +export const KIBANA_STATS_TYPE = 'oss_kibana_stats'; // kibana stats per 5s intervals diff --git a/x-pack/.i18nrc.json b/x-pack/.i18nrc.json index d568e9b951d28..a8bb989f6bff3 100644 --- a/x-pack/.i18nrc.json +++ b/x-pack/.i18nrc.json @@ -28,7 +28,7 @@ "xpack.main": "legacy/plugins/xpack_main", "xpack.maps": ["plugins/maps", "legacy/plugins/maps"], "xpack.ml": ["plugins/ml", "legacy/plugins/ml"], - "xpack.monitoring": "legacy/plugins/monitoring", + "xpack.monitoring": ["plugins/monitoring", "legacy/plugins/monitoring"], "xpack.remoteClusters": "plugins/remote_clusters", "xpack.reporting": ["plugins/reporting", "legacy/plugins/reporting"], "xpack.rollupJobs": "legacy/plugins/rollup", diff --git a/x-pack/legacy/plugins/monitoring/config.js b/x-pack/legacy/plugins/monitoring/config.js index bd35d5271132d..fd4e6512c5063 100644 --- a/x-pack/legacy/plugins/monitoring/config.js +++ b/x-pack/legacy/plugins/monitoring/config.js @@ -4,8 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import { XPACK_INFO_API_DEFAULT_POLL_FREQUENCY_IN_MILLIS } from '../../server/lib/constants'; - /** * User-configurable settings for xpack.monitoring via configuration schema * @param {Object} Joi - HapiJS Joi module that allows for schema validation @@ -132,9 +130,9 @@ export const config = Joi => { email_address: Joi.string().email(), }).default(), }).default(), - xpack_api_polling_frequency_millis: Joi.number().default( - XPACK_INFO_API_DEFAULT_POLL_FREQUENCY_IN_MILLIS - ), + licensing: Joi.object({ + api_polling_frequency: Joi.number().default(30001), + }), agent: Joi.object({ interval: Joi.string() .regex(/[\d\.]+[yMwdhms]/) diff --git a/x-pack/legacy/plugins/monitoring/index.js b/x-pack/legacy/plugins/monitoring/index.js new file mode 100644 index 0000000000000..fcf704b5f65d3 --- /dev/null +++ b/x-pack/legacy/plugins/monitoring/index.js @@ -0,0 +1,59 @@ +/* + * 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. + */ + +import { get } from 'lodash'; +import { resolve } from 'path'; +import { config } from './config'; +import { getUiExports } from './ui_exports'; +import { KIBANA_ALERTING_ENABLED } from './common/constants'; +import { telemetryCollectionManager } from '../../../../src/legacy/core_plugins/telemetry/server'; + +/** + * Invokes plugin modules to instantiate the Monitoring plugin for Kibana + * @param kibana {Object} Kibana plugin instance + * @return {Object} Monitoring UI Kibana plugin object + */ +const deps = ['kibana', 'elasticsearch', 'xpack_main']; +if (KIBANA_ALERTING_ENABLED) { + deps.push(...['alerting', 'actions']); +} +export const monitoring = kibana => { + return new kibana.Plugin({ + require: deps, + id: 'monitoring', + configPrefix: 'monitoring', + publicDir: resolve(__dirname, 'public'), + init(server) { + const serverConfig = server.config(); + const npMonitoring = server.newPlatform.setup.plugins.monitoring; + if (npMonitoring) { + const kbnServerStatus = this.kbnServer.status; + npMonitoring.registerLegacyAPI({ + telemetryCollectionManager, + getServerStatus: () => { + const status = kbnServerStatus.toJSON(); + return get(status, 'overall.state'); + }, + }); + } + + server.injectUiAppVars('monitoring', () => { + return { + maxBucketSize: serverConfig.get('monitoring.ui.max_bucket_size'), + minIntervalSeconds: serverConfig.get('monitoring.ui.min_interval_seconds'), + kbnIndex: serverConfig.get('kibana.index'), + showLicenseExpiration: serverConfig.get('monitoring.ui.show_license_expiration'), + showCgroupMetricsElasticsearch: serverConfig.get( + 'monitoring.ui.container.elasticsearch.enabled' + ), + showCgroupMetricsLogstash: serverConfig.get('monitoring.ui.container.logstash.enabled'), // Note, not currently used, but see https://github.com/elastic/x-pack-kibana/issues/1559 part 2 + }; + }); + }, + config, + uiExports: getUiExports(), + }); +}; diff --git a/x-pack/legacy/plugins/monitoring/index.ts b/x-pack/legacy/plugins/monitoring/index.ts deleted file mode 100644 index 3a23140104e16..0000000000000 --- a/x-pack/legacy/plugins/monitoring/index.ts +++ /dev/null @@ -1,141 +0,0 @@ -/* - * 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. - */ - -import { resolve } from 'path'; -import KbnServer, { Server } from 'src/legacy/server/kbn_server'; -import { - LegacyPluginApi, - LegacyPluginSpec, - LegacyPluginOptions, -} from 'src/legacy/plugin_discovery/types'; -import { KIBANA_ALERTING_ENABLED } from './common/constants'; - -// @ts-ignore -import { getUiExports } from './ui_exports'; -// @ts-ignore -import { config as configDefaults } from './config'; -// @ts-ignore -import { deprecations } from './deprecations'; -// @ts-ignore -import { Plugin } from './server/plugin'; -// @ts-ignore -import { initInfraSource } from './server/lib/logs/init_infra_source'; - -type InfraPlugin = any; // TODO -type PluginsSetup = any; // TODO -type LegacySetup = any; // TODO - -const deps = ['kibana', 'elasticsearch', 'xpack_main']; -if (KIBANA_ALERTING_ENABLED) { - deps.push(...['alerting', 'actions']); -} - -const validConfigOptions: string[] = [ - 'monitoring.ui.enabled', - 'monitoring.kibana.collection.enabled', - 'monitoring.ui.max_bucket_size', - 'monitoring.ui.min_interval_seconds', - 'kibana.index', - 'monitoring.ui.show_license_expiration', - 'monitoring.ui.container.elasticsearch.enabled', - 'monitoring.ui.container.logstash.enabled', - 'monitoring.tests.cloud_detector.enabled', - 'monitoring.kibana.collection.interval', - 'monitoring.elasticsearch.hosts', - 'monitoring.elasticsearch', - 'monitoring.ui.elasticsearch.hosts', - 'monitoring.ui.elasticsearch', - 'monitoring.xpack_api_polling_frequency_millis', - 'server.uuid', - 'server.name', - 'server.host', - 'server.port', - 'monitoring.cluster_alerts.email_notifications.enabled', - 'monitoring.cluster_alerts.email_notifications.email_address', - 'monitoring.ui.ccs.enabled', - 'monitoring.ui.elasticsearch.logFetchCount', - 'monitoring.ui.logs.index', -]; - -interface LegacyPluginOptionsWithKbnServer extends LegacyPluginOptions { - kbnServer?: KbnServer; -} - -/** - * Invokes plugin modules to instantiate the Monitoring plugin for Kibana - * @param kibana {Object} Kibana plugin instance - * @return {Object} Monitoring UI Kibana plugin object - */ -export const monitoring = (kibana: LegacyPluginApi): LegacyPluginSpec => { - return new kibana.Plugin({ - require: deps, - id: 'monitoring', - configPrefix: 'monitoring', - publicDir: resolve(__dirname, 'public'), - config: configDefaults, - uiExports: getUiExports(), - deprecations, - - async init(server: Server) { - const serverConfig = server.config(); - const { getOSInfo, plugins, injectUiAppVars } = server as typeof server & { getOSInfo?: any }; - const log = (...args: Parameters) => server.log(...args); - const route = (...args: Parameters) => server.route(...args); - const expose = (...args: Parameters) => server.expose(...args); - const serverFacade = { - config: () => ({ - get: (key: string) => { - if (validConfigOptions.includes(key)) { - return serverConfig.get(key); - } - throw new Error(`Unknown key '${key}'`); - }, - }), - injectUiAppVars, - log, - logger: server.newPlatform.coreContext.logger, - getOSInfo, - events: { - on: (...args: Parameters) => server.events.on(...args), - }, - route, - expose, - _hapi: server, - _kbnServer: this.kbnServer, - }; - - const legacyPlugins = plugins as Partial & { infra?: InfraPlugin }; - const { xpack_main, elasticsearch, infra } = legacyPlugins; - const { - core: coreSetup, - plugins: { usageCollection, licensing, alerting }, - } = server.newPlatform.setup; - - const pluginsSetup: PluginsSetup = { - usageCollection, - licensing, - alerting, - }; - - const __LEGACY: LegacySetup = { - ...serverFacade, - plugins: { - xpack_main, - elasticsearch, - infra, - }, - }; - - const plugin = new Plugin(); - await plugin.setup(coreSetup, pluginsSetup, __LEGACY); - }, - - postInit(server: Server) { - const { infra } = server.plugins as Partial & { infra?: InfraPlugin }; - initInfraSource(server.config(), infra); - }, - } as Partial); -}; diff --git a/x-pack/legacy/plugins/monitoring/public/views/cluster/listing/index.js b/x-pack/legacy/plugins/monitoring/public/views/cluster/listing/index.js index 1c8500caa48af..958226514b146 100644 --- a/x-pack/legacy/plugins/monitoring/public/views/cluster/listing/index.js +++ b/x-pack/legacy/plugins/monitoring/public/views/cluster/listing/index.js @@ -56,6 +56,7 @@ uiRoutes const globalState = $injector.get('globalState'); const storage = $injector.get('localStorage'); const showLicenseExpiration = $injector.get('showLicenseExpiration'); + this.data = $route.current.locals.clusters; $scope.$watch( diff --git a/x-pack/legacy/plugins/monitoring/server/__tests__/check_license.js b/x-pack/legacy/plugins/monitoring/server/__tests__/check_license.js deleted file mode 100644 index 60b27cae30878..0000000000000 --- a/x-pack/legacy/plugins/monitoring/server/__tests__/check_license.js +++ /dev/null @@ -1,87 +0,0 @@ -/* - * 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. - */ - -import { BehaviorSubject } from 'rxjs'; -import expect from '@kbn/expect'; -import sinon from 'sinon'; - -import { XPackInfo } from '../../../xpack_main/server/lib/xpack_info'; -import { licensingMock } from '../../../../../plugins/licensing/server/mocks'; - -const createLicense = (type = 'basic') => { - return licensingMock.createLicense({ - license: { - uid: 'custom-uid', - type, - mode: 'basic', - status: 'active', - expiryDateInMillis: 1286575200000, - }, - features: { - monitoring: { - description: '...', - isAvailable: true, - isEnabled: true, - }, - }, - }); -}; - -describe('XPackInfo', () => { - let mockServer; - let mockElasticsearchPlugin; - - beforeEach(() => { - mockServer = sinon.stub({ - plugins: { elasticsearch: mockElasticsearchPlugin }, - events: { on() {} }, - newPlatform: { - setup: { - plugins: { - licensing: {}, - }, - }, - }, - }); - }); - - describe('refreshNow()', () => { - it('check new platform licensing plugin', async () => { - const refresh = sinon.spy(); - const license$ = new BehaviorSubject(createLicense()); - const xPackInfo = new XPackInfo(mockServer, { - licensing: { - license$, - refresh, - }, - }); - - let changed = false; - license$.subscribe(() => (changed = true)); - await xPackInfo.refreshNow(); - expect(changed).to.be(true); - sinon.assert.calledOnce(refresh); - }); - }); - - describe('Change type', () => { - it('trigger event when license type changes', async () => { - const license$ = new BehaviorSubject(createLicense()); - const refresh = () => void 0; - const xPackInfo = new XPackInfo(mockServer, { - licensing: { - license$, - refresh, - }, - }); - let changed = false; - license$.subscribe(() => (changed = true)); - await license$.next(createLicense('gold')); - expect(xPackInfo.license.getType()).to.be('gold'); - expect(changed).to.be(true); - }); - }); -}); diff --git a/x-pack/legacy/plugins/monitoring/server/es_client/__tests__/fixture_read_file.txt b/x-pack/legacy/plugins/monitoring/server/es_client/__tests__/fixture_read_file.txt deleted file mode 100644 index 0cc06add41119..0000000000000 --- a/x-pack/legacy/plugins/monitoring/server/es_client/__tests__/fixture_read_file.txt +++ /dev/null @@ -1 +0,0 @@ -another jejune test file diff --git a/x-pack/legacy/plugins/monitoring/server/es_client/__tests__/instantiate_client.js b/x-pack/legacy/plugins/monitoring/server/es_client/__tests__/instantiate_client.js deleted file mode 100644 index 88cf9734d5f57..0000000000000 --- a/x-pack/legacy/plugins/monitoring/server/es_client/__tests__/instantiate_client.js +++ /dev/null @@ -1,145 +0,0 @@ -/* - * 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. - */ - -import expect from '@kbn/expect'; -import sinon from 'sinon'; -import { noop } from 'lodash'; -import { exposeClient, hasMonitoringCluster } from '../instantiate_client'; - -function getMockServerFromConnectionUrl(monitoringClusterUrl) { - const server = { - monitoring: { - ui: { - elasticsearch: { - hosts: monitoringClusterUrl ? [monitoringClusterUrl] : [], - username: 'monitoring-user-internal-test', - password: 'monitoring-p@ssw0rd!-internal-test', - ssl: {}, - customHeaders: { - 'x-custom-headers-test': 'connection-monitoring', - }, - }, - }, - }, - }; - - return { - elasticsearchConfig: server.monitoring.ui.elasticsearch, - elasticsearchPlugin: { - getCluster: sinon - .stub() - .withArgs('admin') - .returns({ - config: sinon.stub().returns(server.elasticsearch), - }), - createCluster: sinon.stub(), - }, - events: { - on: noop, - }, - expose: sinon.stub(), - log: sinon.stub(), - }; -} - -describe('Instantiate Client', () => { - describe('Logging', () => { - it('logs that the config was sourced from the production options', () => { - const server = getMockServerFromConnectionUrl(null); // pass null for URL to create the client using prod config - - exposeClient(server); - - expect(server.log.getCall(0).args).to.eql([ - ['monitoring', 'es-client'], - 'config sourced from: production cluster', - ]); - }); - - it('logs that the config was sourced from the monitoring options', () => { - const server = getMockServerFromConnectionUrl('monitoring-cluster.test:9200'); - exposeClient(server); - - expect(server.log.getCall(0).args).to.eql([ - ['monitoring', 'es-client'], - 'config sourced from: monitoring cluster', - ]); - }); - }); - - describe('Custom Headers Configuration', () => { - it('Does not add xpack.monitoring.elasticsearch.customHeaders if connected to production cluster', () => { - const server = getMockServerFromConnectionUrl(null); // pass null for URL to create the client using prod config - - exposeClient(server); - - const createCluster = server.elasticsearchPlugin.createCluster; - const createClusterCall = createCluster.getCall(0); - - sinon.assert.calledOnce(createCluster); - expect(createClusterCall.args[0]).to.be('monitoring'); - expect(createClusterCall.args[1].customHeaders).to.eql(undefined); - }); - - it('Adds xpack.monitoring.elasticsearch.customHeaders if connected to monitoring cluster', () => { - const server = getMockServerFromConnectionUrl('http://monitoring-cluster.test:9200'); // pass null for URL to create the client using prod config - - exposeClient(server); - - const createCluster = server.elasticsearchPlugin.createCluster; - const createClusterCall = createCluster.getCall(0); - - sinon.assert.calledOnce(createCluster); - expect(createClusterCall.args[0]).to.be('monitoring'); - expect(createClusterCall.args[1].customHeaders).to.eql({ - 'x-custom-headers-test': 'connection-monitoring', - }); - }); - }); - - describe('Use a connection to production cluster', () => { - it('exposes an authenticated client using production host settings', () => { - const server = getMockServerFromConnectionUrl(null); // pass null for URL to create the client using prod config - exposeClient(server); - - const createCluster = server.elasticsearchPlugin.createCluster; - const createClusterCall = createCluster.getCall(0); - const createClientOptions = createClusterCall.args[1]; - - sinon.assert.calledOnce(createCluster); - expect(createClusterCall.args[0]).to.be('monitoring'); - expect(createClientOptions.hosts).to.eql(undefined); - }); - }); - - describe('Use a connection to monitoring cluster', () => { - it('exposes an authenticated client using monitoring host settings', () => { - const server = getMockServerFromConnectionUrl('http://monitoring-cluster.test:9200'); - exposeClient(server); - - const createCluster = server.elasticsearchPlugin.createCluster; - const createClusterCall = createCluster.getCall(0); - const createClientOptions = createClusterCall.args[1]; - - sinon.assert.calledOnce(createCluster); - expect(createClusterCall.args[0]).to.be('monitoring'); - expect(createClientOptions.hosts[0]).to.eql('http://monitoring-cluster.test:9200'); - expect(createClientOptions.username).to.eql('monitoring-user-internal-test'); - expect(createClientOptions.password).to.eql('monitoring-p@ssw0rd!-internal-test'); - }); - }); - - describe('hasMonitoringCluster', () => { - it('returns true if monitoring is configured', () => { - const server = getMockServerFromConnectionUrl('http://monitoring-cluster.test:9200'); // pass null for URL to create the client using prod config - expect(hasMonitoringCluster(server.elasticsearchConfig)).to.be(true); - }); - - it('returns false if monitoring is not configured', () => { - const server = getMockServerFromConnectionUrl(null); - expect(hasMonitoringCluster(server.elasticsearchConfig)).to.be(false); - }); - }); -}); diff --git a/x-pack/legacy/plugins/monitoring/server/es_client/parse_elasticsearch_config.test.mocks.ts b/x-pack/legacy/plugins/monitoring/server/es_client/parse_elasticsearch_config.test.mocks.ts deleted file mode 100644 index 42141313ceea2..0000000000000 --- a/x-pack/legacy/plugins/monitoring/server/es_client/parse_elasticsearch_config.test.mocks.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* - * 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. - */ - -export const mockReadFileSync = jest.fn(); -jest.mock('fs', () => ({ readFileSync: mockReadFileSync })); - -export const mockReadPkcs12Keystore = jest.fn(); -export const mockReadPkcs12Truststore = jest.fn(); -jest.mock('../../../../../../src/core/utils', () => ({ - readPkcs12Keystore: mockReadPkcs12Keystore, - readPkcs12Truststore: mockReadPkcs12Truststore, -})); diff --git a/x-pack/legacy/plugins/monitoring/server/es_client/parse_elasticsearch_config.test.ts b/x-pack/legacy/plugins/monitoring/server/es_client/parse_elasticsearch_config.test.ts deleted file mode 100644 index 8d9b5335732c0..0000000000000 --- a/x-pack/legacy/plugins/monitoring/server/es_client/parse_elasticsearch_config.test.ts +++ /dev/null @@ -1,181 +0,0 @@ -/* - * 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. - */ - -import { - mockReadFileSync, - mockReadPkcs12Keystore, - mockReadPkcs12Truststore, -} from './parse_elasticsearch_config.test.mocks'; - -import { parseElasticsearchConfig } from './parse_elasticsearch_config'; - -const parse = (config: any) => { - return parseElasticsearchConfig({ - get: () => config, - }); -}; - -describe('reads files', () => { - beforeEach(() => { - mockReadFileSync.mockReset(); - mockReadFileSync.mockImplementation((path: string) => `content-of-${path}`); - mockReadPkcs12Keystore.mockReset(); - mockReadPkcs12Keystore.mockImplementation((path: string) => ({ - key: `content-of-${path}.key`, - cert: `content-of-${path}.cert`, - ca: [`content-of-${path}.ca`], - })); - mockReadPkcs12Truststore.mockReset(); - mockReadPkcs12Truststore.mockImplementation((path: string) => [`content-of-${path}`]); - }); - - it('reads certificate authorities when ssl.keystore.path is specified', () => { - const configValue = parse({ ssl: { keystore: { path: 'some-path' } } }); - expect(mockReadPkcs12Keystore).toHaveBeenCalledTimes(1); - expect(configValue.ssl.certificateAuthorities).toEqual(['content-of-some-path.ca']); - }); - - it('reads certificate authorities when ssl.truststore.path is specified', () => { - const configValue = parse({ ssl: { truststore: { path: 'some-path' } } }); - expect(mockReadPkcs12Truststore).toHaveBeenCalledTimes(1); - expect(configValue.ssl.certificateAuthorities).toEqual(['content-of-some-path']); - }); - - it('reads certificate authorities when ssl.certificateAuthorities is specified', () => { - let configValue = parse({ ssl: { certificateAuthorities: 'some-path' } }); - expect(mockReadFileSync).toHaveBeenCalledTimes(1); - expect(configValue.ssl.certificateAuthorities).toEqual(['content-of-some-path']); - - mockReadFileSync.mockClear(); - configValue = parse({ ssl: { certificateAuthorities: ['some-path'] } }); - expect(mockReadFileSync).toHaveBeenCalledTimes(1); - expect(configValue.ssl.certificateAuthorities).toEqual(['content-of-some-path']); - - mockReadFileSync.mockClear(); - configValue = parse({ ssl: { certificateAuthorities: ['some-path', 'another-path'] } }); - expect(mockReadFileSync).toHaveBeenCalledTimes(2); - expect(configValue.ssl.certificateAuthorities).toEqual([ - 'content-of-some-path', - 'content-of-another-path', - ]); - }); - - it('reads certificate authorities when ssl.keystore.path, ssl.truststore.path, and ssl.certificateAuthorities are specified', () => { - const configValue = parse({ - ssl: { - keystore: { path: 'some-path' }, - truststore: { path: 'another-path' }, - certificateAuthorities: 'yet-another-path', - }, - }); - expect(mockReadPkcs12Keystore).toHaveBeenCalledTimes(1); - expect(mockReadPkcs12Truststore).toHaveBeenCalledTimes(1); - expect(mockReadFileSync).toHaveBeenCalledTimes(1); - expect(configValue.ssl.certificateAuthorities).toEqual([ - 'content-of-some-path.ca', - 'content-of-another-path', - 'content-of-yet-another-path', - ]); - }); - - it('reads a private key and certificate when ssl.keystore.path is specified', () => { - const configValue = parse({ ssl: { keystore: { path: 'some-path' } } }); - expect(mockReadPkcs12Keystore).toHaveBeenCalledTimes(1); - expect(configValue.ssl.key).toEqual('content-of-some-path.key'); - expect(configValue.ssl.certificate).toEqual('content-of-some-path.cert'); - }); - - it('reads a private key when ssl.key is specified', () => { - const configValue = parse({ ssl: { key: 'some-path' } }); - expect(mockReadFileSync).toHaveBeenCalledTimes(1); - expect(configValue.ssl.key).toEqual('content-of-some-path'); - }); - - it('reads a certificate when ssl.certificate is specified', () => { - const configValue = parse({ ssl: { certificate: 'some-path' } }); - expect(mockReadFileSync).toHaveBeenCalledTimes(1); - expect(configValue.ssl.certificate).toEqual('content-of-some-path'); - }); -}); - -describe('throws when config is invalid', () => { - beforeAll(() => { - const realFs = jest.requireActual('fs'); - mockReadFileSync.mockImplementation((path: string) => realFs.readFileSync(path)); - const utils = jest.requireActual('../../../../../../src/core/utils'); - mockReadPkcs12Keystore.mockImplementation((path: string, password?: string) => - utils.readPkcs12Keystore(path, password) - ); - mockReadPkcs12Truststore.mockImplementation((path: string, password?: string) => - utils.readPkcs12Truststore(path, password) - ); - }); - - it('throws if key is invalid', () => { - const value = { ssl: { key: '/invalid/key' } }; - expect(() => parse(value)).toThrowErrorMatchingInlineSnapshot( - `"ENOENT: no such file or directory, open '/invalid/key'"` - ); - }); - - it('throws if certificate is invalid', () => { - const value = { ssl: { certificate: '/invalid/cert' } }; - expect(() => parse(value)).toThrowErrorMatchingInlineSnapshot( - `"ENOENT: no such file or directory, open '/invalid/cert'"` - ); - }); - - it('throws if certificateAuthorities is invalid', () => { - const value = { ssl: { certificateAuthorities: '/invalid/ca' } }; - expect(() => parse(value)).toThrowErrorMatchingInlineSnapshot( - `"ENOENT: no such file or directory, open '/invalid/ca'"` - ); - }); - - it('throws if keystore path is invalid', () => { - const value = { ssl: { keystore: { path: '/invalid/keystore' } } }; - expect(() => parse(value)).toThrowErrorMatchingInlineSnapshot( - `"ENOENT: no such file or directory, open '/invalid/keystore'"` - ); - }); - - it('throws if keystore does not contain a key', () => { - mockReadPkcs12Keystore.mockReturnValueOnce({}); - const value = { ssl: { keystore: { path: 'some-path' } } }; - expect(() => parse(value)).toThrowErrorMatchingInlineSnapshot( - `"Did not find key in Elasticsearch keystore."` - ); - }); - - it('throws if keystore does not contain a certificate', () => { - mockReadPkcs12Keystore.mockReturnValueOnce({ key: 'foo' }); - const value = { ssl: { keystore: { path: 'some-path' } } }; - expect(() => parse(value)).toThrowErrorMatchingInlineSnapshot( - `"Did not find certificate in Elasticsearch keystore."` - ); - }); - - it('throws if truststore path is invalid', () => { - const value = { ssl: { keystore: { path: '/invalid/truststore' } } }; - expect(() => parse(value)).toThrowErrorMatchingInlineSnapshot( - `"ENOENT: no such file or directory, open '/invalid/truststore'"` - ); - }); - - it('throws if key and keystore.path are both specified', () => { - const value = { ssl: { key: 'foo', keystore: { path: 'bar' } } }; - expect(() => parse(value)).toThrowErrorMatchingInlineSnapshot( - `"[config validation of [monitoring.ui.elasticsearch].ssl]: cannot use [key] when [keystore.path] is specified"` - ); - }); - - it('throws if certificate and keystore.path are both specified', () => { - const value = { ssl: { certificate: 'foo', keystore: { path: 'bar' } } }; - expect(() => parse(value)).toThrowErrorMatchingInlineSnapshot( - `"[config validation of [monitoring.ui.elasticsearch].ssl]: cannot use [certificate] when [keystore.path] is specified"` - ); - }); -}); diff --git a/x-pack/legacy/plugins/monitoring/server/es_client/parse_elasticsearch_config.ts b/x-pack/legacy/plugins/monitoring/server/es_client/parse_elasticsearch_config.ts deleted file mode 100644 index 87b225e48c158..0000000000000 --- a/x-pack/legacy/plugins/monitoring/server/es_client/parse_elasticsearch_config.ts +++ /dev/null @@ -1,114 +0,0 @@ -/* - * 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. - */ - -import { readFileSync } from 'fs'; -import { readPkcs12Truststore, readPkcs12Keystore } from '../../../../../../src/core/utils'; - -const KEY = 'monitoring.ui.elasticsearch'; - -/* - * Parse a config object's Elasticsearch configuration, reading any - * certificates/keys from the filesystem - * - * TODO: this code can be removed when this plugin is migrated to the Kibana Platform, - * at that point the ElasticsearchClient and ElasticsearchConfig should be used instead - */ -export const parseElasticsearchConfig = (config: any, configKey: string = KEY) => { - const es = config.get(configKey); - if (!es) { - return {}; - } - - const errorPrefix = `[config validation of [${configKey}].ssl]`; - if (es.ssl?.key && es.ssl?.keystore?.path) { - throw new Error(`${errorPrefix}: cannot use [key] when [keystore.path] is specified`); - } - if (es.ssl?.certificate && es.ssl?.keystore?.path) { - throw new Error(`${errorPrefix}: cannot use [certificate] when [keystore.path] is specified`); - } - - const { alwaysPresentCertificate, verificationMode } = es.ssl; - const { key, keyPassphrase, certificate, certificateAuthorities } = readKeyAndCerts(es); - - return { - ...es, - ssl: { - alwaysPresentCertificate, - key, - keyPassphrase, - certificate, - certificateAuthorities, - verificationMode, - }, - }; -}; - -const readKeyAndCerts = (rawConfig: any) => { - let key: string | undefined; - let keyPassphrase: string | undefined; - let certificate: string | undefined; - let certificateAuthorities: string[] | undefined; - - const addCAs = (ca: string[] | undefined) => { - if (ca && ca.length) { - certificateAuthorities = [...(certificateAuthorities || []), ...ca]; - } - }; - - if (rawConfig.ssl.keystore?.path) { - const keystore = readPkcs12Keystore( - rawConfig.ssl.keystore.path, - rawConfig.ssl.keystore.password - ); - if (!keystore.key) { - throw new Error(`Did not find key in Elasticsearch keystore.`); - } else if (!keystore.cert) { - throw new Error(`Did not find certificate in Elasticsearch keystore.`); - } - key = keystore.key; - certificate = keystore.cert; - addCAs(keystore.ca); - } else { - if (rawConfig.ssl.key) { - key = readFile(rawConfig.ssl.key); - keyPassphrase = rawConfig.ssl.keyPassphrase; - } - if (rawConfig.ssl.certificate) { - certificate = readFile(rawConfig.ssl.certificate); - } - } - - if (rawConfig.ssl.truststore?.path) { - const ca = readPkcs12Truststore( - rawConfig.ssl.truststore.path, - rawConfig.ssl.truststore.password - ); - addCAs(ca); - } - - const ca = rawConfig.ssl.certificateAuthorities; - if (ca) { - const parsed: string[] = []; - const paths = Array.isArray(ca) ? ca : [ca]; - if (paths.length > 0) { - for (const path of paths) { - parsed.push(readFile(path)); - } - addCAs(parsed); - } - } - - return { - key, - keyPassphrase, - certificate, - certificateAuthorities, - }; -}; - -const readFile = (file: string) => { - return readFileSync(file, 'utf8'); -}; diff --git a/x-pack/legacy/plugins/monitoring/server/init_monitoring_xpack_info.js b/x-pack/legacy/plugins/monitoring/server/init_monitoring_xpack_info.js deleted file mode 100644 index 7a6ab37798db6..0000000000000 --- a/x-pack/legacy/plugins/monitoring/server/init_monitoring_xpack_info.js +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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. - */ - -import { checkLicenseGenerator } from './cluster_alerts/check_license'; -import { hasMonitoringCluster } from './es_client/instantiate_client'; -import { LOGGING_TAG } from '../common/constants'; -import { XPackInfo } from '../../xpack_main/server/lib/xpack_info'; - -/* - * Expose xpackInfo for the Monitoring cluster as server.plugins.monitoring.info - */ -export const initMonitoringXpackInfo = async ({ - config, - server, - client, - xpackMainPlugin, - licensing, - expose, - log, -}) => { - const xpackInfo = hasMonitoringCluster(config) - ? new XPackInfo(server, { - licensing: licensing.createLicensePoller( - client, - config.get('monitoring.xpack_api_polling_frequency_millis') - ), - }) - : xpackMainPlugin.info; - - xpackInfo.feature('monitoring').registerLicenseCheckResultsGenerator(checkLicenseGenerator); - expose('info', xpackInfo); - - // check if X-Pack is installed on Monitoring Cluster - const xpackInfoTest = await xpackInfo.refreshNow(); - if (!xpackInfoTest.isAvailable()) { - log( - [LOGGING_TAG, 'warning'], - `X-Pack Monitoring Cluster Alerts will not be available: ${xpackInfoTest.unavailableReason()}` - ); - } -}; diff --git a/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/get_ops_stats_collector.js b/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/get_ops_stats_collector.js deleted file mode 100644 index e7219fcfcaef1..0000000000000 --- a/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/get_ops_stats_collector.js +++ /dev/null @@ -1,95 +0,0 @@ -/* - * 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. - */ - -import { - LOGGING_TAG, - KIBANA_MONITORING_LOGGING_TAG, - KIBANA_STATS_TYPE_MONITORING, -} from '../../../common/constants'; -import { opsBuffer } from './ops_buffer'; -import Oppsy from 'oppsy'; -import { cloneDeep } from 'lodash'; - -let bufferHadEvents = false; - -class OpsMonitor { - constructor(hapiServer, buffer, interval) { - this._buffer = buffer; - this._interval = interval; - this._oppsy = new Oppsy(hapiServer); - this._server = hapiServer; - } - - start = () => { - this._oppsy.on('ops', event => { - // Oppsy has a bad race condition that will modify this data before - // we ship it off to the buffer. Let's create our copy first. - event = cloneDeep(event); - // Oppsy used to provide this, but doesn't anymore. Grab it ourselves. - this._server.listener.getConnections((_, count) => { - event.concurrent_connections = count; - this._buffer.push(event); - }); - }); - - this._oppsy.on('error', console.log); - this._oppsy.start(this._interval); - }; - - stop = () => { - this._oppsy.stop(); - this._oppsy.removeAllListeners(); - }; -} - -/* - * Initialize a collector for Kibana Ops Stats - */ -export function getOpsStatsCollector( - usageCollection, - { elasticsearchPlugin, kbnServerConfig, log, config, getOSInfo, hapiServer } -) { - const buffer = opsBuffer({ log, config, getOSInfo }); - const interval = kbnServerConfig.get('ops.interval'); - const opsMonitor = new OpsMonitor(hapiServer, buffer, interval); - - /* Handle stopping / restarting the event listener if Elasticsearch stops and restarts - * NOTE it is possible for the plugin status to go from red to red and - * trigger handlers twice - */ - elasticsearchPlugin.status.on('red', opsMonitor.stop); - elasticsearchPlugin.status.on('green', opsMonitor.start); - - // `process` is a NodeJS global, and is always available without using require/import - process.on('SIGHUP', () => { - log( - ['info', LOGGING_TAG, KIBANA_MONITORING_LOGGING_TAG], - 'Re-initializing Kibana Monitoring due to SIGHUP' - ); - setTimeout(() => { - opsMonitor.stop(); - opsMonitor.start(); - log( - ['info', LOGGING_TAG, KIBANA_MONITORING_LOGGING_TAG], - 'Re-initializing Kibana Monitoring due to SIGHUP' - ); - }, 5 * 1000); // wait 5 seconds to avoid race condition with reloading logging configuration - }); - - return usageCollection.makeStatsCollector({ - type: KIBANA_STATS_TYPE_MONITORING, - init: opsMonitor.start, - isReady: () => { - if (!bufferHadEvents) { - bufferHadEvents = buffer.hasEvents(); - } - return bufferHadEvents; - }, - fetch: async () => { - return await buffer.flush(); - }, - }); -} diff --git a/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/ops_buffer/__tests__/event_roller.js b/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/ops_buffer/__tests__/event_roller.js deleted file mode 100644 index b64f1a010725d..0000000000000 --- a/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/ops_buffer/__tests__/event_roller.js +++ /dev/null @@ -1,124 +0,0 @@ -/* - * 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. - */ - -import { EventRoller } from '../event_roller'; -import expect from '@kbn/expect'; - -const events = [ - { - requests: { - '5601': { - total: 103, - disconnects: 0, - statusCodes: { '200': 15, '304': 88 }, - }, - }, - responseTimes: { '5601': { avg: 5.213592233009709, max: 36 } }, - osload: [1.90380859375, 1.84033203125, 1.82666015625], - osmem: { total: 17179869184, free: 613638144 }, - osup: 4615, - psup: 62.388, - psmem: { - rss: 518164480, - heapTotal: 474275840, - heapUsed: 318428400, - external: 5172252, - }, - concurrent_connections: 6, - psdelay: 0.4091129992157221, - }, - { - requests: { - '5601': { - total: 35, - disconnects: 0, - statusCodes: { '200': 5, '304': 30 }, - }, - }, - responseTimes: { '5601': { avg: 4.6, max: 29 } }, - sockets: { - http: { total: 1, '169.254.169.254:80:': 1 }, - https: { total: 0 }, - }, - osload: [1.9111328125, 1.8427734375, 1.82763671875], - osmem: { total: 17179869184, free: 641744896 }, - osup: 4620, - psup: 67.39, - psmem: { - rss: 518193152, - heapTotal: 474275840, - heapUsed: 315669840, - external: 5083177, - }, - concurrent_connections: 6, - psdelay: 0.6715770000591874, - }, -]; - -describe('Event Roller', () => { - it('constructs an event roller object', () => { - const eventRoller = new EventRoller(); - expect(eventRoller.rollup).to.be(null); - expect(eventRoller.getFromRollup()).to.be(undefined); - expect(eventRoller.getFromRollup('concurrent_connections')).to.be(undefined); - }); - - it('adds events and rolls them up', () => { - const eventRoller = new EventRoller(); - const [event1, event2] = events; - eventRoller.addEvent(event1); - eventRoller.addEvent(event2); - - const flush = eventRoller.flush(); - // delete unpredictable fields - delete flush.timestamp; - delete flush.process.memory.heap.size_limit; - - expect(flush).to.eql({ - concurrent_connections: 12, // 6 + 6 - os: { - load: { '1m': 1.9111328125, '5m': 1.8427734375, '15m': 1.82763671875 }, // just the latest - memory: { - total_in_bytes: 17179869184, - free_in_bytes: 641744896, - used_in_bytes: 16538124288, // just the latest - }, - uptime_in_millis: 4620000, // converted from latest osup - }, - process: { - event_loop_delay: 1.0806899992749095, // 0.4091129992157221 + 0.6715770000591874 - memory: { - heap: { - total_in_bytes: 474275840, - used_in_bytes: 315669840, - }, - resident_set_size_in_bytes: 518193152, // just the latest - }, - uptime_in_millis: 67390, // latest from psup - }, - requests: { - disconnects: 0, - total: 138, // 103 + 35 - }, - response_times: { - average: 5.213592233009709, // max of 5.213592233009709, 4.6 - max: 36, // max of 36, 29 - }, - }); - }); - - it('forgets the rollup after flush', () => { - const eventRoller = new EventRoller(); - const [event1, event2] = events; - eventRoller.addEvent(event1); - eventRoller.addEvent(event2); - - const flush1 = eventRoller.flush(); // eslint-disable-line no-unused-vars - const flush2 = eventRoller.flush(); - - expect(flush2).to.be(null); - }); -}); diff --git a/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/ops_buffer/__tests__/map_requests.js b/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/ops_buffer/__tests__/map_requests.js deleted file mode 100644 index 330c6387b9476..0000000000000 --- a/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/ops_buffer/__tests__/map_requests.js +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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. - */ - -import _ from 'lodash'; -import { mapRequests } from '../map_requests'; -import expect from '@kbn/expect'; - -describe('Map requests', () => { - it('flatten ports', () => { - const requests = { '5603': { total: 1, disconnects: 0, statusCodes: {} } }; - const expected = { total: 1, disconnects: 0 }; - expect(_.isEqual(mapRequests(requests), expected)).to.be(true); - }); - - it('combine values', () => { - const requests = { - '5603': { total: 1, disconnects: 0, statusCodes: {} }, - '5604': { - total: 1, - disconnects: 44, - statusCodes: { - '200': 2, - '201': 4, - }, - }, - '5605': { - total: 1, - disconnects: 0, - statusCodes: { - '200': 20, - }, - }, - }; - const expected = { - total: 3, - disconnects: 44, - }; - expect(_.isEqual(mapRequests(requests), expected)).to.be(true); - }); -}); diff --git a/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/ops_buffer/__tests__/map_response_times.js b/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/ops_buffer/__tests__/map_response_times.js deleted file mode 100644 index c8e8b2da0c5c5..0000000000000 --- a/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/ops_buffer/__tests__/map_response_times.js +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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. - */ - -import { isEqual } from 'lodash'; -import { mapResponseTimes } from '../map_response_times'; -import expect from '@kbn/expect'; - -describe('Map response times', () => { - it('flatten ports', () => { - const responseTimes = { '5603': { avg: 30, max: 250 } }; - const expected = { average: 30, max: 250 }; - expect(isEqual(mapResponseTimes(responseTimes), expected)).to.be(true); - }); - - it('combine empty', () => { - const responseTimes = {}; - const expected = { average: 0, max: 0 }; - expect(isEqual(mapResponseTimes(responseTimes), expected)).to.be(true); - }); - - it('combine results', () => { - const responseTimes = { - '5600': { - avg: 1, - max: 10, - }, - '5602': { - avg: 3, - max: 200, - }, - }; - const expected = { average: 3, max: 200 }; - expect(isEqual(mapResponseTimes(responseTimes), expected)).to.be(true); - }); - - it('combine results with different maximums for average and max value', () => { - const responseTimes = { - '5600': { - avg: 5, - max: 10, - }, - '5602': { - avg: 3, - max: 200, - }, - '5604': { - // no average - max: 105, - }, - }; - const expected = { average: 5, max: 200 }; - expect(isEqual(mapResponseTimes(responseTimes), expected)).to.be(true); - }); -}); diff --git a/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/ops_buffer/event_roller.js b/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/ops_buffer/event_roller.js deleted file mode 100644 index 08f1c949f25fc..0000000000000 --- a/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/ops_buffer/event_roller.js +++ /dev/null @@ -1,87 +0,0 @@ -/* - * 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. - */ - -import { get, partialRight, assign, max, sum } from 'lodash'; -import moment from 'moment'; -import v8 from 'v8'; -import { mapRequests } from './map_requests'; -import { mapResponseTimes } from './map_response_times'; - -// rollup functions are for objects with unpredictable keys (e.g., {'200': 1, '201': 2} + {'200':2} = {'200': 3, '201': 2}) -const maxRollup = partialRight(assign, (latest, prev) => max([latest, prev])); - -export class EventRoller { - constructor() { - this.rollup = null; - } - - getFromRollup(path) { - return get(this.rollup, path); - } - - hasEvents() { - return this.rollup !== null; - } - - rollupEvent(event) { - const heapStats = v8.getHeapStatistics(); - const requests = mapRequests(event.requests); - - return { - concurrent_connections: sum([ - event.concurrent_connections, - this.getFromRollup('concurrent_connections'), - ]), - // memory/os stats use the latest event's details - os: { - load: { - '1m': get(event, 'osload[0]'), - '5m': get(event, 'osload[1]'), - '15m': get(event, 'osload[2]'), - }, - memory: { - total_in_bytes: get(event, 'osmem.total'), - free_in_bytes: get(event, 'osmem.free'), - used_in_bytes: get(event, 'osmem.total') - get(event, 'osmem.free'), - }, - uptime_in_millis: event.osup * 1000, // seconds to milliseconds - }, - process: { - event_loop_delay: sum([event.psdelay, this.getFromRollup('process.event_loop_delay')]), - memory: { - heap: { - total_in_bytes: get(event, 'psmem.heapTotal'), - used_in_bytes: get(event, 'psmem.heapUsed'), - size_limit: heapStats.heap_size_limit, - }, - resident_set_size_in_bytes: get(event, 'psmem.rss'), - }, - uptime_in_millis: event.psup * 1000, // seconds to milliseconds - }, - requests: { - disconnects: sum([requests.disconnects, this.getFromRollup('requests.disconnects')]), - total: sum([requests.total, this.getFromRollup('requests.total')]), - }, - response_times: maxRollup( - mapResponseTimes(event.responseTimes), - this.getFromRollup('response_times') - ), - timestamp: moment.utc().toISOString(), - }; - } - - addEvent(event) { - // update internal state with new event data - this.rollup = this.rollupEvent(event); - } - - flush() { - // reset the internal state and return it - const rollup = this.rollup; - this.rollup = null; - return rollup; - } -} diff --git a/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/ops_buffer/map_requests.js b/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/ops_buffer/map_requests.js deleted file mode 100644 index 0a4cbc567b60f..0000000000000 --- a/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/ops_buffer/map_requests.js +++ /dev/null @@ -1,19 +0,0 @@ -/* - * 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. - */ - -import _ from 'lodash'; - -export function mapRequests(requests) { - return _.reduce( - _.values(requests), - (result, value) => { - result.total += value.total; - result.disconnects += value.disconnects; - return result; - }, - { total: 0, disconnects: 0 } - ); -} diff --git a/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/ops_buffer/map_response_times.js b/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/ops_buffer/map_response_times.js deleted file mode 100644 index 496ae914a0c57..0000000000000 --- a/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/ops_buffer/map_response_times.js +++ /dev/null @@ -1,25 +0,0 @@ -/* - * 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. - */ - -import _ from 'lodash'; - -export function mapResponseTimes(times) { - const responseTimes = _.reduce( - _.values(times), - (result, value) => { - if (value.avg) { - result.avg = Math.max(result.avg, value.avg); - } - result.max = Math.max(result.max, value.max); - return result; - }, - { avg: 0, max: 0 } - ); - return { - average: responseTimes.avg, - max: responseTimes.max, - }; -} diff --git a/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/ops_buffer/ops_buffer.js b/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/ops_buffer/ops_buffer.js deleted file mode 100644 index 05f81f5c376a7..0000000000000 --- a/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/ops_buffer/ops_buffer.js +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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. - */ - -import { EventRoller } from './event_roller'; -import { CloudDetector } from '../../../cloud'; - -/** - * Manage the buffer of Kibana Ops events - * @param {Object} server HapiJS server instance - * @return {Object} the revealed `push` and `flush` modules - */ -export function opsBuffer({ config, getOSInfo }) { - // determine the cloud service in the background - const cloudDetector = new CloudDetector(); - - if (config.get('monitoring.tests.cloud_detector.enabled')) { - cloudDetector.detectCloudService(); - } - - const eventRoller = new EventRoller(); - - return { - push(event) { - eventRoller.addEvent(event); - }, - - hasEvents() { - return eventRoller.hasEvents(); - }, - - async flush() { - let cloud; // a property that will be left out of the result if the details are undefined - const cloudDetails = cloudDetector.getCloudDetails(); - if (cloudDetails != null) { - cloud = { cloud: cloudDetails }; - } - - const eventRollup = eventRoller.flush(); - if (eventRollup && eventRollup.os) { - eventRollup.os = { - ...eventRollup.os, - ...(await getOSInfo()), - }; - } - - return { - ...cloud, - ...eventRollup, - }; - }, - }; -} diff --git a/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/lib/get_kibana_info_for_stats.js b/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/lib/get_kibana_info_for_stats.js deleted file mode 100644 index b7cbdbc4f2f9d..0000000000000 --- a/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/lib/get_kibana_info_for_stats.js +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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. - */ - -import { get } from 'lodash'; - -const snapshotRegex = /-snapshot/i; - -/** - * This provides a common structure to apply to all Kibana monitoring documents so that they can be commonly - * searched, field-collapsed, and aggregated against. - * - * @param {Object} kbnServer manager of Kibana services - see `src/legacy/server/kbn_server` in Kibana core - * @param {Object} config Server config - * @param {String} host Kibana host - * @return {Object} The object containing a "kibana" field and source instance details. - */ -export function getKibanaInfoForStats({ kbnServerStatus, kbnServerVersion, config }) { - const status = kbnServerStatus.toJSON(); - - return { - uuid: config.get('server.uuid'), - name: config.get('server.name'), - index: config.get('kibana.index'), - host: config.get('server.host'), - transport_address: `${config.get('server.host')}:${config.get('server.port')}`, - version: kbnServerVersion.replace(snapshotRegex, ''), - snapshot: snapshotRegex.test(kbnServerVersion), - status: get(status, 'overall.state'), - }; -} diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/shards/__tests__/fixtures/index.js b/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/shards/__tests__/fixtures/index.js deleted file mode 100644 index 7380864d5ebe1..0000000000000 --- a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/shards/__tests__/fixtures/index.js +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Not using named imports, because the resources are JSON files - */ -import shardStatsFixture from './shard_stats'; -import clusterFixture from './cluster'; - -export { - shardStatsFixture, - clusterFixture -}; diff --git a/x-pack/legacy/plugins/monitoring/server/plugin.js b/x-pack/legacy/plugins/monitoring/server/plugin.js deleted file mode 100644 index fa9f1ae699919..0000000000000 --- a/x-pack/legacy/plugins/monitoring/server/plugin.js +++ /dev/null @@ -1,189 +0,0 @@ -/* - * 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. - */ - -import { i18n } from '@kbn/i18n'; -import { - LOGGING_TAG, - KIBANA_MONITORING_LOGGING_TAG, - KIBANA_ALERTING_ENABLED, -} from '../common/constants'; -import { requireUIRoutes } from './routes'; -import { instantiateClient } from './es_client/instantiate_client'; -import { initMonitoringXpackInfo } from './init_monitoring_xpack_info'; -import { initBulkUploader, registerCollectors } from './kibana_monitoring'; -import { registerMonitoringCollection } from './telemetry_collection'; -import { getLicenseExpiration } from './alerts/license_expiration'; -import { parseElasticsearchConfig } from './es_client/parse_elasticsearch_config'; - -export class Plugin { - async setup(_coreSetup, pluginsSetup, __LEGACY) { - const { - plugins, - _kbnServer: kbnServer, - log, - logger, - getOSInfo, - _hapi: hapiServer, - events, - expose, - config: monitoringConfig, - injectUiAppVars, - } = __LEGACY; - const config = monitoringConfig(); - - const { usageCollection, licensing, alerting } = pluginsSetup; - registerMonitoringCollection(); - /* - * Register collector objects for stats to show up in the APIs - */ - registerCollectors(usageCollection, { - elasticsearchPlugin: plugins.elasticsearch, - kbnServerConfig: kbnServer.config, - log, - config, - getOSInfo, - hapiServer, - }); - - /* - * Instantiate and start the internal background task that calls collector - * fetch methods and uploads to the ES monitoring bulk endpoint - */ - const xpackMainPlugin = plugins.xpack_main; - - /* - * Parse the Elasticsearch config and read any certificates/keys if necessary - */ - const elasticsearchConfig = parseElasticsearchConfig(config); - - // Create the dedicated client - const client = await instantiateClient({ - log, - events, - elasticsearchConfig, - elasticsearchPlugin: plugins.elasticsearch, - }); - - xpackMainPlugin.status.once('green', async () => { - // first time xpack_main turns green - /* - * End-user-facing services - */ - const uiEnabled = config.get('monitoring.ui.enabled'); - - if (uiEnabled) { - await initMonitoringXpackInfo({ - config, - server: hapiServer, - client, - log, - xpackMainPlugin: plugins.xpack_main, - expose, - }); // Route handlers depend on this for xpackInfo - await requireUIRoutes(__LEGACY); - } - }); - - xpackMainPlugin.registerFeature({ - id: 'monitoring', - name: i18n.translate('xpack.monitoring.featureRegistry.monitoringFeatureName', { - defaultMessage: 'Stack Monitoring', - }), - icon: 'monitoringApp', - navLinkId: 'monitoring', - app: ['monitoring', 'kibana'], - catalogue: ['monitoring'], - privileges: {}, - reserved: { - privilege: { - savedObject: { - all: [], - read: [], - }, - ui: [], - }, - description: i18n.translate('xpack.monitoring.feature.reserved.description', { - defaultMessage: 'To grant users access, you should also assign the monitoring_user role.', - }), - }, - }); - - const bulkUploader = initBulkUploader({ - elasticsearchPlugin: plugins.elasticsearch, - config, - log, - kbnServerStatus: kbnServer.status, - kbnServerVersion: kbnServer.version, - }); - const kibanaCollectionEnabled = config.get('monitoring.kibana.collection.enabled'); - - if (kibanaCollectionEnabled) { - /* - * Bulk uploading of Kibana stats - */ - licensing.license$.subscribe(license => { - // use updated xpack license info to start/stop bulk upload - const mainMonitoring = license.getFeature('monitoring'); - const monitoringBulkEnabled = - mainMonitoring && mainMonitoring.isAvailable && mainMonitoring.isEnabled; - if (monitoringBulkEnabled) { - bulkUploader.start(usageCollection); - } else { - bulkUploader.handleNotEnabled(); - } - }); - } else if (!kibanaCollectionEnabled) { - log( - ['info', LOGGING_TAG, KIBANA_MONITORING_LOGGING_TAG], - 'Internal collection for Kibana monitoring is disabled per configuration.' - ); - } - - injectUiAppVars('monitoring', () => { - return { - maxBucketSize: config.get('monitoring.ui.max_bucket_size'), - minIntervalSeconds: config.get('monitoring.ui.min_interval_seconds'), - kbnIndex: config.get('kibana.index'), - monitoringUiEnabled: config.get('monitoring.ui.enabled'), - showLicenseExpiration: config.get('monitoring.ui.show_license_expiration'), - showCgroupMetricsElasticsearch: config.get('monitoring.ui.container.elasticsearch.enabled'), - showCgroupMetricsLogstash: config.get('monitoring.ui.container.logstash.enabled'), // Note, not currently used, but see https://github.com/elastic/x-pack-kibana/issues/1559 part 2 - }; - }); - - if (KIBANA_ALERTING_ENABLED && alerting) { - // this is not ready right away but we need to register alerts right away - async function getMonitoringCluster() { - const configs = config.get('xpack.monitoring.elasticsearch'); - if (configs.hosts) { - const monitoringCluster = plugins.elasticsearch.getCluster('monitoring'); - const { username, password } = configs; - const fakeRequest = { - headers: { - authorization: `Basic ${Buffer.from(`${username}:${password}`).toString('base64')}`, - }, - }; - return { - callCluster: (...args) => monitoringCluster.callWithRequest(fakeRequest, ...args), - }; - } - return null; - } - - function getLogger(contexts) { - return logger.get('plugins', LOGGING_TAG, ...contexts); - } - alerting.registerType( - getLicenseExpiration( - hapiServer, - getMonitoringCluster, - getLogger, - config.get('xpack.monitoring.ccs.enabled') - ) - ); - } - } -} diff --git a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/register_monitoring_collection.ts b/x-pack/legacy/plugins/monitoring/server/telemetry_collection/register_monitoring_collection.ts deleted file mode 100644 index 0b14eb05f796f..0000000000000 --- a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/register_monitoring_collection.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* - * 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. - */ - -import { telemetryCollectionManager } from '../../../../../../src/legacy/core_plugins/telemetry/server'; -import { getAllStats } from './get_all_stats'; -import { getClusterUuids } from './get_cluster_uuids'; -import { getLicenses } from './get_licenses'; - -export function registerMonitoringCollection() { - telemetryCollectionManager.setCollection({ - esCluster: 'monitoring', - title: 'monitoring', - priority: 2, - statsGetter: getAllStats, - clusterDetailsGetter: getClusterUuids, - licenseGetter: getLicenses, - }); -} diff --git a/x-pack/legacy/plugins/xpack_main/server/routes/api/v1/settings.js b/x-pack/legacy/plugins/xpack_main/server/routes/api/v1/settings.js index 0773a142a8c9e..c830fc9fcd483 100644 --- a/x-pack/legacy/plugins/xpack_main/server/routes/api/v1/settings.js +++ b/x-pack/legacy/plugins/xpack_main/server/routes/api/v1/settings.js @@ -5,8 +5,8 @@ */ import { boomify } from 'boom'; +import { get } from 'lodash'; import { KIBANA_SETTINGS_TYPE } from '../../../../../monitoring/common/constants'; -import { getKibanaInfoForStats } from '../../../../../monitoring/server/kibana_monitoring/lib'; const getClusterUuid = async callCluster => { const { cluster_uuid: uuid } = await callCluster('info', { filterPath: 'cluster_uuid' }); @@ -32,11 +32,21 @@ export function settingsRoute(server, kbnServer) { } const uuid = await getClusterUuid(callCluster); - const kibana = getKibanaInfoForStats({ - kbnServerStatus: kbnServer.status, - kbnServerVersion: kbnServer.version, - config: server.config(), - }); + const snapshotRegex = /-snapshot/i; + const config = server.config(); + const status = kbnServer.status.toJSON(); + const kibana = { + uuid: config.get('server.uuid'), + name: config.get('server.name'), + index: config.get('kibana.index'), + host: config.get('server.host'), + port: config.get('server.port'), + locale: config.get('i18n.locale'), + transport_address: `${config.get('server.host')}:${config.get('server.port')}`, + version: kbnServer.version.replace(snapshotRegex, ''), + snapshot: snapshotRegex.test(kbnServer.version), + status: get(status, 'overall.state'), + }; return { cluster_uuid: uuid, diff --git a/x-pack/plugins/infra/server/index.ts b/x-pack/plugins/infra/server/index.ts index 54f858554a5a3..6cb04897af3f5 100644 --- a/x-pack/plugins/infra/server/index.ts +++ b/x-pack/plugins/infra/server/index.ts @@ -5,10 +5,10 @@ */ import { PluginInitializerContext } from 'src/core/server'; -import { config, InfraConfig, InfraServerPlugin } from './plugin'; +import { config, InfraConfig, InfraServerPlugin, InfraPluginSetup } from './plugin'; import { savedObjectMappings } from './saved_objects'; -export { config, InfraConfig, savedObjectMappings }; +export { config, InfraConfig, savedObjectMappings, InfraPluginSetup }; export function plugin(context: PluginInitializerContext) { return new InfraServerPlugin(context); diff --git a/x-pack/plugins/monitoring/common/__tests__/format_timestamp_to_duration.js b/x-pack/plugins/monitoring/common/__tests__/format_timestamp_to_duration.js new file mode 100644 index 0000000000000..470d596bd2bdc --- /dev/null +++ b/x-pack/plugins/monitoring/common/__tests__/format_timestamp_to_duration.js @@ -0,0 +1,128 @@ +/* + * 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. + */ + +import expect from '@kbn/expect'; +import moment from 'moment'; +import { formatTimestampToDuration } from '../format_timestamp_to_duration'; +import { CALCULATE_DURATION_SINCE, CALCULATE_DURATION_UNTIL } from '../constants'; + +const testTime = moment('2010-05-01'); // pick a date where adding/subtracting 2 months formats roundly to '2 months 0 days' +const getTestTime = () => moment(testTime); // clones the obj so it's not mutated with .adds and .subtracts + +/** + * Test the moment-duration-format template + */ +describe('formatTimestampToDuration', () => { + describe('format timestamp to duration - time since', () => { + it('should format timestamp to human-readable duration', () => { + // time inputs are a few "moments" extra from the time advertised by name + const fiftyNineSeconds = getTestTime().subtract(59, 'seconds'); + expect( + formatTimestampToDuration(fiftyNineSeconds, CALCULATE_DURATION_SINCE, getTestTime()) + ).to.be('59 seconds'); + + const fiveMins = getTestTime() + .subtract(5, 'minutes') + .subtract(30, 'seconds'); + expect(formatTimestampToDuration(fiveMins, CALCULATE_DURATION_SINCE, getTestTime())).to.be( + '6 mins' + ); + + const sixHours = getTestTime() + .subtract(6, 'hours') + .subtract(30, 'minutes'); + expect(formatTimestampToDuration(sixHours, CALCULATE_DURATION_SINCE, getTestTime())).to.be( + '6 hrs 30 mins' + ); + + const sevenDays = getTestTime() + .subtract(7, 'days') + .subtract(6, 'hours') + .subtract(18, 'minutes'); + expect(formatTimestampToDuration(sevenDays, CALCULATE_DURATION_SINCE, getTestTime())).to.be( + '7 days 6 hrs 18 mins' + ); + + const eightWeeks = getTestTime() + .subtract(8, 'weeks') + .subtract(7, 'days') + .subtract(6, 'hours') + .subtract(18, 'minutes'); + expect(formatTimestampToDuration(eightWeeks, CALCULATE_DURATION_SINCE, getTestTime())).to.be( + '2 months 2 days' + ); + + const oneHour = getTestTime().subtract(1, 'hour'); // should trim 0 min + expect(formatTimestampToDuration(oneHour, CALCULATE_DURATION_SINCE, getTestTime())).to.be( + '1 hr' + ); + + const oneDay = getTestTime().subtract(1, 'day'); // should trim 0 hrs + expect(formatTimestampToDuration(oneDay, CALCULATE_DURATION_SINCE, getTestTime())).to.be( + '1 day' + ); + + const twoMonths = getTestTime().subtract(2, 'month'); // should trim 0 days + expect(formatTimestampToDuration(twoMonths, CALCULATE_DURATION_SINCE, getTestTime())).to.be( + '2 months' + ); + }); + }); + + describe('format timestamp to duration - time until', () => { + it('should format timestamp to human-readable duration', () => { + // time inputs are a few "moments" extra from the time advertised by name + const fiftyNineSeconds = getTestTime().add(59, 'seconds'); + expect( + formatTimestampToDuration(fiftyNineSeconds, CALCULATE_DURATION_UNTIL, getTestTime()) + ).to.be('59 seconds'); + + const fiveMins = getTestTime().add(10, 'minutes'); + expect(formatTimestampToDuration(fiveMins, CALCULATE_DURATION_UNTIL, getTestTime())).to.be( + '10 mins' + ); + + const sixHours = getTestTime() + .add(6, 'hours') + .add(30, 'minutes'); + expect(formatTimestampToDuration(sixHours, CALCULATE_DURATION_UNTIL, getTestTime())).to.be( + '6 hrs 30 mins' + ); + + const sevenDays = getTestTime() + .add(7, 'days') + .add(6, 'hours') + .add(18, 'minutes'); + expect(formatTimestampToDuration(sevenDays, CALCULATE_DURATION_UNTIL, getTestTime())).to.be( + '7 days 6 hrs 18 mins' + ); + + const eightWeeks = getTestTime() + .add(8, 'weeks') + .add(7, 'days') + .add(6, 'hours') + .add(18, 'minutes'); + expect(formatTimestampToDuration(eightWeeks, CALCULATE_DURATION_UNTIL, getTestTime())).to.be( + '2 months 2 days' + ); + + const oneHour = getTestTime().add(1, 'hour'); // should trim 0 min + expect(formatTimestampToDuration(oneHour, CALCULATE_DURATION_UNTIL, getTestTime())).to.be( + '1 hr' + ); + + const oneDay = getTestTime().add(1, 'day'); // should trim 0 hrs + expect(formatTimestampToDuration(oneDay, CALCULATE_DURATION_UNTIL, getTestTime())).to.be( + '1 day' + ); + + const twoMonths = getTestTime().add(2, 'month'); // should trim 0 days + expect(formatTimestampToDuration(twoMonths, CALCULATE_DURATION_UNTIL, getTestTime())).to.be( + '2 months' + ); + }); + }); +}); diff --git a/x-pack/plugins/monitoring/common/cancel_promise.ts b/x-pack/plugins/monitoring/common/cancel_promise.ts new file mode 100644 index 0000000000000..f100edda50796 --- /dev/null +++ b/x-pack/plugins/monitoring/common/cancel_promise.ts @@ -0,0 +1,70 @@ +/* + * 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. + */ + +export enum Status { + Canceled, + Failed, + Resolved, + Awaiting, + Idle, +} + +/** + * Simple [PromiseWithCancel] factory + */ +export class PromiseWithCancel { + private _promise: Promise; + private _status: Status = Status.Idle; + + /** + * @param {Promise} promise Promise you want to cancel / track + */ + constructor(promise: Promise) { + this._promise = promise; + } + + /** + * Cancel the promise in any state + */ + public cancel = (): void => { + this._status = Status.Canceled; + }; + + /** + * @returns status based on [Status] + */ + public status = (): Status => { + return this._status; + }; + + /** + * @returns promise passed in [constructor] + * This sets the state to Status.Awaiting + */ + public promise = (): Promise => { + if (this._status === Status.Canceled) { + throw Error('Getting a canceled promise is not allowed'); + } else if (this._status !== Status.Idle) { + return this._promise; + } + return new Promise((resolve, reject) => { + this._status = Status.Awaiting; + return this._promise + .then(response => { + if (this._status !== Status.Canceled) { + this._status = Status.Resolved; + return resolve(response); + } + }) + .catch(error => { + if (this._status !== Status.Canceled) { + this._status = Status.Failed; + return reject(error); + } + }); + }); + }; +} diff --git a/x-pack/plugins/monitoring/common/constants.ts b/x-pack/plugins/monitoring/common/constants.ts new file mode 100644 index 0000000000000..9a4030f3eb214 --- /dev/null +++ b/x-pack/plugins/monitoring/common/constants.ts @@ -0,0 +1,264 @@ +/* + * 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. + */ + +/** + * Helper string to add as a tag in every logging call + */ +export const LOGGING_TAG = 'monitoring'; +/** + * Helper string to add as a tag in every logging call related to Kibana monitoring + */ +export const KIBANA_MONITORING_LOGGING_TAG = 'kibana-monitoring'; + +/** + * The Monitoring API version is the expected API format that we export and expect to import. + * @type {string} + */ +export const MONITORING_SYSTEM_API_VERSION = '7'; +/** + * The type name used within the Monitoring index to publish Kibana ops stats. + * @type {string} + */ +export const KIBANA_STATS_TYPE_MONITORING = 'kibana_stats'; // similar to KIBANA_STATS_TYPE but rolled up into 10s stats from 5s intervals through ops_buffer +/** + * The type name used within the Monitoring index to publish Kibana stats. + * @type {string} + */ +export const KIBANA_SETTINGS_TYPE = 'kibana_settings'; +/** + * The type name used within the Monitoring index to publish Kibana usage stats. + * NOTE: this string shows as-is in the stats API as a field name for the kibana usage stats + * @type {string} + */ +export const KIBANA_USAGE_TYPE = 'kibana'; + +/* + * Key for the localStorage service + */ +export const STORAGE_KEY = 'xpack.monitoring.data'; + +/** + * Units for derivative metric values + */ +export const NORMALIZED_DERIVATIVE_UNIT = '1s'; + +/* + * Values for column sorting in table options + * @type {number} 1 or -1 + */ +export const EUI_SORT_ASCENDING = 'asc'; +export const EUI_SORT_DESCENDING = 'desc'; +export const SORT_ASCENDING = 1; +export const SORT_DESCENDING = -1; + +/* + * Chart colors + * @type {string} + */ +export const CHART_LINE_COLOR = '#d2d2d2'; +export const CHART_TEXT_COLOR = '#9c9c9c'; + +/* + * Number of cluster alerts to show on overview page + * @type {number} + */ +export const CLUSTER_ALERTS_SEARCH_SIZE = 3; + +/* + * Format for moment-duration-format timestamp-to-duration template if the time diffs are gte 1 month + * @type {string} + */ +export const FORMAT_DURATION_TEMPLATE_LONG = 'M [months] d [days]'; + +/* + * Format for moment-duration-format timestamp-to-duration template if the time diffs are lt 1 month but gt 1 minute + * @type {string} + */ +export const FORMAT_DURATION_TEMPLATE_SHORT = ' d [days] h [hrs] m [min]'; + +/* + * Format for moment-duration-format timestamp-to-duration template if the time diffs are lt 1 minute + * @type {string} + */ +export const FORMAT_DURATION_TEMPLATE_TINY = ' s [seconds]'; + +/* + * Simple unique values for Timestamp to duration flags. These are used for + * determining if calculation should be formatted as "time until" (now to + * timestamp) or "time since" (timestamp to now) + */ +export const CALCULATE_DURATION_SINCE = 'since'; +export const CALCULATE_DURATION_UNTIL = 'until'; + +/** + * In order to show ML Jobs tab in the Elasticsearch section / tab navigation, license must be supported + */ +export const ML_SUPPORTED_LICENSES = ['trial', 'platinum', 'enterprise']; + +/** + * Metadata service URLs for the different cloud services that have constant URLs (e.g., unlike GCP, which is a constant prefix). + * + * @type {Object} + */ +export const CLOUD_METADATA_SERVICES = { + // We explicitly call out the version, 2016-09-02, rather than 'latest' to avoid unexpected changes + AWS_URL: 'http://169.254.169.254/2016-09-02/dynamic/instance-identity/document', + + // 2017-04-02 is the first GA release of this API + AZURE_URL: 'http://169.254.169.254/metadata/instance?api-version=2017-04-02', + + // GCP documentation shows both 'metadata.google.internal' (mostly) and '169.254.169.254' (sometimes) + // To bypass potential DNS changes, the IP was used because it's shared with other cloud services + GCP_URL_PREFIX: 'http://169.254.169.254/computeMetadata/v1/instance', +}; + +/** + * Constants used by Logstash monitoring code + */ +export const LOGSTASH = { + MAJOR_VER_REQD_FOR_PIPELINES: 6, + + /* + * Names ES keys on for different Logstash pipeline queues. + * @type {string} + */ + QUEUE_TYPES: { + MEMORY: 'memory', + PERSISTED: 'persisted', + }, +}; + +export const DEBOUNCE_SLOW_MS = 17; // roughly how long it takes to render a frame at 60fps +export const DEBOUNCE_FAST_MS = 10; // roughly how long it takes to render a frame at 100fps + +/** + * Configuration key for setting the email address used for cluster alert notifications. + */ +export const CLUSTER_ALERTS_ADDRESS_CONFIG_KEY = 'cluster_alerts.email_notifications.email_address'; + +export const STANDALONE_CLUSTER_CLUSTER_UUID = '__standalone_cluster__'; + +export const INDEX_PATTERN = '.monitoring-*-6-*,.monitoring-*-7-*'; +export const INDEX_PATTERN_KIBANA = '.monitoring-kibana-6-*,.monitoring-kibana-7-*'; +export const INDEX_PATTERN_LOGSTASH = '.monitoring-logstash-6-*,.monitoring-logstash-7-*'; +export const INDEX_PATTERN_BEATS = '.monitoring-beats-6-*,.monitoring-beats-7-*'; +export const INDEX_ALERTS = '.monitoring-alerts-6,.monitoring-alerts-7'; +export const INDEX_PATTERN_ELASTICSEARCH = '.monitoring-es-6-*,.monitoring-es-7-*'; + +// This is the unique token that exists in monitoring indices collected by metricbeat +export const METRICBEAT_INDEX_NAME_UNIQUE_TOKEN = '-mb-'; + +// We use this for metricbeat migration to identify specific products that we do not have constants for +export const ELASTICSEARCH_SYSTEM_ID = 'elasticsearch'; + +/** + * The id of the infra source owned by the monitoring plugin. + */ +export const INFRA_SOURCE_ID = 'internal-stack-monitoring'; + +/* + * These constants represent code paths within `getClustersFromRequest` + * that an api call wants to invoke. This is meant as an optimization to + * avoid unnecessary ES queries (looking at you logstash) when the data + * is not used. In the long term, it'd be nice to have separate api calls + * instead of this path logic. + */ +export const CODE_PATH_ALL = 'all'; +export const CODE_PATH_ALERTS = 'alerts'; +export const CODE_PATH_KIBANA = 'kibana'; +export const CODE_PATH_ELASTICSEARCH = 'elasticsearch'; +export const CODE_PATH_ML = 'ml'; +export const CODE_PATH_BEATS = 'beats'; +export const CODE_PATH_LOGSTASH = 'logstash'; +export const CODE_PATH_APM = 'apm'; +export const CODE_PATH_LICENSE = 'license'; +export const CODE_PATH_LOGS = 'logs'; + +/** + * The header sent by telemetry service when hitting Elasticsearch to identify query source + * @type {string} + */ +export const TELEMETRY_QUERY_SOURCE = 'TELEMETRY'; + +/** + * The name of the Kibana System ID used to publish and look up Kibana stats through the Monitoring system. + * @type {string} + */ +export const KIBANA_SYSTEM_ID = 'kibana'; + +/** + * The name of the Beats System ID used to publish and look up Beats stats through the Monitoring system. + * @type {string} + */ +export const BEATS_SYSTEM_ID = 'beats'; + +/** + * The name of the Apm System ID used to publish and look up Apm stats through the Monitoring system. + * @type {string} + */ +export const APM_SYSTEM_ID = 'apm'; + +/** + * The name of the Kibana System ID used to look up Logstash stats through the Monitoring system. + * @type {string} + */ +export const LOGSTASH_SYSTEM_ID = 'logstash'; + +/** + * The name of the Kibana System ID used to look up Reporting stats through the Monitoring system. + * @type {string} + */ +export const REPORTING_SYSTEM_ID = 'reporting'; + +/** + * The amount of time, in milliseconds, to wait between collecting kibana stats from es. + * + * Currently 24 hours kept in sync with reporting interval. + * @type {Number} + */ +export const TELEMETRY_COLLECTION_INTERVAL = 86400000; + +/** + * We want to slowly rollout the migration from watcher-based cluster alerts to + * kibana alerts and we only want to enable the kibana alerts once all + * watcher-based cluster alerts have been migrated so this flag will serve + * as the only way to see the new UI and actually run Kibana alerts. It will + * be false until all alerts have been migrated, then it will be removed + */ +export const KIBANA_ALERTING_ENABLED = false; + +/** + * The prefix for all alert types used by monitoring + */ +export const ALERT_TYPE_PREFIX = 'monitoring_'; + +/** + * This is the alert type id for the license expiration alert + */ +export const ALERT_TYPE_LICENSE_EXPIRATION = `${ALERT_TYPE_PREFIX}alert_type_license_expiration`; + +/** + * A listing of all alert types + */ +export const ALERT_TYPES = [ALERT_TYPE_LICENSE_EXPIRATION]; + +/** + * Matches the id for the built-in in email action type + * See x-pack/legacy/plugins/actions/server/builtin_action_types/email.ts + */ +export const ALERT_ACTION_TYPE_EMAIL = '.email'; + +/** + * The number of alerts that have been migrated + */ +export const NUMBER_OF_MIGRATED_ALERTS = 1; + +/** + * The advanced settings config name for the email address + */ +export const MONITORING_CONFIG_ALERTING_EMAIL_ADDRESS = 'monitoring:alertingEmailAddress'; + +export const ALERT_EMAIL_SERVICES = ['gmail', 'hotmail', 'icloud', 'outlook365', 'ses', 'yahoo']; diff --git a/x-pack/plugins/monitoring/common/format_timestamp_to_duration.js b/x-pack/plugins/monitoring/common/format_timestamp_to_duration.js new file mode 100644 index 0000000000000..46c8f7db49b0f --- /dev/null +++ b/x-pack/plugins/monitoring/common/format_timestamp_to_duration.js @@ -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. + */ + +import moment from 'moment'; +import 'moment-duration-format'; +import { + FORMAT_DURATION_TEMPLATE_TINY, + FORMAT_DURATION_TEMPLATE_SHORT, + FORMAT_DURATION_TEMPLATE_LONG, + CALCULATE_DURATION_SINCE, + CALCULATE_DURATION_UNTIL, +} from './constants'; + +/* + * Formats a timestamp string + * @param timestamp: ISO time string + * @param calculationFlag: control "since" or "until" logic + * @param initialTime {Object} moment object (not required) + * @return string + */ +export function formatTimestampToDuration(timestamp, calculationFlag, initialTime) { + initialTime = initialTime || moment(); + let timeDuration; + if (calculationFlag === CALCULATE_DURATION_SINCE) { + timeDuration = moment.duration(initialTime - moment(timestamp)); // since: now - timestamp + } else if (calculationFlag === CALCULATE_DURATION_UNTIL) { + timeDuration = moment.duration(moment(timestamp) - initialTime); // until: timestamp - now + } else { + throw new Error( + '[formatTimestampToDuration] requires a [calculationFlag] parameter to specify format as "since" or "until" the given time.' + ); + } + + // See https://github.com/elastic/x-pack-kibana/issues/3554 + let duration; + if (Math.abs(initialTime.diff(timestamp, 'months')) >= 1) { + // time diff is greater than 1 month, show months / days + duration = moment.duration(timeDuration).format(FORMAT_DURATION_TEMPLATE_LONG); + } else if (Math.abs(initialTime.diff(timestamp, 'minutes')) >= 1) { + // time diff is less than 1 month but greater than a minute, show days / hours / minutes + duration = moment.duration(timeDuration).format(FORMAT_DURATION_TEMPLATE_SHORT); + } else { + // time diff is less than a minute, show seconds + duration = moment.duration(timeDuration).format(FORMAT_DURATION_TEMPLATE_TINY); + } + + return duration + .replace(/ 0 mins$/, '') + .replace(/ 0 hrs$/, '') + .replace(/ 0 days$/, ''); // See https://github.com/jsmreese/moment-duration-format/issues/64 +} diff --git a/x-pack/plugins/monitoring/common/formatting.js b/x-pack/plugins/monitoring/common/formatting.js new file mode 100644 index 0000000000000..a3b3ce07c8c76 --- /dev/null +++ b/x-pack/plugins/monitoring/common/formatting.js @@ -0,0 +1,33 @@ +/* + * 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. + */ + +import moment from 'moment-timezone'; + +export const LARGE_FLOAT = '0,0.[00]'; +export const SMALL_FLOAT = '0.[00]'; +export const LARGE_BYTES = '0,0.0 b'; +export const SMALL_BYTES = '0.0 b'; +export const LARGE_ABBREVIATED = '0,0.[0]a'; + +/** + * Format the {@code date} in the user's expected date/time format using their guessed local time zone. + * @param date Either a numeric Unix timestamp or a {@code Date} object + * @returns The date formatted using 'LL LTS' + */ +export function formatDateTimeLocal(date, useUTC = false) { + return useUTC + ? moment.utc(date).format('LL LTS') + : moment.tz(date, moment.tz.guess()).format('LL LTS'); +} + +/** + * Shorten a Logstash Pipeline's hash for display purposes + * @param {string} hash The complete hash + * @return {string} The shortened hash + */ +export function shortenPipelineHash(hash) { + return hash.substr(0, 6); +} diff --git a/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/ops_buffer/index.js b/x-pack/plugins/monitoring/common/index.js similarity index 76% rename from x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/ops_buffer/index.js rename to x-pack/plugins/monitoring/common/index.js index 8ac495f6293b5..183396f8f0d72 100644 --- a/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/ops_buffer/index.js +++ b/x-pack/plugins/monitoring/common/index.js @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { opsBuffer } from './ops_buffer'; +export { formatTimestampToDuration } from './format_timestamp_to_duration'; diff --git a/x-pack/plugins/monitoring/kibana.json b/x-pack/plugins/monitoring/kibana.json new file mode 100644 index 0000000000000..8d69937c3677d --- /dev/null +++ b/x-pack/plugins/monitoring/kibana.json @@ -0,0 +1,10 @@ +{ + "id": "monitoring", + "version": "8.0.0", + "kibanaVersion": "kibana", + "configPath": ["monitoring"], + "requiredPlugins": ["usageCollection", "licensing", "features"], + "optionalPlugins": ["alerting", "actions", "infra"], + "server": true, + "ui": false +} diff --git a/x-pack/legacy/plugins/monitoring/__tests__/deprecations.js b/x-pack/plugins/monitoring/server/__tests__/deprecations.js similarity index 75% rename from x-pack/legacy/plugins/monitoring/__tests__/deprecations.js rename to x-pack/plugins/monitoring/server/__tests__/deprecations.js index 3df93bdb24f32..aa8008346af85 100644 --- a/x-pack/legacy/plugins/monitoring/__tests__/deprecations.js +++ b/x-pack/plugins/monitoring/server/__tests__/deprecations.js @@ -11,11 +11,13 @@ import sinon from 'sinon'; describe('monitoring plugin deprecations', function() { let transformDeprecations; + const rename = sinon.stub().returns(() => {}); + const fromPath = 'monitoring'; before(function() { - const deprecations = deprecationsModule(); - transformDeprecations = (settings, log = noop) => { - deprecations.forEach(deprecation => deprecation(settings, log)); + const deprecations = deprecationsModule({ rename }); + transformDeprecations = (settings, fromPath, log = noop) => { + deprecations.forEach(deprecation => deprecation(settings, fromPath, log)); }; }); @@ -30,7 +32,7 @@ describe('monitoring plugin deprecations', function() { }; const log = sinon.spy(); - transformDeprecations(settings, log); + transformDeprecations(settings, fromPath, log); expect(log.called).to.be(false); }); @@ -45,7 +47,7 @@ describe('monitoring plugin deprecations', function() { }; const log = sinon.spy(); - transformDeprecations(settings, log); + transformDeprecations(settings, fromPath, log); expect(log.called).to.be(false); }); @@ -61,7 +63,7 @@ describe('monitoring plugin deprecations', function() { }; const log = sinon.spy(); - transformDeprecations(settings, log); + transformDeprecations(settings, fromPath, log); expect(log.called).to.be(false); }); @@ -76,7 +78,7 @@ describe('monitoring plugin deprecations', function() { }; const log = sinon.spy(); - transformDeprecations(settings, log); + transformDeprecations(settings, fromPath, log); expect(log.called).to.be(true); }); }); @@ -86,7 +88,7 @@ describe('monitoring plugin deprecations', function() { const settings = { elasticsearch: { username: 'elastic' } }; const log = sinon.spy(); - transformDeprecations(settings, log); + transformDeprecations(settings, fromPath, log); expect(log.called).to.be(true); }); @@ -94,7 +96,7 @@ describe('monitoring plugin deprecations', function() { const settings = { elasticsearch: { username: 'otheruser' } }; const log = sinon.spy(); - transformDeprecations(settings, log); + transformDeprecations(settings, fromPath, log); expect(log.called).to.be(false); }); @@ -102,7 +104,7 @@ describe('monitoring plugin deprecations', function() { const settings = { elasticsearch: { username: undefined } }; const log = sinon.spy(); - transformDeprecations(settings, log); + transformDeprecations(settings, fromPath, log); expect(log.called).to.be(false); }); @@ -110,7 +112,7 @@ describe('monitoring plugin deprecations', function() { const settings = { elasticsearch: { ssl: { key: '' } } }; const log = sinon.spy(); - transformDeprecations(settings, log); + transformDeprecations(settings, fromPath, log); expect(log.called).to.be(true); }); @@ -118,7 +120,7 @@ describe('monitoring plugin deprecations', function() { const settings = { elasticsearch: { ssl: { certificate: '' } } }; const log = sinon.spy(); - transformDeprecations(settings, log); + transformDeprecations(settings, fromPath, log); expect(log.called).to.be(true); }); @@ -126,8 +128,17 @@ describe('monitoring plugin deprecations', function() { const settings = { elasticsearch: { ssl: { key: '', certificate: '' } } }; const log = sinon.spy(); - transformDeprecations(settings, log); + transformDeprecations(settings, fromPath, log); expect(log.called).to.be(false); }); }); + + describe('xpack_api_polling_frequency_millis', () => { + it('should call rename for this renamed config key', () => { + const settings = { xpack_api_polling_frequency_millis: 30000 }; + const log = sinon.spy(); + transformDeprecations(settings, fromPath, log); + expect(rename.called).to.be(true); + }); + }); }); diff --git a/x-pack/legacy/plugins/monitoring/server/alerts/license_expiration.test.ts b/x-pack/plugins/monitoring/server/alerts/license_expiration.test.ts similarity index 89% rename from x-pack/legacy/plugins/monitoring/server/alerts/license_expiration.test.ts rename to x-pack/plugins/monitoring/server/alerts/license_expiration.test.ts index 1d52ab04dcdbd..0773af6e7f070 100644 --- a/x-pack/legacy/plugins/monitoring/server/alerts/license_expiration.test.ts +++ b/x-pack/plugins/monitoring/server/alerts/license_expiration.test.ts @@ -11,7 +11,7 @@ import { MONITORING_CONFIG_ALERTING_EMAIL_ADDRESS, } from '../../common/constants'; import { Logger } from 'src/core/server'; -import { AlertServices, AlertInstance } from '../../../../../plugins/alerting/server'; +import { AlertServices, AlertInstance } from '../../../alerting/server'; import { savedObjectsClientMock } from 'src/core/server/mocks'; import { AlertState, @@ -69,18 +69,12 @@ const alertExecutorOptions: LicenseExpirationAlertExecutorOptions = { describe('getLicenseExpiration', () => { const emailAddress = 'foo@foo.com'; - const server: any = { - newPlatform: { - __internals: { - uiSettings: { - asScopedToClient: (): any => ({ - get: () => new Promise(resolve => resolve(emailAddress)), - }), - }, - }, - }, - }; - const getMonitoringCluster: () => void = jest.fn(); + const getUiSettingsService: any = () => ({ + asScopedToClient: (): any => ({ + get: () => new Promise(resolve => resolve(emailAddress)), + }), + }); + const monitoringCluster: any = null; const logger: Logger = { warn: jest.fn(), log: jest.fn(), @@ -99,13 +93,23 @@ describe('getLicenseExpiration', () => { }); it('should have the right id and actionGroups', () => { - const alert = getLicenseExpiration(server, getMonitoringCluster, getLogger, ccrEnabled); + const alert = getLicenseExpiration( + getUiSettingsService, + monitoringCluster, + getLogger, + ccrEnabled + ); expect(alert.id).toBe(ALERT_TYPE_LICENSE_EXPIRATION); expect(alert.actionGroups).toEqual([{ id: 'default', name: 'Default' }]); }); it('should return the state if no license is provided', async () => { - const alert = getLicenseExpiration(server, getMonitoringCluster, getLogger, ccrEnabled); + const alert = getLicenseExpiration( + getUiSettingsService, + monitoringCluster, + getLogger, + ccrEnabled + ); const services: MockServices | AlertServices = { callCluster: jest.fn(), @@ -125,18 +129,17 @@ describe('getLicenseExpiration', () => { }); it('should log a warning if no email is provided', async () => { - const customServer: any = { - newPlatform: { - __internals: { - uiSettings: { - asScopedToClient: () => ({ - get: () => null, - }), - }, - }, - }, - }; - const alert = getLicenseExpiration(customServer, getMonitoringCluster, getLogger, ccrEnabled); + const customGetUiSettingsService: any = () => ({ + asScopedToClient: () => ({ + get: () => null, + }), + }); + const alert = getLicenseExpiration( + customGetUiSettingsService, + monitoringCluster, + getLogger, + ccrEnabled + ); const services = { callCluster: jest.fn( @@ -186,7 +189,12 @@ describe('getLicenseExpiration', () => { } ); - const alert = getLicenseExpiration(server, getMonitoringCluster, getLogger, ccrEnabled); + const alert = getLicenseExpiration( + getUiSettingsService, + monitoringCluster, + getLogger, + ccrEnabled + ); const savedObjectsClient = savedObjectsClientMock.create(); savedObjectsClient.get.mockReturnValue( @@ -256,7 +264,12 @@ describe('getLicenseExpiration', () => { return instance; } ); - const alert = getLicenseExpiration(server, getMonitoringCluster, getLogger, ccrEnabled); + const alert = getLicenseExpiration( + getUiSettingsService, + monitoringCluster, + getLogger, + ccrEnabled + ); const savedObjectsClient = savedObjectsClientMock.create(); savedObjectsClient.get.mockReturnValue( @@ -332,7 +345,12 @@ describe('getLicenseExpiration', () => { return instance; } ); - const alert = getLicenseExpiration(server, getMonitoringCluster, getLogger, ccrEnabled); + const alert = getLicenseExpiration( + getUiSettingsService, + monitoringCluster, + getLogger, + ccrEnabled + ); const savedObjectsClient = savedObjectsClientMock.create(); savedObjectsClient.get.mockReturnValue( @@ -396,7 +414,12 @@ describe('getLicenseExpiration', () => { return instance; } ); - const alert = getLicenseExpiration(server, getMonitoringCluster, getLogger, ccrEnabled); + const alert = getLicenseExpiration( + getUiSettingsService, + monitoringCluster, + getLogger, + ccrEnabled + ); const savedObjectsClient = savedObjectsClientMock.create(); savedObjectsClient.get.mockReturnValue( diff --git a/x-pack/legacy/plugins/monitoring/server/alerts/license_expiration.ts b/x-pack/plugins/monitoring/server/alerts/license_expiration.ts similarity index 91% rename from x-pack/legacy/plugins/monitoring/server/alerts/license_expiration.ts rename to x-pack/plugins/monitoring/server/alerts/license_expiration.ts index 9ef19e58bada7..93397ff3641ae 100644 --- a/x-pack/legacy/plugins/monitoring/server/alerts/license_expiration.ts +++ b/x-pack/plugins/monitoring/server/alerts/license_expiration.ts @@ -6,11 +6,10 @@ import moment from 'moment-timezone'; import { get } from 'lodash'; -import { Legacy } from 'kibana'; -import { Logger } from 'src/core/server'; +import { Logger, ICustomClusterClient, UiSettingsServiceStart } from 'src/core/server'; import { i18n } from '@kbn/i18n'; import { ALERT_TYPE_LICENSE_EXPIRATION, INDEX_PATTERN_ELASTICSEARCH } from '../../common/constants'; -import { AlertType } from '../../../../../plugins/alerting/server'; +import { AlertType } from '../../../../plugins/alerting/server'; import { fetchLicenses } from '../lib/alerts/fetch_licenses'; import { fetchDefaultEmailAddress } from '../lib/alerts/fetch_default_email_address'; import { fetchClusters } from '../lib/alerts/fetch_clusters'; @@ -28,21 +27,20 @@ import { executeActions, getUiMessage } from '../lib/alerts/license_expiration.l const EXPIRES_DAYS = [60, 30, 14, 7]; export const getLicenseExpiration = ( - server: Legacy.Server, - getMonitoringCluster: any, - getLogger: (contexts: string[]) => Logger, + getUiSettingsService: () => Promise, + monitoringCluster: ICustomClusterClient, + getLogger: (...scopes: string[]) => Logger, ccsEnabled: boolean ): AlertType => { async function getCallCluster(services: any): Promise { - const monitoringCluster = await getMonitoringCluster(); if (!monitoringCluster) { return services.callCluster; } - return monitoringCluster.callCluster; + return monitoringCluster.callAsInternalUser; } - const logger = getLogger([ALERT_TYPE_LICENSE_EXPIRATION]); + const logger = getLogger(ALERT_TYPE_LICENSE_EXPIRATION); return { id: ALERT_TYPE_LICENSE_EXPIRATION, name: 'Monitoring Alert - License Expiration', @@ -85,7 +83,7 @@ export const getLicenseExpiration = ( return state; } - const uiSettings = server.newPlatform.__internals.uiSettings.asScopedToClient( + const uiSettings = (await getUiSettingsService()).asScopedToClient( services.savedObjectsClient ); const dateFormat: string = await uiSettings.get('dateFormat'); diff --git a/x-pack/legacy/plugins/monitoring/server/alerts/types.d.ts b/x-pack/plugins/monitoring/server/alerts/types.d.ts similarity index 92% rename from x-pack/legacy/plugins/monitoring/server/alerts/types.d.ts rename to x-pack/plugins/monitoring/server/alerts/types.d.ts index 76fc7074e411c..ff47d6f2ad4dc 100644 --- a/x-pack/legacy/plugins/monitoring/server/alerts/types.d.ts +++ b/x-pack/plugins/monitoring/server/alerts/types.d.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ import { Moment } from 'moment'; -import { AlertExecutorOptions } from '../../../../../plugins/alerting/server'; +import { AlertExecutorOptions } from '../../../alerting/server'; export interface AlertLicense { status: string; diff --git a/x-pack/legacy/plugins/monitoring/server/cloud/__tests__/aws.js b/x-pack/plugins/monitoring/server/cloud/__tests__/aws.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/cloud/__tests__/aws.js rename to x-pack/plugins/monitoring/server/cloud/__tests__/aws.js diff --git a/x-pack/legacy/plugins/monitoring/server/cloud/__tests__/azure.js b/x-pack/plugins/monitoring/server/cloud/__tests__/azure.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/cloud/__tests__/azure.js rename to x-pack/plugins/monitoring/server/cloud/__tests__/azure.js diff --git a/x-pack/legacy/plugins/monitoring/server/cloud/__tests__/cloud_detector.js b/x-pack/plugins/monitoring/server/cloud/__tests__/cloud_detector.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/cloud/__tests__/cloud_detector.js rename to x-pack/plugins/monitoring/server/cloud/__tests__/cloud_detector.js diff --git a/x-pack/legacy/plugins/monitoring/server/cloud/__tests__/cloud_response.js b/x-pack/plugins/monitoring/server/cloud/__tests__/cloud_response.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/cloud/__tests__/cloud_response.js rename to x-pack/plugins/monitoring/server/cloud/__tests__/cloud_response.js diff --git a/x-pack/legacy/plugins/monitoring/server/cloud/__tests__/cloud_service.js b/x-pack/plugins/monitoring/server/cloud/__tests__/cloud_service.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/cloud/__tests__/cloud_service.js rename to x-pack/plugins/monitoring/server/cloud/__tests__/cloud_service.js diff --git a/x-pack/legacy/plugins/monitoring/server/cloud/__tests__/cloud_services.js b/x-pack/plugins/monitoring/server/cloud/__tests__/cloud_services.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/cloud/__tests__/cloud_services.js rename to x-pack/plugins/monitoring/server/cloud/__tests__/cloud_services.js diff --git a/x-pack/legacy/plugins/monitoring/server/cloud/__tests__/gcp.js b/x-pack/plugins/monitoring/server/cloud/__tests__/gcp.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/cloud/__tests__/gcp.js rename to x-pack/plugins/monitoring/server/cloud/__tests__/gcp.js diff --git a/x-pack/legacy/plugins/monitoring/server/cloud/aws.js b/x-pack/plugins/monitoring/server/cloud/aws.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/cloud/aws.js rename to x-pack/plugins/monitoring/server/cloud/aws.js diff --git a/x-pack/legacy/plugins/monitoring/server/cloud/azure.js b/x-pack/plugins/monitoring/server/cloud/azure.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/cloud/azure.js rename to x-pack/plugins/monitoring/server/cloud/azure.js diff --git a/x-pack/legacy/plugins/monitoring/server/cloud/cloud_detector.js b/x-pack/plugins/monitoring/server/cloud/cloud_detector.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/cloud/cloud_detector.js rename to x-pack/plugins/monitoring/server/cloud/cloud_detector.js diff --git a/x-pack/legacy/plugins/monitoring/server/cloud/cloud_response.js b/x-pack/plugins/monitoring/server/cloud/cloud_response.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/cloud/cloud_response.js rename to x-pack/plugins/monitoring/server/cloud/cloud_response.js diff --git a/x-pack/legacy/plugins/monitoring/server/cloud/cloud_service.js b/x-pack/plugins/monitoring/server/cloud/cloud_service.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/cloud/cloud_service.js rename to x-pack/plugins/monitoring/server/cloud/cloud_service.js diff --git a/x-pack/legacy/plugins/monitoring/server/cloud/cloud_services.js b/x-pack/plugins/monitoring/server/cloud/cloud_services.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/cloud/cloud_services.js rename to x-pack/plugins/monitoring/server/cloud/cloud_services.js diff --git a/x-pack/legacy/plugins/monitoring/server/cloud/gcp.js b/x-pack/plugins/monitoring/server/cloud/gcp.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/cloud/gcp.js rename to x-pack/plugins/monitoring/server/cloud/gcp.js diff --git a/x-pack/legacy/plugins/monitoring/server/cloud/index.js b/x-pack/plugins/monitoring/server/cloud/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/cloud/index.js rename to x-pack/plugins/monitoring/server/cloud/index.js diff --git a/x-pack/legacy/plugins/monitoring/server/cluster_alerts/__tests__/alerts_cluster_search.js b/x-pack/plugins/monitoring/server/cluster_alerts/__tests__/alerts_cluster_search.js similarity index 99% rename from x-pack/legacy/plugins/monitoring/server/cluster_alerts/__tests__/alerts_cluster_search.js rename to x-pack/plugins/monitoring/server/cluster_alerts/__tests__/alerts_cluster_search.js index f6dafb5bb8c7e..aa94adb57e657 100644 --- a/x-pack/legacy/plugins/monitoring/server/cluster_alerts/__tests__/alerts_cluster_search.js +++ b/x-pack/plugins/monitoring/server/cluster_alerts/__tests__/alerts_cluster_search.js @@ -97,6 +97,7 @@ describe('Alerts Cluster Search', () => { expect(alerts[1]).to.eql({ metadata: { severity: 0, + cluster_uuid: cluster.cluster_uuid, link: 'https://www.elastic.co/guide/en/x-pack/6.1/ssl-tls.html', }, diff --git a/x-pack/legacy/plugins/monitoring/server/cluster_alerts/__tests__/alerts_clusters_aggregation.js b/x-pack/plugins/monitoring/server/cluster_alerts/__tests__/alerts_clusters_aggregation.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/cluster_alerts/__tests__/alerts_clusters_aggregation.js rename to x-pack/plugins/monitoring/server/cluster_alerts/__tests__/alerts_clusters_aggregation.js diff --git a/x-pack/legacy/plugins/monitoring/server/cluster_alerts/__tests__/check_license.js b/x-pack/plugins/monitoring/server/cluster_alerts/__tests__/check_license.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/cluster_alerts/__tests__/check_license.js rename to x-pack/plugins/monitoring/server/cluster_alerts/__tests__/check_license.js diff --git a/x-pack/legacy/plugins/monitoring/server/cluster_alerts/__tests__/fixtures/create_stubs.js b/x-pack/plugins/monitoring/server/cluster_alerts/__tests__/fixtures/create_stubs.js similarity index 51% rename from x-pack/legacy/plugins/monitoring/server/cluster_alerts/__tests__/fixtures/create_stubs.js rename to x-pack/plugins/monitoring/server/cluster_alerts/__tests__/fixtures/create_stubs.js index 5f1ed3f970c2b..9fc53cea2f4ee 100644 --- a/x-pack/legacy/plugins/monitoring/server/cluster_alerts/__tests__/fixtures/create_stubs.js +++ b/x-pack/plugins/monitoring/server/cluster_alerts/__tests__/fixtures/create_stubs.js @@ -1,10 +1,19 @@ +/* + * 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. + */ + import sinon from 'sinon'; export function createStubs(mockQueryResult, featureStub) { const callWithRequestStub = sinon.stub().returns(Promise.resolve(mockQueryResult)); const getClusterStub = sinon.stub().returns({ callWithRequest: callWithRequestStub }); const configStub = sinon.stub().returns({ - get: sinon.stub().withArgs('xpack.monitoring.cluster_alerts.enabled').returns(true) + get: sinon + .stub() + .withArgs('xpack.monitoring.cluster_alerts.enabled') + .returns(true), }); return { callWithRequestStub, @@ -14,14 +23,14 @@ export function createStubs(mockQueryResult, featureStub) { plugins: { monitoring: { info: { - feature: featureStub - } + feature: featureStub, + }, }, elasticsearch: { - getCluster: getClusterStub - } - } - } - } + getCluster: getClusterStub, + }, + }, + }, + }, }; -}; +} diff --git a/x-pack/legacy/plugins/monitoring/server/cluster_alerts/__tests__/verify_monitoring_license.js b/x-pack/plugins/monitoring/server/cluster_alerts/__tests__/verify_monitoring_license.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/cluster_alerts/__tests__/verify_monitoring_license.js rename to x-pack/plugins/monitoring/server/cluster_alerts/__tests__/verify_monitoring_license.js diff --git a/x-pack/legacy/plugins/monitoring/server/cluster_alerts/alerts_cluster_search.js b/x-pack/plugins/monitoring/server/cluster_alerts/alerts_cluster_search.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/cluster_alerts/alerts_cluster_search.js rename to x-pack/plugins/monitoring/server/cluster_alerts/alerts_cluster_search.js diff --git a/x-pack/legacy/plugins/monitoring/server/cluster_alerts/alerts_clusters_aggregation.js b/x-pack/plugins/monitoring/server/cluster_alerts/alerts_clusters_aggregation.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/cluster_alerts/alerts_clusters_aggregation.js rename to x-pack/plugins/monitoring/server/cluster_alerts/alerts_clusters_aggregation.js diff --git a/x-pack/legacy/plugins/monitoring/server/cluster_alerts/check_license.js b/x-pack/plugins/monitoring/server/cluster_alerts/check_license.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/cluster_alerts/check_license.js rename to x-pack/plugins/monitoring/server/cluster_alerts/check_license.js diff --git a/x-pack/legacy/plugins/monitoring/server/cluster_alerts/verify_monitoring_license.js b/x-pack/plugins/monitoring/server/cluster_alerts/verify_monitoring_license.js similarity index 88% rename from x-pack/legacy/plugins/monitoring/server/cluster_alerts/verify_monitoring_license.js rename to x-pack/plugins/monitoring/server/cluster_alerts/verify_monitoring_license.js index e94f4e08fbdb1..71d8051c45984 100644 --- a/x-pack/legacy/plugins/monitoring/server/cluster_alerts/verify_monitoring_license.js +++ b/x-pack/plugins/monitoring/server/cluster_alerts/verify_monitoring_license.js @@ -22,11 +22,10 @@ export function verifyMonitoringLicense(server) { if (config.get('monitoring.cluster_alerts.enabled')) { const xpackInfo = get(server.plugins.monitoring, 'info'); if (xpackInfo) { - const monitoringCluster = xpackInfo.feature('monitoring').getLicenseCheckResults(); - + const watcherFeature = xpackInfo.getWatcherFeature(); return { - enabled: monitoringCluster.clusterAlerts.enabled, - message: monitoringCluster.message, + enabled: watcherFeature.isEnabled, + message: xpackInfo.getMessage(), }; } diff --git a/x-pack/plugins/monitoring/server/config.ts b/x-pack/plugins/monitoring/server/config.ts new file mode 100644 index 0000000000000..6e5092a112744 --- /dev/null +++ b/x-pack/plugins/monitoring/server/config.ts @@ -0,0 +1,230 @@ +/* + * 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. + */ +import { schema, TypeOf } from '@kbn/config-schema'; + +const hostURISchema = schema.uri({ scheme: ['http', 'https'] }); +const DEFAULT_API_VERSION = 'master'; + +export const configSchema = schema.object({ + enabled: schema.boolean({ defaultValue: true }), + elasticsearch: schema.object({ + logFetchCount: schema.number({ defaultValue: 10 }), + sniffOnStart: schema.boolean({ defaultValue: false }), + sniffInterval: schema.oneOf([schema.duration(), schema.literal(false)], { + defaultValue: false, + }), + sniffOnConnectionFault: schema.boolean({ defaultValue: false }), + hosts: schema.maybe( + schema.oneOf([hostURISchema, schema.arrayOf(hostURISchema, { minSize: 1 })]) + ), + preserveHost: schema.boolean({ defaultValue: true }), + username: schema.maybe( + schema.conditional( + schema.contextRef('dist'), + false, + schema.string({ + validate: () => {}, + }), + schema.string() + ) + ), + password: schema.maybe(schema.string()), + requestHeadersWhitelist: schema.oneOf([schema.string(), schema.arrayOf(schema.string())], { + defaultValue: ['authorization'], + }), + customHeaders: schema.recordOf(schema.string(), schema.string(), { defaultValue: {} }), + shardTimeout: schema.duration({ defaultValue: '30s' }), + requestTimeout: schema.duration({ defaultValue: '30s' }), + pingTimeout: schema.duration({ defaultValue: schema.siblingRef('requestTimeout') }), + startupTimeout: schema.duration({ defaultValue: '5s' }), + logQueries: schema.boolean({ defaultValue: false }), + ssl: schema.object( + { + verificationMode: schema.oneOf( + [schema.literal('none'), schema.literal('certificate'), schema.literal('full')], + { defaultValue: 'full' } + ), + certificateAuthorities: schema.maybe( + schema.oneOf([schema.string(), schema.arrayOf(schema.string(), { minSize: 1 })]) + ), + certificate: schema.maybe(schema.string()), + key: schema.maybe(schema.string()), + keyPassphrase: schema.maybe(schema.string()), + keystore: schema.object({ + path: schema.maybe(schema.string()), + password: schema.maybe(schema.string()), + }), + truststore: schema.object({ + path: schema.maybe(schema.string()), + password: schema.maybe(schema.string()), + }), + alwaysPresentCertificate: schema.boolean({ defaultValue: false }), + }, + { + validate: rawConfig => { + if (rawConfig.key && rawConfig.keystore.path) { + return 'cannot use [key] when [keystore.path] is specified'; + } + if (rawConfig.certificate && rawConfig.keystore.path) { + return 'cannot use [certificate] when [keystore.path] is specified'; + } + }, + } + ), + apiVersion: schema.string({ defaultValue: DEFAULT_API_VERSION }), + healthCheck: schema.object({ delay: schema.duration({ defaultValue: 2500 }) }), + ignoreVersionMismatch: schema.conditional( + schema.contextRef('dev'), + false, + schema.boolean({ + validate: rawValue => { + if (rawValue === true) { + return '"ignoreVersionMismatch" can only be set to true in development mode'; + } + }, + defaultValue: false, + }), + schema.boolean({ defaultValue: false }) + ), + }), + ui: schema.object({ + enabled: schema.boolean({ defaultValue: true }), + ccs: schema.object({ + enabled: schema.boolean({ defaultValue: true }), + }), + logs: schema.object({ + index: schema.string({ defaultValue: 'filebeat-*' }), + }), + max_bucket_size: schema.number({ defaultValue: 10000 }), + elasticsearch: schema.object({ + logFetchCount: schema.number({ defaultValue: 10 }), + sniffOnStart: schema.boolean({ defaultValue: false }), + sniffInterval: schema.oneOf([schema.duration(), schema.literal(false)], { + defaultValue: false, + }), + sniffOnConnectionFault: schema.boolean({ defaultValue: false }), + hosts: schema.maybe( + schema.oneOf([hostURISchema, schema.arrayOf(hostURISchema, { minSize: 1 })]) + ), + preserveHost: schema.boolean({ defaultValue: true }), + username: schema.maybe( + schema.conditional( + schema.contextRef('dist'), + false, + schema.string({ + validate: rawConfig => { + if (rawConfig === 'elastic') { + return ( + 'value of "elastic" is forbidden. This is a superuser account that can obfuscate ' + + 'privilege-related issues. You should use the "kibana" user instead.' + ); + } + }, + }), + schema.string() + ) + ), + password: schema.maybe(schema.string()), + requestHeadersWhitelist: schema.oneOf([schema.string(), schema.arrayOf(schema.string())], { + defaultValue: ['authorization'], + }), + customHeaders: schema.recordOf(schema.string(), schema.string(), { defaultValue: {} }), + shardTimeout: schema.duration({ defaultValue: '30s' }), + requestTimeout: schema.duration({ defaultValue: '30s' }), + pingTimeout: schema.duration({ defaultValue: schema.siblingRef('requestTimeout') }), + startupTimeout: schema.duration({ defaultValue: '5s' }), + logQueries: schema.boolean({ defaultValue: false }), + ssl: schema.object( + { + verificationMode: schema.oneOf( + [schema.literal('none'), schema.literal('certificate'), schema.literal('full')], + { defaultValue: 'full' } + ), + certificateAuthorities: schema.maybe( + schema.oneOf([schema.string(), schema.arrayOf(schema.string(), { minSize: 1 })]) + ), + certificate: schema.maybe(schema.string()), + key: schema.maybe(schema.string()), + keyPassphrase: schema.maybe(schema.string()), + keystore: schema.object({ + path: schema.maybe(schema.string()), + password: schema.maybe(schema.string()), + }), + truststore: schema.object({ + path: schema.maybe(schema.string()), + password: schema.maybe(schema.string()), + }), + alwaysPresentCertificate: schema.boolean({ defaultValue: false }), + }, + { + validate: rawConfig => { + if (rawConfig.key && rawConfig.keystore.path) { + return 'cannot use [key] when [keystore.path] is specified'; + } + if (rawConfig.certificate && rawConfig.keystore.path) { + return 'cannot use [certificate] when [keystore.path] is specified'; + } + }, + } + ), + apiVersion: schema.string({ defaultValue: DEFAULT_API_VERSION }), + healthCheck: schema.object({ delay: schema.duration({ defaultValue: 2500 }) }), + ignoreVersionMismatch: schema.conditional( + schema.contextRef('dev'), + false, + schema.boolean({ + validate: rawValue => { + if (rawValue === true) { + return '"ignoreVersionMismatch" can only be set to true in development mode'; + } + }, + defaultValue: false, + }), + schema.boolean({ defaultValue: false }) + ), + }), + container: schema.object({ + elasticsearch: schema.object({ + enabled: schema.boolean({ defaultValue: false }), + }), + logstash: schema.object({ + enabled: schema.boolean({ defaultValue: false }), + }), + }), + min_interval_seconds: schema.number({ defaultValue: 10 }), + show_license_expiration: schema.boolean({ defaultValue: true }), + }), + kibana: schema.object({ + collection: schema.object({ + enabled: schema.boolean({ defaultValue: true }), + interval: schema.number({ defaultValue: 10000 }), // op status metrics get buffered at `ops.interval` and flushed to the bulk endpoint at this interval + }), + }), + cluster_alerts: schema.object({ + enabled: schema.boolean({ defaultValue: true }), + email_notifications: schema.object({ + enabled: schema.boolean({ defaultValue: true }), + email_address: schema.string({ defaultValue: '' }), + }), + }), + licensing: schema.object({ + api_polling_frequency: schema.duration({ + defaultValue: '30s', + }), + }), + agent: schema.object({ + interval: schema.string({ defaultValue: '10s' }), + // TOOD: NP + // .regex(/[\d\.]+[yMwdhms]/) + }), + tests: schema.object({ + cloud_detector: schema.object({ + enabled: schema.boolean({ defaultValue: true }), + }), + }), +}); + +export type MonitoringConfig = TypeOf; diff --git a/x-pack/legacy/plugins/monitoring/deprecations.js b/x-pack/plugins/monitoring/server/deprecations.ts similarity index 54% rename from x-pack/legacy/plugins/monitoring/deprecations.js rename to x-pack/plugins/monitoring/server/deprecations.ts index ae8650fd3b26a..dfe8ab31f972c 100644 --- a/x-pack/legacy/plugins/monitoring/deprecations.js +++ b/x-pack/plugins/monitoring/server/deprecations.ts @@ -5,7 +5,8 @@ */ import { get } from 'lodash'; -import { CLUSTER_ALERTS_ADDRESS_CONFIG_KEY, KIBANA_ALERTING_ENABLED } from './common/constants'; +import { ConfigDeprecationFactory, ConfigDeprecation } from 'kibana/server'; +import { CLUSTER_ALERTS_ADDRESS_CONFIG_KEY } from '../common/constants'; /** * Re-writes deprecated user-defined config settings and logs warnings as a @@ -15,53 +16,45 @@ import { CLUSTER_ALERTS_ADDRESS_CONFIG_KEY, KIBANA_ALERTING_ENABLED } from './co * major version! * @return {Array} array of rename operations and callback function for rename logging */ -export const deprecations = () => { +export const deprecations = ({ rename }: ConfigDeprecationFactory): ConfigDeprecation[] => { return [ - (settings, log) => { - const clusterAlertsEnabled = get(settings, 'cluster_alerts.enabled'); + (config, fromPath, logger) => { + const clusterAlertsEnabled = get(config, 'cluster_alerts.enabled'); const emailNotificationsEnabled = - clusterAlertsEnabled && get(settings, 'cluster_alerts.email_notifications.enabled'); - if (emailNotificationsEnabled) { - if (KIBANA_ALERTING_ENABLED) { - if (get(settings, CLUSTER_ALERTS_ADDRESS_CONFIG_KEY)) { - log( - `Config key "${CLUSTER_ALERTS_ADDRESS_CONFIG_KEY}" is deprecated. Please configure the email adddress through the Stack Monitoring UI instead."` - ); - } - } else { - if (!get(settings, CLUSTER_ALERTS_ADDRESS_CONFIG_KEY)) { - log( - `Config key "${CLUSTER_ALERTS_ADDRESS_CONFIG_KEY}" will be required for email notifications to work in 7.0."` - ); - } - } + clusterAlertsEnabled && get(config, 'cluster_alerts.email_notifications.enabled'); + if (emailNotificationsEnabled && !get(config, CLUSTER_ALERTS_ADDRESS_CONFIG_KEY)) { + logger( + `Config key [${fromPath}.${CLUSTER_ALERTS_ADDRESS_CONFIG_KEY}] will be required for email notifications to work in 7.0."` + ); } + return config; }, - (settings, log) => { - const fromPath = 'monitoring.elasticsearch'; - const es = get(settings, 'elasticsearch'); + (config, fromPath, logger) => { + const es: Record = get(config, 'elasticsearch'); if (es) { if (es.username === 'elastic') { - log( + logger( `Setting [${fromPath}.username] to "elastic" is deprecated. You should use the "kibana" user instead.` ); } } + return config; }, - (settings, log) => { - const fromPath = 'monitoring.elasticsearch.ssl'; - const ssl = get(settings, 'elasticsearch.ssl'); + (config, fromPath, logger) => { + const ssl: Record = get(config, 'elasticsearch.ssl'); if (ssl) { if (ssl.key !== undefined && ssl.certificate === undefined) { - log( + logger( `Setting [${fromPath}.key] without [${fromPath}.certificate] is deprecated. This has no effect, you should use both settings to enable TLS client authentication to Elasticsearch.` ); } else if (ssl.certificate !== undefined && ssl.key === undefined) { - log( + logger( `Setting [${fromPath}.certificate] without [${fromPath}.key] is deprecated. This has no effect, you should use both settings to enable TLS client authentication to Elasticsearch.` ); } } + return config; }, + rename('xpack_api_polling_frequency_millis', 'licensing.api_polling_frequency'), ]; }; diff --git a/x-pack/legacy/plugins/monitoring/server/es_client/README.md b/x-pack/plugins/monitoring/server/es_client/README.md similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/es_client/README.md rename to x-pack/plugins/monitoring/server/es_client/README.md diff --git a/x-pack/plugins/monitoring/server/es_client/__tests__/instantiate_client.js b/x-pack/plugins/monitoring/server/es_client/__tests__/instantiate_client.js new file mode 100644 index 0000000000000..a18b7cc8b79f3 --- /dev/null +++ b/x-pack/plugins/monitoring/server/es_client/__tests__/instantiate_client.js @@ -0,0 +1,125 @@ +/* + * 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. + */ + +import expect from '@kbn/expect'; +import sinon from 'sinon'; +import { instantiateClient, hasMonitoringCluster } from '../instantiate_client'; + +const server = { + monitoring: { + ui: { + elasticsearch: { + hosts: [], + username: 'monitoring-user-internal-test', + password: 'monitoring-p@ssw0rd!-internal-test', + ssl: {}, + customHeaders: { + 'x-custom-headers-test': 'connection-monitoring', + }, + }, + }, + }, +}; +const serverWithUrl = { + monitoring: { + ui: { + elasticsearch: { + hosts: ['http://monitoring-cluster.test:9200'], + username: 'monitoring-user-internal-test', + password: 'monitoring-p@ssw0rd!-internal-test', + ssl: {}, + customHeaders: { + 'x-custom-headers-test': 'connection-monitoring', + }, + }, + }, + }, +}; + +const createClient = sinon.stub(); +const log = { info: sinon.stub() }; + +describe('Instantiate Client', () => { + afterEach(() => { + createClient.resetHistory(); + log.info.resetHistory(); + }); + + describe('Logging', () => { + it('logs that the config was sourced from the production options', () => { + instantiateClient(server.monitoring.ui.elasticsearch, log, createClient); + + expect(log.info.getCall(0).args).to.eql(['config sourced from: production cluster']); + }); + + it('logs that the config was sourced from the monitoring options', () => { + instantiateClient(serverWithUrl.monitoring.ui.elasticsearch, log, createClient); + + expect(log.info.getCall(0).args).to.eql(['config sourced from: monitoring cluster']); + }); + }); + + describe('Custom Headers Configuration', () => { + it('Does not add xpack.monitoring.elasticsearch.customHeaders if connected to production cluster', () => { + instantiateClient(server.monitoring.ui.elasticsearch, log, createClient); + + const createClusterCall = createClient.getCall(0); + + sinon.assert.calledOnce(createClient); + expect(createClusterCall.args[0]).to.be('monitoring'); + expect(createClusterCall.args[1].customHeaders).to.eql(undefined); + }); + + it('Adds xpack.monitoring.elasticsearch.customHeaders if connected to monitoring cluster', () => { + instantiateClient(serverWithUrl.monitoring.ui.elasticsearch, log, createClient); + + const createClusterCall = createClient.getCall(0); + + sinon.assert.calledOnce(createClient); + expect(createClusterCall.args[0]).to.be('monitoring'); + expect(createClusterCall.args[1].customHeaders).to.eql({ + 'x-custom-headers-test': 'connection-monitoring', + }); + }); + }); + + describe('Use a connection to production cluster', () => { + it('exposes an authenticated client using production host settings', () => { + instantiateClient(server.monitoring.ui.elasticsearch, log, createClient); + + const createClusterCall = createClient.getCall(0); + const createClientOptions = createClusterCall.args[1]; + + sinon.assert.calledOnce(createClient); + expect(createClusterCall.args[0]).to.be('monitoring'); + expect(createClientOptions.hosts).to.eql(undefined); + }); + }); + + describe('Use a connection to monitoring cluster', () => { + it('exposes an authenticated client using monitoring host settings', () => { + instantiateClient(serverWithUrl.monitoring.ui.elasticsearch, log, createClient); + const createClusterCall = createClient.getCall(0); + const createClientOptions = createClusterCall.args[1]; + + sinon.assert.calledOnce(createClient); + expect(createClusterCall.args[0]).to.be('monitoring'); + expect(createClientOptions.hosts[0]).to.eql('http://monitoring-cluster.test:9200'); + expect(createClientOptions.username).to.eql('monitoring-user-internal-test'); + expect(createClientOptions.password).to.eql('monitoring-p@ssw0rd!-internal-test'); + }); + }); + + describe('hasMonitoringCluster', () => { + it('returns true if monitoring is configured', () => { + expect(hasMonitoringCluster(serverWithUrl.monitoring.ui.elasticsearch)).to.be(true); + }); + + it('returns false if monitoring is not configured', () => { + expect(hasMonitoringCluster(server.monitoring.ui.elasticsearch)).to.be(false); + }); + }); +}); diff --git a/x-pack/legacy/plugins/monitoring/server/es_client/instantiate_client.js b/x-pack/plugins/monitoring/server/es_client/instantiate_client.ts similarity index 60% rename from x-pack/legacy/plugins/monitoring/server/es_client/instantiate_client.js rename to x-pack/plugins/monitoring/server/es_client/instantiate_client.ts index 671c6cdaaed70..280d8aab70300 100644 --- a/x-pack/legacy/plugins/monitoring/server/es_client/instantiate_client.js +++ b/x-pack/plugins/monitoring/server/es_client/instantiate_client.ts @@ -4,9 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ -import { bindKey, once } from 'lodash'; +import { Logger, ElasticsearchClientConfig, ICustomClusterClient } from 'kibana/server'; +// @ts-ignore import { monitoringBulk } from '../kibana_monitoring/lib/monitoring_bulk'; -import { LOGGING_TAG } from '../../common/constants'; +import { MonitoringElasticsearchConfig } from '../types'; /* Provide a dedicated Elasticsearch client for Monitoring * The connection options can be customized for the Monitoring application @@ -14,22 +15,26 @@ import { LOGGING_TAG } from '../../common/constants'; * Kibana itself is connected to a production cluster. */ -export function exposeClient({ elasticsearchConfig, events, log, elasticsearchPlugin }) { +export function instantiateClient( + elasticsearchConfig: any, + log: Logger, + createClient: ( + type: string, + clientConfig?: Partial + ) => ICustomClusterClient +) { const isMonitoringCluster = hasMonitoringCluster(elasticsearchConfig); - const cluster = elasticsearchPlugin.createCluster('monitoring', { + const cluster = createClient('monitoring', { ...(isMonitoringCluster ? elasticsearchConfig : {}), plugins: [monitoringBulk], logQueries: Boolean(elasticsearchConfig.logQueries), }); - events.on('stop', bindKey(cluster, 'close')); const configSource = isMonitoringCluster ? 'monitoring' : 'production'; - log([LOGGING_TAG, 'es-client'], `config sourced from: ${configSource} cluster`); + log.info(`config sourced from: ${configSource} cluster`); return cluster; } -export function hasMonitoringCluster(config) { - return Boolean(config.hosts && config.hosts.length); +export function hasMonitoringCluster(config: MonitoringElasticsearchConfig) { + return Boolean(config.hosts && config.hosts[0]); } - -export const instantiateClient = once(exposeClient); diff --git a/x-pack/plugins/monitoring/server/index.ts b/x-pack/plugins/monitoring/server/index.ts new file mode 100644 index 0000000000000..a992037fc6087 --- /dev/null +++ b/x-pack/plugins/monitoring/server/index.ts @@ -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. + */ + +import { TypeOf } from '@kbn/config-schema'; +import { PluginInitializerContext, PluginConfigDescriptor } from '../../../../src/core/server'; +import { Plugin } from './plugin'; +import { configSchema } from './config'; +import { deprecations } from './deprecations'; + +export const plugin = (initContext: PluginInitializerContext) => new Plugin(initContext); +export const config: PluginConfigDescriptor> = { + schema: configSchema, + deprecations, +}; diff --git a/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/__tests__/bulk_uploader.js b/x-pack/plugins/monitoring/server/kibana_monitoring/__tests__/bulk_uploader.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/kibana_monitoring/__tests__/bulk_uploader.js rename to x-pack/plugins/monitoring/server/kibana_monitoring/__tests__/bulk_uploader.js diff --git a/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/bulk_uploader.js b/x-pack/plugins/monitoring/server/kibana_monitoring/bulk_uploader.js similarity index 82% rename from x-pack/legacy/plugins/monitoring/server/kibana_monitoring/bulk_uploader.js rename to x-pack/plugins/monitoring/server/kibana_monitoring/bulk_uploader.js index 7417e6ca804d9..c09a08f61dc0a 100644 --- a/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/bulk_uploader.js +++ b/x-pack/plugins/monitoring/server/kibana_monitoring/bulk_uploader.js @@ -5,20 +5,12 @@ */ import { defaultsDeep, uniq, compact, get } from 'lodash'; -import { callClusterFactory } from '../../../xpack_main'; -import { - LOGGING_TAG, - KIBANA_MONITORING_LOGGING_TAG, - TELEMETRY_COLLECTION_INTERVAL, -} from '../../common/constants'; +import { TELEMETRY_COLLECTION_INTERVAL } from '../../common/constants'; -import { sendBulkPayload, monitoringBulk, getKibanaInfoForStats } from './lib'; -import { parseElasticsearchConfig } from '../es_client/parse_elasticsearch_config'; +import { sendBulkPayload, monitoringBulk } from './lib'; import { hasMonitoringCluster } from '../es_client/instantiate_client'; -const LOGGING_TAGS = [LOGGING_TAG, KIBANA_MONITORING_LOGGING_TAG]; - /* * Handles internal Kibana stats collection and uploading data to Monitoring * bulk endpoint. @@ -36,7 +28,7 @@ const LOGGING_TAGS = [LOGGING_TAG, KIBANA_MONITORING_LOGGING_TAG]; * @param {Object} xpackInfo server.plugins.xpack_main.info object */ export class BulkUploader { - constructor({ config, log, interval, elasticsearchPlugin, kbnServerStatus, kbnServerVersion }) { + constructor({ config, log, interval, elasticsearch, kibanaStats }) { if (typeof interval !== 'number') { throw new Error('interval number of milliseconds is required'); } @@ -53,39 +45,27 @@ export class BulkUploader { // Limit sending and fetching usage to once per day once usage is successfully stored // into the monitoring indices. this._usageInterval = TELEMETRY_COLLECTION_INTERVAL; + this._log = log; - this._log = { - debug: message => log(['debug', ...LOGGING_TAGS], message), - info: message => log(['info', ...LOGGING_TAGS], message), - warn: message => log(['warning', ...LOGGING_TAGS], message), - }; - - this._cluster = elasticsearchPlugin.createCluster('admin', { + this._cluster = elasticsearch.createClient('admin', { plugins: [monitoringBulk], }); - const directConfig = parseElasticsearchConfig(config, 'monitoring.elasticsearch'); - if (hasMonitoringCluster(directConfig)) { + if (hasMonitoringCluster(config.elasticsearch)) { this._log.info(`Detected direct connection to monitoring cluster`); this._hasDirectConnectionToMonitoringCluster = true; - this._cluster = elasticsearchPlugin.createCluster('monitoring-direct', directConfig); - elasticsearchPlugin - .getCluster('admin') - .callWithInternalUser('info') - .then(data => { - this._productionClusterUuid = get(data, 'cluster_uuid'); - }); + this._cluster = elasticsearch.createClient('monitoring-direct', config.elasticsearch); + elasticsearch.adminClient.callAsInternalUser('info').then(data => { + this._productionClusterUuid = get(data, 'cluster_uuid'); + }); } - this._callClusterWithInternalUser = callClusterFactory({ - plugins: { elasticsearch: elasticsearchPlugin }, - }).getCallClusterInternal(); - this._getKibanaInfoForStats = () => - getKibanaInfoForStats({ - kbnServerStatus, - kbnServerVersion, - config, - }); + this.kibanaStats = kibanaStats; + this.kibanaStatusGetter = null; + } + + setKibanaStatusGetter(getter) { + this.kibanaStatusGetter = getter; } filterCollectorSet(usageCollection) { @@ -166,7 +146,7 @@ export class BulkUploader { return; } - const data = await usageCollection.bulkFetch(this._callClusterWithInternalUser); + const data = await usageCollection.bulkFetch(this._cluster.callAsInternalUser); const payload = this.toBulkUploadFormat(compact(data), usageCollection); if (payload) { try { @@ -208,6 +188,13 @@ export class BulkUploader { ); } + getKibanaStats() { + return { + ...this.kibanaStats, + status: this.kibanaStatusGetter(), + }; + } + /* * Bulk stats are transformed into a bulk upload format * Non-legacy transformation is done in CollectorSet.toApiStats @@ -265,7 +252,7 @@ export class BulkUploader { ...accum, { index: { _type: type } }, { - kibana: this._getKibanaInfoForStats(), + kibana: this.getKibanaStats(), ...typesNested[type], }, ]; diff --git a/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/__tests__/check_for_email_value.js b/x-pack/plugins/monitoring/server/kibana_monitoring/collectors/__tests__/check_for_email_value.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/__tests__/check_for_email_value.js rename to x-pack/plugins/monitoring/server/kibana_monitoring/collectors/__tests__/check_for_email_value.js diff --git a/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/__tests__/get_default_admin_email.js b/x-pack/plugins/monitoring/server/kibana_monitoring/collectors/__tests__/get_default_admin_email.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/__tests__/get_default_admin_email.js rename to x-pack/plugins/monitoring/server/kibana_monitoring/collectors/__tests__/get_default_admin_email.js diff --git a/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/get_kibana_usage_collector.js b/x-pack/plugins/monitoring/server/kibana_monitoring/collectors/get_kibana_usage_collector.ts similarity index 83% rename from x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/get_kibana_usage_collector.js rename to x-pack/plugins/monitoring/server/kibana_monitoring/collectors/get_kibana_usage_collector.ts index ffb4ea5831073..2c40ac56e19ec 100644 --- a/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/get_kibana_usage_collector.js +++ b/x-pack/plugins/monitoring/server/kibana_monitoring/collectors/get_kibana_usage_collector.ts @@ -5,6 +5,7 @@ */ import { get, snakeCase } from 'lodash'; +import { CallCluster } from 'src/legacy/core_plugins/elasticsearch'; import { KIBANA_USAGE_TYPE, KIBANA_STATS_TYPE_MONITORING } from '../../../common/constants'; const TYPES = [ @@ -19,14 +20,13 @@ const TYPES = [ /** * Fetches saved object counts by querying the .kibana index */ -export function getKibanaUsageCollector(usageCollection, config) { +export function getKibanaUsageCollector(usageCollection: any, kibanaIndex: string) { return usageCollection.makeUsageCollector({ type: KIBANA_USAGE_TYPE, isReady: () => true, - async fetch(callCluster) { - const index = config.get('kibana.index'); + async fetch(callCluster: CallCluster) { const savedObjectCountSearchParams = { - index, + index: kibanaIndex, ignoreUnavailable: true, filterPath: 'aggregations.types.buckets', body: { @@ -43,11 +43,11 @@ export function getKibanaUsageCollector(usageCollection, config) { }; const resp = await callCluster('search', savedObjectCountSearchParams); - const buckets = get(resp, 'aggregations.types.buckets', []); + const buckets: any = get(resp, 'aggregations.types.buckets', []); // get the doc_count from each bucket const bucketCounts = buckets.reduce( - (acc, bucket) => ({ + (acc: any, bucket: any) => ({ ...acc, [bucket.key]: bucket.doc_count, }), @@ -55,7 +55,7 @@ export function getKibanaUsageCollector(usageCollection, config) { ); return { - index, + index: kibanaIndex, ...TYPES.reduce( (acc, type) => ({ // combine the bucketCounts and 0s for types that don't have documents @@ -74,7 +74,7 @@ export function getKibanaUsageCollector(usageCollection, config) { * 1. Make this data part of the "kibana_stats" type * 2. Organize the payload in the usage namespace of the data payload (usage.index, etc) */ - formatForBulkUpload: result => { + formatForBulkUpload: (result: any) => { return { type: KIBANA_STATS_TYPE_MONITORING, payload: { diff --git a/x-pack/plugins/monitoring/server/kibana_monitoring/collectors/get_ops_stats_collector.ts b/x-pack/plugins/monitoring/server/kibana_monitoring/collectors/get_ops_stats_collector.ts new file mode 100644 index 0000000000000..00197e98948bf --- /dev/null +++ b/x-pack/plugins/monitoring/server/kibana_monitoring/collectors/get_ops_stats_collector.ts @@ -0,0 +1,37 @@ +/* + * 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. + */ + +import { Observable } from 'rxjs'; +import moment from 'moment'; +import { OpsMetrics } from 'kibana/server'; +import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; +import { KIBANA_STATS_TYPE_MONITORING } from '../../../common/constants'; + +interface MonitoringOpsMetrics extends OpsMetrics { + timestamp: string; +} + +/* + * Initialize a collector for Kibana Ops Stats + */ +export function getOpsStatsCollector( + usageCollection: UsageCollectionSetup, + metrics$: Observable +) { + let lastMetrics: MonitoringOpsMetrics | null = null; + metrics$.subscribe(metrics => { + lastMetrics = { + ...metrics, + timestamp: moment.utc().toISOString(), + }; + }); + + return usageCollection.makeStatsCollector({ + type: KIBANA_STATS_TYPE_MONITORING, + isReady: () => !!lastMetrics, + fetch: () => lastMetrics, + }); +} diff --git a/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/get_settings_collector.js b/x-pack/plugins/monitoring/server/kibana_monitoring/collectors/get_settings_collector.ts similarity index 74% rename from x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/get_settings_collector.js rename to x-pack/plugins/monitoring/server/kibana_monitoring/collectors/get_settings_collector.ts index f51e7d22a0c7c..63e1dbc400787 100644 --- a/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/get_settings_collector.js +++ b/x-pack/plugins/monitoring/server/kibana_monitoring/collectors/get_settings_collector.ts @@ -4,34 +4,29 @@ * you may not use this file except in compliance with the Elastic License. */ -import { CLUSTER_ALERTS_ADDRESS_CONFIG_KEY, KIBANA_SETTINGS_TYPE } from '../../../common/constants'; +import { KIBANA_SETTINGS_TYPE } from '../../../common/constants'; +import { MonitoringConfig } from '../../config'; /* * Check if Cluster Alert email notifications is enabled in config * If so, get email from kibana.yml */ -export async function getDefaultAdminEmail(config) { - if (!config.get('monitoring.cluster_alerts.email_notifications.enabled')) { +export async function getDefaultAdminEmail(config: MonitoringConfig) { + if (!config.cluster_alerts.email_notifications.enabled) { return null; } - - const emailAddressConfigKey = `monitoring.${CLUSTER_ALERTS_ADDRESS_CONFIG_KEY}`; - const configuredEmailAddress = config.get(emailAddressConfigKey); - - return configuredEmailAddress || null; + return config.cluster_alerts.email_notifications.email_address || null; } // we use shouldUseNull to determine if we need to send nulls; we only send nulls if the last email wasn't null let shouldUseNull = true; export async function checkForEmailValue( - config, - callCluster, - log, + config: MonitoringConfig, _shouldUseNull = shouldUseNull, _getDefaultAdminEmail = getDefaultAdminEmail ) { - const defaultAdminEmail = await _getDefaultAdminEmail(config, callCluster, log); + const defaultAdminEmail = await _getDefaultAdminEmail(config); // Allow null so clearing the advanced setting will be reflected in the data const isAcceptableNull = defaultAdminEmail === null && _shouldUseNull; @@ -46,13 +41,13 @@ export async function checkForEmailValue( } } -export function getSettingsCollector(usageCollection, config) { +export function getSettingsCollector(usageCollection: any, config: MonitoringConfig) { return usageCollection.makeStatsCollector({ type: KIBANA_SETTINGS_TYPE, isReady: () => true, - async fetch(callCluster) { + async fetch() { let kibanaSettingsData; - const defaultAdminEmail = await checkForEmailValue(config, callCluster, this.log); + const defaultAdminEmail = await checkForEmailValue(config); // skip everything if defaultAdminEmail === undefined if (defaultAdminEmail || (defaultAdminEmail === null && shouldUseNull)) { @@ -72,7 +67,7 @@ export function getSettingsCollector(usageCollection, config) { // returns undefined if there was no result return kibanaSettingsData; }, - getEmailValueStructure(email) { + getEmailValueStructure(email: string) { return { xpack: { default_admin_email: email, diff --git a/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/index.js b/x-pack/plugins/monitoring/server/kibana_monitoring/collectors/index.ts similarity index 66% rename from x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/index.js rename to x-pack/plugins/monitoring/server/kibana_monitoring/collectors/index.ts index 1099a23dea103..e41b1512f1b29 100644 --- a/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/collectors/index.js +++ b/x-pack/plugins/monitoring/server/kibana_monitoring/collectors/index.ts @@ -3,15 +3,20 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - +import { Observable } from 'rxjs'; +import { OpsMetrics } from 'kibana/server'; import { getKibanaUsageCollector } from './get_kibana_usage_collector'; import { getOpsStatsCollector } from './get_ops_stats_collector'; import { getSettingsCollector } from './get_settings_collector'; +import { MonitoringConfig } from '../../config'; -export function registerCollectors(usageCollection, collectorsConfigs) { - const { config } = collectorsConfigs; - - usageCollection.registerCollector(getOpsStatsCollector(usageCollection, collectorsConfigs)); - usageCollection.registerCollector(getKibanaUsageCollector(usageCollection, config)); +export function registerCollectors( + usageCollection: any, + config: MonitoringConfig, + opsMetrics$: Observable, + kibanaIndex: string +) { + usageCollection.registerCollector(getOpsStatsCollector(usageCollection, opsMetrics$)); + usageCollection.registerCollector(getKibanaUsageCollector(usageCollection, kibanaIndex)); usageCollection.registerCollector(getSettingsCollector(usageCollection, config)); } diff --git a/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/index.js b/x-pack/plugins/monitoring/server/kibana_monitoring/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/kibana_monitoring/index.js rename to x-pack/plugins/monitoring/server/kibana_monitoring/index.js diff --git a/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/init.js b/x-pack/plugins/monitoring/server/kibana_monitoring/init.js similarity index 91% rename from x-pack/legacy/plugins/monitoring/server/kibana_monitoring/init.js rename to x-pack/plugins/monitoring/server/kibana_monitoring/init.js index 3c02e2be58dec..79aafb8f361f3 100644 --- a/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/init.js +++ b/x-pack/plugins/monitoring/server/kibana_monitoring/init.js @@ -16,7 +16,7 @@ import { BulkUploader } from './bulk_uploader'; * @param {Object} server HapiJS server instance */ export function initBulkUploader({ config, ...params }) { - const interval = config.get('monitoring.kibana.collection.interval'); + const interval = config.kibana.collection.interval; return new BulkUploader({ interval, config, diff --git a/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/lib/index.js b/x-pack/plugins/monitoring/server/kibana_monitoring/lib/index.js similarity index 83% rename from x-pack/legacy/plugins/monitoring/server/kibana_monitoring/lib/index.js rename to x-pack/plugins/monitoring/server/kibana_monitoring/lib/index.js index 56a2f48de88db..c5fdd29d4306d 100644 --- a/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/lib/index.js +++ b/x-pack/plugins/monitoring/server/kibana_monitoring/lib/index.js @@ -6,4 +6,3 @@ export { sendBulkPayload } from './send_bulk_payload'; export { monitoringBulk } from './monitoring_bulk'; -export { getKibanaInfoForStats } from './get_kibana_info_for_stats'; diff --git a/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/lib/monitoring_bulk.js b/x-pack/plugins/monitoring/server/kibana_monitoring/lib/monitoring_bulk.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/kibana_monitoring/lib/monitoring_bulk.js rename to x-pack/plugins/monitoring/server/kibana_monitoring/lib/monitoring_bulk.js diff --git a/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/lib/send_bulk_payload.js b/x-pack/plugins/monitoring/server/kibana_monitoring/lib/send_bulk_payload.js similarity index 94% rename from x-pack/legacy/plugins/monitoring/server/kibana_monitoring/lib/send_bulk_payload.js rename to x-pack/plugins/monitoring/server/kibana_monitoring/lib/send_bulk_payload.js index c378c0ad0fa08..9607b45d7e408 100644 --- a/x-pack/legacy/plugins/monitoring/server/kibana_monitoring/lib/send_bulk_payload.js +++ b/x-pack/plugins/monitoring/server/kibana_monitoring/lib/send_bulk_payload.js @@ -56,12 +56,12 @@ export async function sendBulkPayload( ); } const formattedPayload = formatForNormalBulkEndpoint(payload, productionClusterUuid); - return await cluster.callWithInternalUser('bulk', { + return await cluster.callAsInternalUser('bulk', { body: formattedPayload, }); } - return cluster.callWithInternalUser('monitoring.bulk', { + return cluster.callAsInternalUser('monitoring.bulk', { system_id: KIBANA_SYSTEM_ID, system_api_version: MONITORING_SYSTEM_API_VERSION, interval: interval + 'ms', diff --git a/x-pack/legacy/plugins/monitoring/server/lib/__tests__/calculate_auto.js b/x-pack/plugins/monitoring/server/lib/__tests__/calculate_auto.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/__tests__/calculate_auto.js rename to x-pack/plugins/monitoring/server/lib/__tests__/calculate_auto.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/__tests__/calculate_availabiilty.js b/x-pack/plugins/monitoring/server/lib/__tests__/calculate_availabiilty.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/__tests__/calculate_availabiilty.js rename to x-pack/plugins/monitoring/server/lib/__tests__/calculate_availabiilty.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/__tests__/calculate_overall_status.js b/x-pack/plugins/monitoring/server/lib/__tests__/calculate_overall_status.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/__tests__/calculate_overall_status.js rename to x-pack/plugins/monitoring/server/lib/__tests__/calculate_overall_status.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/__tests__/calculate_rate.js b/x-pack/plugins/monitoring/server/lib/__tests__/calculate_rate.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/__tests__/calculate_rate.js rename to x-pack/plugins/monitoring/server/lib/__tests__/calculate_rate.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/__tests__/calculate_timeseries_interval.js b/x-pack/plugins/monitoring/server/lib/__tests__/calculate_timeseries_interval.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/__tests__/calculate_timeseries_interval.js rename to x-pack/plugins/monitoring/server/lib/__tests__/calculate_timeseries_interval.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/__tests__/ccs_utils.js b/x-pack/plugins/monitoring/server/lib/__tests__/ccs_utils.js similarity index 79% rename from x-pack/legacy/plugins/monitoring/server/lib/__tests__/ccs_utils.js rename to x-pack/plugins/monitoring/server/lib/__tests__/ccs_utils.js index ad02807b5585e..d17253dc0169a 100644 --- a/x-pack/legacy/plugins/monitoring/server/lib/__tests__/ccs_utils.js +++ b/x-pack/plugins/monitoring/server/lib/__tests__/ccs_utils.js @@ -53,9 +53,11 @@ describe('ccs_utils', () => { const abcPattern = prefixIndexPattern(config, indexPattern, 'aBc'); const underscorePattern = prefixIndexPattern(config, indexPattern, 'cluster_one'); - expect(abcPattern).to.eql('aBc:.monitoring-xyz-1-*,aBc:.monitoring-xyz-2-*'); + expect(abcPattern).to.eql( + 'aBc:.monitoring-xyz-1-*,aBc:.monitoring-xyz-2-*,aBc:monitoring-xyz-1-*,aBc:monitoring-xyz-2-*' + ); expect(underscorePattern).to.eql( - 'cluster_one:.monitoring-xyz-1-*,cluster_one:.monitoring-xyz-2-*' + 'cluster_one:.monitoring-xyz-1-*,cluster_one:.monitoring-xyz-2-*,cluster_one:monitoring-xyz-1-*,cluster_one:monitoring-xyz-2-*' ); expect(get.callCount).to.eql(2); }); @@ -69,7 +71,11 @@ describe('ccs_utils', () => { const pattern = prefixIndexPattern(config, indexPattern, '*'); // it should have BOTH patterns so that it searches all CCS clusters and the local cluster - expect(pattern).to.eql('*:.monitoring-xyz-1-*,*:.monitoring-xyz-2-*' + ',' + indexPattern); + expect(pattern).to.eql( + '*:.monitoring-xyz-1-*,*:.monitoring-xyz-2-*,*:monitoring-xyz-1-*,*:monitoring-xyz-2-*' + + ',' + + indexPattern + ); expect(get.callCount).to.eql(1); }); }); @@ -77,18 +83,25 @@ describe('ccs_utils', () => { describe('parseCrossClusterPrefix', () => { it('returns ccs prefix for index with one', () => { expect(parseCrossClusterPrefix('abc:.monitoring-es-6-2017.07.28')).to.eql('abc'); + expect(parseCrossClusterPrefix('abc:monitoring-es-6-2017.07.28')).to.eql('abc'); expect(parseCrossClusterPrefix('abc_123:.monitoring-es-6-2017.07.28')).to.eql('abc_123'); + expect(parseCrossClusterPrefix('abc_123:monitoring-es-6-2017.07.28')).to.eql('abc_123'); expect(parseCrossClusterPrefix('broken:example:.monitoring-es-6-2017.07.28')).to.eql( 'broken' ); + expect(parseCrossClusterPrefix('broken:example:monitoring-es-6-2017.07.28')).to.eql('broken'); expect(parseCrossClusterPrefix('with-a-dash:.monitoring-es-6-2017.07.28')).to.eql( 'with-a-dash' ); + expect(parseCrossClusterPrefix('with-a-dash:monitoring-es-6-2017.07.28')).to.eql( + 'with-a-dash' + ); expect(parseCrossClusterPrefix('something:not-monitoring')).to.eql('something'); }); it('returns null when no prefix exists', () => { expect(parseCrossClusterPrefix('.monitoring-es-6-2017.07.28')).to.be(null); + expect(parseCrossClusterPrefix('monitoring-es-6-2017.07.28')).to.be(null); expect(parseCrossClusterPrefix('random')).to.be(null); }); }); diff --git a/x-pack/legacy/plugins/monitoring/server/lib/__tests__/create_query.js b/x-pack/plugins/monitoring/server/lib/__tests__/create_query.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/__tests__/create_query.js rename to x-pack/plugins/monitoring/server/lib/__tests__/create_query.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/__tests__/helpers.js b/x-pack/plugins/monitoring/server/lib/__tests__/helpers.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/__tests__/helpers.js rename to x-pack/plugins/monitoring/server/lib/__tests__/helpers.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/__tests__/process_version_string.js b/x-pack/plugins/monitoring/server/lib/__tests__/process_version_string.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/__tests__/process_version_string.js rename to x-pack/plugins/monitoring/server/lib/__tests__/process_version_string.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/alerts/fetch_available_ccs.test.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_available_ccs.test.ts similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/alerts/fetch_available_ccs.test.ts rename to x-pack/plugins/monitoring/server/lib/alerts/fetch_available_ccs.test.ts diff --git a/x-pack/legacy/plugins/monitoring/server/lib/alerts/fetch_available_ccs.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_available_ccs.ts similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/alerts/fetch_available_ccs.ts rename to x-pack/plugins/monitoring/server/lib/alerts/fetch_available_ccs.ts diff --git a/x-pack/legacy/plugins/monitoring/server/lib/alerts/fetch_clusters.test.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_clusters.test.ts similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/alerts/fetch_clusters.test.ts rename to x-pack/plugins/monitoring/server/lib/alerts/fetch_clusters.test.ts diff --git a/x-pack/legacy/plugins/monitoring/server/lib/alerts/fetch_clusters.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_clusters.ts similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/alerts/fetch_clusters.ts rename to x-pack/plugins/monitoring/server/lib/alerts/fetch_clusters.ts diff --git a/x-pack/legacy/plugins/monitoring/server/lib/alerts/fetch_default_email_address.test.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_default_email_address.test.ts similarity index 88% rename from x-pack/legacy/plugins/monitoring/server/lib/alerts/fetch_default_email_address.test.ts rename to x-pack/plugins/monitoring/server/lib/alerts/fetch_default_email_address.test.ts index 25b09b956038a..ae914c7a2ace1 100644 --- a/x-pack/legacy/plugins/monitoring/server/lib/alerts/fetch_default_email_address.test.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_default_email_address.test.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ import { fetchDefaultEmailAddress } from './fetch_default_email_address'; -import { uiSettingsServiceMock } from '../../../../../../../src/core/server/mocks'; +import { uiSettingsServiceMock } from '../../../../../../src/core/server/mocks'; describe('fetchDefaultEmailAddress', () => { it('get the email address', async () => { diff --git a/x-pack/legacy/plugins/monitoring/server/lib/alerts/fetch_default_email_address.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_default_email_address.ts similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/alerts/fetch_default_email_address.ts rename to x-pack/plugins/monitoring/server/lib/alerts/fetch_default_email_address.ts diff --git a/x-pack/legacy/plugins/monitoring/server/lib/alerts/fetch_licenses.test.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_licenses.test.ts similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/alerts/fetch_licenses.test.ts rename to x-pack/plugins/monitoring/server/lib/alerts/fetch_licenses.test.ts diff --git a/x-pack/legacy/plugins/monitoring/server/lib/alerts/fetch_licenses.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_licenses.ts similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/alerts/fetch_licenses.ts rename to x-pack/plugins/monitoring/server/lib/alerts/fetch_licenses.ts diff --git a/x-pack/legacy/plugins/monitoring/server/lib/alerts/fetch_status.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_status.ts similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/alerts/fetch_status.ts rename to x-pack/plugins/monitoring/server/lib/alerts/fetch_status.ts diff --git a/x-pack/legacy/plugins/monitoring/server/lib/alerts/get_ccs_index_pattern.test.ts b/x-pack/plugins/monitoring/server/lib/alerts/get_ccs_index_pattern.test.ts similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/alerts/get_ccs_index_pattern.test.ts rename to x-pack/plugins/monitoring/server/lib/alerts/get_ccs_index_pattern.test.ts diff --git a/x-pack/legacy/plugins/monitoring/server/lib/alerts/get_ccs_index_pattern.ts b/x-pack/plugins/monitoring/server/lib/alerts/get_ccs_index_pattern.ts similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/alerts/get_ccs_index_pattern.ts rename to x-pack/plugins/monitoring/server/lib/alerts/get_ccs_index_pattern.ts diff --git a/x-pack/legacy/plugins/monitoring/server/lib/alerts/license_expiration.lib.test.ts b/x-pack/plugins/monitoring/server/lib/alerts/license_expiration.lib.test.ts similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/alerts/license_expiration.lib.test.ts rename to x-pack/plugins/monitoring/server/lib/alerts/license_expiration.lib.test.ts diff --git a/x-pack/legacy/plugins/monitoring/server/lib/alerts/license_expiration.lib.ts b/x-pack/plugins/monitoring/server/lib/alerts/license_expiration.lib.ts similarity index 96% rename from x-pack/legacy/plugins/monitoring/server/lib/alerts/license_expiration.lib.ts rename to x-pack/plugins/monitoring/server/lib/alerts/license_expiration.lib.ts index 520cb31e151ae..41b68d69bbd25 100644 --- a/x-pack/legacy/plugins/monitoring/server/lib/alerts/license_expiration.lib.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/license_expiration.lib.ts @@ -5,7 +5,7 @@ */ import { Moment } from 'moment-timezone'; import { i18n } from '@kbn/i18n'; -import { AlertInstance } from '../../../../../../plugins/alerting/server'; +import { AlertInstance } from '../../../../alerting/server'; import { AlertLicense } from '../../alerts/types'; const RESOLVED_SUBJECT = i18n.translate( diff --git a/x-pack/legacy/plugins/monitoring/server/lib/apm/__tests__/get_apms.js b/x-pack/plugins/monitoring/server/lib/apm/__tests__/get_apms.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/apm/__tests__/get_apms.js rename to x-pack/plugins/monitoring/server/lib/apm/__tests__/get_apms.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/apm/_apm_stats.js b/x-pack/plugins/monitoring/server/lib/apm/_apm_stats.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/apm/_apm_stats.js rename to x-pack/plugins/monitoring/server/lib/apm/_apm_stats.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/apm/_get_time_of_last_event.js b/x-pack/plugins/monitoring/server/lib/apm/_get_time_of_last_event.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/apm/_get_time_of_last_event.js rename to x-pack/plugins/monitoring/server/lib/apm/_get_time_of_last_event.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/apm/create_apm_query.js b/x-pack/plugins/monitoring/server/lib/apm/create_apm_query.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/apm/create_apm_query.js rename to x-pack/plugins/monitoring/server/lib/apm/create_apm_query.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/apm/get_apm_info.js b/x-pack/plugins/monitoring/server/lib/apm/get_apm_info.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/apm/get_apm_info.js rename to x-pack/plugins/monitoring/server/lib/apm/get_apm_info.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/apm/get_apms.js b/x-pack/plugins/monitoring/server/lib/apm/get_apms.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/apm/get_apms.js rename to x-pack/plugins/monitoring/server/lib/apm/get_apms.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/apm/get_apms_for_clusters.js b/x-pack/plugins/monitoring/server/lib/apm/get_apms_for_clusters.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/apm/get_apms_for_clusters.js rename to x-pack/plugins/monitoring/server/lib/apm/get_apms_for_clusters.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/apm/get_stats.js b/x-pack/plugins/monitoring/server/lib/apm/get_stats.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/apm/get_stats.js rename to x-pack/plugins/monitoring/server/lib/apm/get_stats.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/apm/index.js b/x-pack/plugins/monitoring/server/lib/apm/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/apm/index.js rename to x-pack/plugins/monitoring/server/lib/apm/index.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/beats/__tests__/create_beats_query.js b/x-pack/plugins/monitoring/server/lib/beats/__tests__/create_beats_query.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/beats/__tests__/create_beats_query.js rename to x-pack/plugins/monitoring/server/lib/beats/__tests__/create_beats_query.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/beats/__tests__/fixtures/get_listing_response.js b/x-pack/plugins/monitoring/server/lib/beats/__tests__/fixtures/get_listing_response.js similarity index 61% rename from x-pack/legacy/plugins/monitoring/server/lib/beats/__tests__/fixtures/get_listing_response.js rename to x-pack/plugins/monitoring/server/lib/beats/__tests__/fixtures/get_listing_response.js index 7771f916ae28a..f6e86ae92d0ba 100644 --- a/x-pack/legacy/plugins/monitoring/server/lib/beats/__tests__/fixtures/get_listing_response.js +++ b/x-pack/plugins/monitoring/server/lib/beats/__tests__/fixtures/get_listing_response.js @@ -1,3 +1,9 @@ +/* + * 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. + */ + export function getListingsResponses() { return { obsolete_hit: { @@ -8,37 +14,37 @@ export function getListingsResponses() { name: 'spicy.local', type: 'filebeat', uuid: '2736e08b-5830-409b-8169-32aac39c5e55', - version: '7.0.0-alpha1' + version: '7.0.0-alpha1', }, metrics: { beat: { info: { - ephemeral_id: '919c2130-47ea-4f6b-8e7c-510d87e185f2' + ephemeral_id: '919c2130-47ea-4f6b-8e7c-510d87e185f2', }, memstats: { - memory_alloc: 30680648 - } + memory_alloc: 30680648, + }, }, libbeat: { output: { read: { - errors: 0 + errors: 0, }, type: 'elasticsearch', write: { bytes: 137661163, - errors: 0 - } + errors: 0, + }, }, pipeline: { events: { - total: 100 - } - } - } + total: 100, + }, + }, + }, }, - timestamp: '2018-02-09T21:49:35.683Z' - } + timestamp: '2018-02-09T21:49:35.683Z', + }, }, inner_hits: { earliest: { @@ -51,28 +57,28 @@ export function getListingsResponses() { libbeat: { output: { read: { - errors: 0 + errors: 0, }, write: { bytes: 49325414, - errors: 0 - } + errors: 0, + }, }, pipeline: { events: { - total: 34 - } - } - } + total: 34, + }, + }, + }, }, - timestamp: '2018-02-09T21:49:15.683Z' - } - } - } - ] - } - } - } + timestamp: '2018-02-09T21:49:15.683Z', + }, + }, + }, + ], + }, + }, + }, }, unique_hits: [ { @@ -83,37 +89,37 @@ export function getListingsResponses() { name: 'spicy.local', type: 'filebeat', uuid: '2736e08b-5830-409b-8169-32aac39c5e55', - version: '7.0.0-alpha1' + version: '7.0.0-alpha1', }, metrics: { beat: { info: { - ephemeral_id: 'd9b3ccac-cb80-4cb4-9179-2295a305679f' + ephemeral_id: 'd9b3ccac-cb80-4cb4-9179-2295a305679f', }, memstats: { - memory_alloc: 27209376 - } + memory_alloc: 27209376, + }, }, libbeat: { output: { read: { - errors: 0 + errors: 0, }, type: 'elasticsearch', write: { bytes: 2046089790, - errors: 0 - } + errors: 0, + }, }, pipeline: { events: { - total: 1366 - } - } - } + total: 1366, + }, + }, + }, }, - timestamp: '2018-02-09T21:48:55.244Z' - } + timestamp: '2018-02-09T21:48:55.244Z', + }, }, inner_hits: { earliest: { @@ -126,28 +132,28 @@ export function getListingsResponses() { libbeat: { output: { read: { - errors: 0 + errors: 0, }, write: { bytes: 103678160, - errors: 0 - } + errors: 0, + }, }, pipeline: { events: { - total: 69 - } - } - } + total: 69, + }, + }, + }, }, - timestamp: '2018-02-09T21:42:35.243Z' - } - } - } - ] - } - } - } + timestamp: '2018-02-09T21:42:35.243Z', + }, + }, + }, + ], + }, + }, + }, }, { _source: { @@ -157,37 +163,37 @@ export function getListingsResponses() { name: 'spicy.local', type: 'metricbeat', uuid: '60599a4f-8139-4251-b0b9-15866df34221', - version: '7.0.0-alpha1' + version: '7.0.0-alpha1', }, metrics: { beat: { info: { - ephemeral_id: 'f506ef06-1f89-4520-b698-b5591c0784b8' + ephemeral_id: 'f506ef06-1f89-4520-b698-b5591c0784b8', }, memstats: { - memory_alloc: 7598304 - } + memory_alloc: 7598304, + }, }, libbeat: { output: { read: { - errors: 0 + errors: 0, }, type: 'elasticsearch', write: { bytes: 9992700, - errors: 0 - } + errors: 0, + }, }, pipeline: { events: { - total: 12011 - } - } - } + total: 12011, + }, + }, + }, }, - timestamp: '2018-02-09T21:49:38.496Z' - } + timestamp: '2018-02-09T21:49:38.496Z', + }, }, inner_hits: { earliest: { @@ -200,29 +206,29 @@ export function getListingsResponses() { libbeat: { output: { read: { - errors: 0 + errors: 0, }, write: { bytes: 427954, - errors: 0 - } + errors: 0, + }, }, pipeline: { events: { - total: 545 - } - } - } + total: 545, + }, + }, + }, }, - timestamp: '2018-02-09T21:42:38.496Z' - } - } - } - ] - } - } - } - } - ] + timestamp: '2018-02-09T21:42:38.496Z', + }, + }, + }, + ], + }, + }, + }, + }, + ], }; } diff --git a/x-pack/legacy/plugins/monitoring/server/lib/beats/__tests__/get_beat_summary.js b/x-pack/plugins/monitoring/server/lib/beats/__tests__/get_beat_summary.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/beats/__tests__/get_beat_summary.js rename to x-pack/plugins/monitoring/server/lib/beats/__tests__/get_beat_summary.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/beats/__tests__/get_beats.js b/x-pack/plugins/monitoring/server/lib/beats/__tests__/get_beats.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/beats/__tests__/get_beats.js rename to x-pack/plugins/monitoring/server/lib/beats/__tests__/get_beats.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/beats/__tests__/get_beats_for_clusters.js b/x-pack/plugins/monitoring/server/lib/beats/__tests__/get_beats_for_clusters.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/beats/__tests__/get_beats_for_clusters.js rename to x-pack/plugins/monitoring/server/lib/beats/__tests__/get_beats_for_clusters.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/beats/__tests__/get_latest_stats.js b/x-pack/plugins/monitoring/server/lib/beats/__tests__/get_latest_stats.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/beats/__tests__/get_latest_stats.js rename to x-pack/plugins/monitoring/server/lib/beats/__tests__/get_latest_stats.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/beats/__tests__/get_stats.js b/x-pack/plugins/monitoring/server/lib/beats/__tests__/get_stats.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/beats/__tests__/get_stats.js rename to x-pack/plugins/monitoring/server/lib/beats/__tests__/get_stats.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/beats/_beats_stats.js b/x-pack/plugins/monitoring/server/lib/beats/_beats_stats.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/beats/_beats_stats.js rename to x-pack/plugins/monitoring/server/lib/beats/_beats_stats.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/beats/create_beats_query.js b/x-pack/plugins/monitoring/server/lib/beats/create_beats_query.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/beats/create_beats_query.js rename to x-pack/plugins/monitoring/server/lib/beats/create_beats_query.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/beats/get_beat_summary.js b/x-pack/plugins/monitoring/server/lib/beats/get_beat_summary.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/beats/get_beat_summary.js rename to x-pack/plugins/monitoring/server/lib/beats/get_beat_summary.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/beats/get_beats.js b/x-pack/plugins/monitoring/server/lib/beats/get_beats.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/beats/get_beats.js rename to x-pack/plugins/monitoring/server/lib/beats/get_beats.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/beats/get_beats_for_clusters.js b/x-pack/plugins/monitoring/server/lib/beats/get_beats_for_clusters.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/beats/get_beats_for_clusters.js rename to x-pack/plugins/monitoring/server/lib/beats/get_beats_for_clusters.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/beats/get_latest_stats.js b/x-pack/plugins/monitoring/server/lib/beats/get_latest_stats.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/beats/get_latest_stats.js rename to x-pack/plugins/monitoring/server/lib/beats/get_latest_stats.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/beats/get_stats.js b/x-pack/plugins/monitoring/server/lib/beats/get_stats.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/beats/get_stats.js rename to x-pack/plugins/monitoring/server/lib/beats/get_stats.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/beats/index.js b/x-pack/plugins/monitoring/server/lib/beats/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/beats/index.js rename to x-pack/plugins/monitoring/server/lib/beats/index.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/calculate_auto.js b/x-pack/plugins/monitoring/server/lib/calculate_auto.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/calculate_auto.js rename to x-pack/plugins/monitoring/server/lib/calculate_auto.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/calculate_availability.js b/x-pack/plugins/monitoring/server/lib/calculate_availability.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/calculate_availability.js rename to x-pack/plugins/monitoring/server/lib/calculate_availability.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/calculate_overall_status.js b/x-pack/plugins/monitoring/server/lib/calculate_overall_status.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/calculate_overall_status.js rename to x-pack/plugins/monitoring/server/lib/calculate_overall_status.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/calculate_rate.js b/x-pack/plugins/monitoring/server/lib/calculate_rate.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/calculate_rate.js rename to x-pack/plugins/monitoring/server/lib/calculate_rate.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/calculate_timeseries_interval.js b/x-pack/plugins/monitoring/server/lib/calculate_timeseries_interval.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/calculate_timeseries_interval.js rename to x-pack/plugins/monitoring/server/lib/calculate_timeseries_interval.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/ccs_utils.js b/x-pack/plugins/monitoring/server/lib/ccs_utils.js similarity index 88% rename from x-pack/legacy/plugins/monitoring/server/lib/ccs_utils.js rename to x-pack/plugins/monitoring/server/lib/ccs_utils.js index 3409462156a07..f600fafd892c5 100644 --- a/x-pack/legacy/plugins/monitoring/server/lib/ccs_utils.js +++ b/x-pack/plugins/monitoring/server/lib/ccs_utils.js @@ -3,6 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ +import { isFunction, get } from 'lodash'; /** * Prefix all comma separated index patterns within the original {@code indexPattern}. @@ -16,7 +17,14 @@ * @return {String} The index pattern with the {@code cluster} prefix appropriately prepended. */ export function prefixIndexPattern(config, indexPattern, ccs) { - const ccsEnabled = config.get('monitoring.ui.ccs.enabled'); + let ccsEnabled = false; + // TODO: NP + // This function is called with both NP config and LP config + if (isFunction(config.get)) { + ccsEnabled = config.get('monitoring.ui.ccs.enabled'); + } else { + ccsEnabled = get(config, 'monitoring.ui.ccs.enabled'); + } if (!ccsEnabled || !ccs) { return indexPattern; diff --git a/x-pack/legacy/plugins/monitoring/server/lib/cluster/__test__/__snapshots__/get_clusters_summary.test.js.snap b/x-pack/plugins/monitoring/server/lib/cluster/__test__/__snapshots__/get_clusters_summary.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/cluster/__test__/__snapshots__/get_clusters_summary.test.js.snap rename to x-pack/plugins/monitoring/server/lib/cluster/__test__/__snapshots__/get_clusters_summary.test.js.snap diff --git a/x-pack/legacy/plugins/monitoring/server/lib/cluster/__test__/fixtures/clusters.json b/x-pack/plugins/monitoring/server/lib/cluster/__test__/fixtures/clusters.json similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/cluster/__test__/fixtures/clusters.json rename to x-pack/plugins/monitoring/server/lib/cluster/__test__/fixtures/clusters.json diff --git a/x-pack/legacy/plugins/monitoring/server/lib/cluster/__test__/get_clusters_summary.test.js b/x-pack/plugins/monitoring/server/lib/cluster/__test__/get_clusters_summary.test.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/cluster/__test__/get_clusters_summary.test.js rename to x-pack/plugins/monitoring/server/lib/cluster/__test__/get_clusters_summary.test.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/cluster/__tests__/flag_supported_clusters.js b/x-pack/plugins/monitoring/server/lib/cluster/__tests__/flag_supported_clusters.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/cluster/__tests__/flag_supported_clusters.js rename to x-pack/plugins/monitoring/server/lib/cluster/__tests__/flag_supported_clusters.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/cluster/__tests__/get_cluster_status.js b/x-pack/plugins/monitoring/server/lib/cluster/__tests__/get_cluster_status.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/cluster/__tests__/get_cluster_status.js rename to x-pack/plugins/monitoring/server/lib/cluster/__tests__/get_cluster_status.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/cluster/__tests__/get_clusters_state.js b/x-pack/plugins/monitoring/server/lib/cluster/__tests__/get_clusters_state.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/cluster/__tests__/get_clusters_state.js rename to x-pack/plugins/monitoring/server/lib/cluster/__tests__/get_clusters_state.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/cluster/__tests__/get_clusters_stats.js b/x-pack/plugins/monitoring/server/lib/cluster/__tests__/get_clusters_stats.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/cluster/__tests__/get_clusters_stats.js rename to x-pack/plugins/monitoring/server/lib/cluster/__tests__/get_clusters_stats.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/cluster/flag_supported_clusters.js b/x-pack/plugins/monitoring/server/lib/cluster/flag_supported_clusters.js similarity index 96% rename from x-pack/legacy/plugins/monitoring/server/lib/cluster/flag_supported_clusters.js rename to x-pack/plugins/monitoring/server/lib/cluster/flag_supported_clusters.js index 3683be968f0c7..1739f5dc33038 100644 --- a/x-pack/legacy/plugins/monitoring/server/lib/cluster/flag_supported_clusters.js +++ b/x-pack/plugins/monitoring/server/lib/cluster/flag_supported_clusters.js @@ -6,7 +6,7 @@ import { get, set, find } from 'lodash'; import { checkParam } from '../error_missing_required'; -import { LOGGING_TAG, STANDALONE_CLUSTER_CLUSTER_UUID } from '../../../common/constants'; +import { STANDALONE_CLUSTER_CLUSTER_UUID } from '../../../common/constants'; async function findSupportedBasicLicenseCluster( req, @@ -72,7 +72,7 @@ export function flagSupportedClusters(req, kbnIndexPattern) { checkParam(kbnIndexPattern, 'kbnIndexPattern in cluster/flagSupportedClusters'); const config = req.server.config(); - const serverLog = msg => req.server.log(['debug', LOGGING_TAG, 'supported-clusters'], msg); + const serverLog = msg => req.getLogger('supported-clusters').debug(msg); const flagAllSupported = clusters => { clusters.forEach(cluster => { if (cluster.license) { diff --git a/x-pack/legacy/plugins/monitoring/server/lib/cluster/get_cluster_license.js b/x-pack/plugins/monitoring/server/lib/cluster/get_cluster_license.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/cluster/get_cluster_license.js rename to x-pack/plugins/monitoring/server/lib/cluster/get_cluster_license.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/cluster/get_cluster_stats.js b/x-pack/plugins/monitoring/server/lib/cluster/get_cluster_stats.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/cluster/get_cluster_stats.js rename to x-pack/plugins/monitoring/server/lib/cluster/get_cluster_stats.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/cluster/get_cluster_status.js b/x-pack/plugins/monitoring/server/lib/cluster/get_cluster_status.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/cluster/get_cluster_status.js rename to x-pack/plugins/monitoring/server/lib/cluster/get_cluster_status.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/cluster/get_clusters_from_request.js b/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_from_request.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/cluster/get_clusters_from_request.js rename to x-pack/plugins/monitoring/server/lib/cluster/get_clusters_from_request.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/cluster/get_clusters_state.js b/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_state.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/cluster/get_clusters_state.js rename to x-pack/plugins/monitoring/server/lib/cluster/get_clusters_state.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/cluster/get_clusters_stats.js b/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_stats.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/cluster/get_clusters_stats.js rename to x-pack/plugins/monitoring/server/lib/cluster/get_clusters_stats.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/cluster/get_clusters_summary.js b/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_summary.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/cluster/get_clusters_summary.js rename to x-pack/plugins/monitoring/server/lib/cluster/get_clusters_summary.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/cluster/get_index_patterns.js b/x-pack/plugins/monitoring/server/lib/cluster/get_index_patterns.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/cluster/get_index_patterns.js rename to x-pack/plugins/monitoring/server/lib/cluster/get_index_patterns.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/cluster/is_in_code_path.js b/x-pack/plugins/monitoring/server/lib/cluster/is_in_code_path.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/cluster/is_in_code_path.js rename to x-pack/plugins/monitoring/server/lib/cluster/is_in_code_path.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/create_query.js b/x-pack/plugins/monitoring/server/lib/create_query.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/create_query.js rename to x-pack/plugins/monitoring/server/lib/create_query.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/details/__test__/__snapshots__/get_metrics.test.js.snap b/x-pack/plugins/monitoring/server/lib/details/__test__/__snapshots__/get_metrics.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/details/__test__/__snapshots__/get_metrics.test.js.snap rename to x-pack/plugins/monitoring/server/lib/details/__test__/__snapshots__/get_metrics.test.js.snap diff --git a/x-pack/legacy/plugins/monitoring/server/lib/details/__test__/fixtures/agg_metrics_buckets.json b/x-pack/plugins/monitoring/server/lib/details/__test__/fixtures/agg_metrics_buckets.json similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/details/__test__/fixtures/agg_metrics_buckets.json rename to x-pack/plugins/monitoring/server/lib/details/__test__/fixtures/agg_metrics_buckets.json diff --git a/x-pack/legacy/plugins/monitoring/server/lib/details/__test__/fixtures/deriv_metrics_buckets.json b/x-pack/plugins/monitoring/server/lib/details/__test__/fixtures/deriv_metrics_buckets.json similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/details/__test__/fixtures/deriv_metrics_buckets.json rename to x-pack/plugins/monitoring/server/lib/details/__test__/fixtures/deriv_metrics_buckets.json diff --git a/x-pack/legacy/plugins/monitoring/server/lib/details/__test__/fixtures/non_deriv_metrics_buckets.json b/x-pack/plugins/monitoring/server/lib/details/__test__/fixtures/non_deriv_metrics_buckets.json similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/details/__test__/fixtures/non_deriv_metrics_buckets.json rename to x-pack/plugins/monitoring/server/lib/details/__test__/fixtures/non_deriv_metrics_buckets.json diff --git a/x-pack/legacy/plugins/monitoring/server/lib/details/__test__/get_metrics.test.js b/x-pack/plugins/monitoring/server/lib/details/__test__/get_metrics.test.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/details/__test__/get_metrics.test.js rename to x-pack/plugins/monitoring/server/lib/details/__test__/get_metrics.test.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/details/get_metrics.js b/x-pack/plugins/monitoring/server/lib/details/get_metrics.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/details/get_metrics.js rename to x-pack/plugins/monitoring/server/lib/details/get_metrics.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/details/get_series.js b/x-pack/plugins/monitoring/server/lib/details/get_series.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/details/get_series.js rename to x-pack/plugins/monitoring/server/lib/details/get_series.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/__tests__/get_last_recovery.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/__tests__/get_last_recovery.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/__tests__/get_last_recovery.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/__tests__/get_last_recovery.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/__tests__/get_ml_jobs.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/__tests__/get_ml_jobs.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/__tests__/get_ml_jobs.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/__tests__/get_ml_jobs.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/ccr.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/ccr.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/ccr.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/ccr.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/convert_metric_names.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/convert_metric_names.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/convert_metric_names.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/convert_metric_names.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/get_last_recovery.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/get_last_recovery.js similarity index 96% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/get_last_recovery.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/get_last_recovery.js index c32b975118f58..d58144ac57290 100644 --- a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/get_last_recovery.js +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/get_last_recovery.js @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - +import moment from 'moment'; import _ from 'lodash'; import { checkParam } from '../error_missing_required'; import { createQuery } from '../create_query'; @@ -38,7 +38,7 @@ export function filterOldShardActivity(startMs) { export function handleLastRecoveries(resp, start) { if (resp.hits.hits.length === 1) { const data = _.get(resp.hits.hits[0], '_source.index_recovery.shards', []).filter( - filterOldShardActivity(start.getTime()) + filterOldShardActivity(moment.utc(start).valueOf()) ); data.sort((a, b) => b.start_time_in_millis - a.start_time_in_millis); return data; diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/get_ml_jobs.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/get_ml_jobs.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/get_ml_jobs.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/get_ml_jobs.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/index.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/index.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/index.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/indices/__tests__/get_index_summary.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/indices/__tests__/get_index_summary.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/indices/__tests__/get_index_summary.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/indices/__tests__/get_index_summary.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/indices/__tests__/get_indices.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/indices/__tests__/get_indices.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/indices/__tests__/get_indices.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/indices/__tests__/get_indices.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/indices/get_index_summary.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/indices/get_index_summary.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/indices/get_index_summary.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/indices/get_index_summary.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/indices/get_indices.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/indices/get_indices.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/indices/get_indices.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/indices/get_indices.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/indices/index.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/indices/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/indices/index.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/indices/index.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/__tests__/calculate_node_type.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/__tests__/calculate_node_type.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/__tests__/calculate_node_type.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/__tests__/calculate_node_type.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/__tests__/get_node_summary.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/__tests__/get_node_summary.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/__tests__/get_node_summary.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/__tests__/get_node_summary.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/__tests__/get_node_type_class_label.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/__tests__/get_node_type_class_label.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/__tests__/get_node_type_class_label.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/__tests__/get_node_type_class_label.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/__tests__/lookups.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/__tests__/lookups.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/__tests__/lookups.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/__tests__/lookups.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/calculate_node_type.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/calculate_node_type.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/calculate_node_type.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/calculate_node_type.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_default_node_from_id.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_default_node_from_id.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_default_node_from_id.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_default_node_from_id.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_node_summary.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_node_summary.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_node_summary.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_node_summary.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_node_type_class_label.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_node_type_class_label.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_node_type_class_label.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_node_type_class_label.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/__snapshots__/get_metric_aggs.test.js.snap b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/__snapshots__/get_metric_aggs.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/__snapshots__/get_metric_aggs.test.js.snap rename to x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/__snapshots__/get_metric_aggs.test.js.snap diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/__snapshots__/handle_response.test.js.snap b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/__snapshots__/handle_response.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/__snapshots__/handle_response.test.js.snap rename to x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/__snapshots__/handle_response.test.js.snap diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/__snapshots__/map_nodes_info.test.js.snap b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/__snapshots__/map_nodes_info.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/__snapshots__/map_nodes_info.test.js.snap rename to x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/__snapshots__/map_nodes_info.test.js.snap diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/__snapshots__/map_nodes_metrics.test.js.snap b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/__snapshots__/map_nodes_metrics.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/__snapshots__/map_nodes_metrics.test.js.snap rename to x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/__snapshots__/map_nodes_metrics.test.js.snap diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/fixtures/cluster_data.json b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/fixtures/cluster_data.json similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/fixtures/cluster_data.json rename to x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/fixtures/cluster_data.json diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/get_metric_aggs.test.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/get_metric_aggs.test.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/get_metric_aggs.test.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/get_metric_aggs.test.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/get_node_ids.test.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/get_node_ids.test.js similarity index 93% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/get_node_ids.test.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/get_node_ids.test.js index 19fa99a783302..969216d6859e5 100644 --- a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/get_node_ids.test.js +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/get_node_ids.test.js @@ -47,7 +47,7 @@ describe('getNodeIds', () => { }; const clusterUuid = '1cb'; - const result = await getNodeIds(req, '.monitoring-es-*', { clusterUuid }, 10); + const result = await getNodeIds(req, '.monitoring-es-*s', { clusterUuid }, 10); expect(result).toEqual([ { name: 'foobar', uuid: 1 }, { name: 'barfoo', uuid: 2 }, diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/get_paginated_nodes.test.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/get_paginated_nodes.test.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/get_paginated_nodes.test.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/get_paginated_nodes.test.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/handle_response.test.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/handle_response.test.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/handle_response.test.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/handle_response.test.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/map_nodes_info.test.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/map_nodes_info.test.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/map_nodes_info.test.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/map_nodes_info.test.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/map_nodes_metrics.test.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/map_nodes_metrics.test.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/map_nodes_metrics.test.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/__test__/map_nodes_metrics.test.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_live_nodes.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_live_nodes.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_live_nodes.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_live_nodes.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_metric_aggs.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_metric_aggs.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_metric_aggs.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_metric_aggs.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_node_ids.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_node_ids.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_node_ids.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_node_ids.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_nodes.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_nodes.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_nodes.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_nodes.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_paginated_nodes.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_paginated_nodes.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_paginated_nodes.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_paginated_nodes.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/handle_response.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/handle_response.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/handle_response.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/handle_response.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/index.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/index.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/index.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/map_nodes_info.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/map_nodes_info.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/map_nodes_info.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/map_nodes_info.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/map_nodes_metrics.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/map_nodes_metrics.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/map_nodes_metrics.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/map_nodes_metrics.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/nodes_listing_metrics.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/nodes_listing_metrics.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/nodes_listing_metrics.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/nodes_listing_metrics.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/sort_nodes.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/sort_nodes.js similarity index 93% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/sort_nodes.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/sort_nodes.js index 6b38e4d3ef3a8..d0f845a8b0ed4 100644 --- a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/sort_nodes.js +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/sort_nodes.js @@ -6,7 +6,7 @@ import { sortByOrder } from 'lodash'; export function sortNodes(nodes, sort) { - if (!sort) { + if (!sort || !sort.field) { return nodes; } diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/index.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/index.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/index.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/lookups.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/lookups.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/nodes/lookups.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/lookups.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/shards/__tests__/fixtures/cluster.json b/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/__tests__/fixtures/cluster.json similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/shards/__tests__/fixtures/cluster.json rename to x-pack/plugins/monitoring/server/lib/elasticsearch/shards/__tests__/fixtures/cluster.json diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/__tests__/fixtures/index.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/__tests__/fixtures/index.js new file mode 100644 index 0000000000000..72db17db82427 --- /dev/null +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/__tests__/fixtures/index.js @@ -0,0 +1,10 @@ +/* + * 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. + */ + +import shardStatsFixture from './shard_stats'; +import clusterFixture from './cluster'; + +export { shardStatsFixture, clusterFixture }; diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/shards/__tests__/fixtures/shard_stats.json b/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/__tests__/fixtures/shard_stats.json similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/shards/__tests__/fixtures/shard_stats.json rename to x-pack/plugins/monitoring/server/lib/elasticsearch/shards/__tests__/fixtures/shard_stats.json diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/shards/__tests__/get_shard_stats.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/__tests__/get_shard_stats.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/shards/__tests__/get_shard_stats.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/shards/__tests__/get_shard_stats.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/shards/__tests__/normalize_shard_objects.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/__tests__/normalize_shard_objects.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/shards/__tests__/normalize_shard_objects.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/shards/__tests__/normalize_shard_objects.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/shards/calculate_shard_stat_indices_totals.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/calculate_shard_stat_indices_totals.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/shards/calculate_shard_stat_indices_totals.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/shards/calculate_shard_stat_indices_totals.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/shards/get_indices_unassigned_shard_stats.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_indices_unassigned_shard_stats.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/shards/get_indices_unassigned_shard_stats.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_indices_unassigned_shard_stats.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/shards/get_indices_unassigned_shard_stats.test.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_indices_unassigned_shard_stats.test.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/shards/get_indices_unassigned_shard_stats.test.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_indices_unassigned_shard_stats.test.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/shards/get_nodes_shard_count.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_nodes_shard_count.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/shards/get_nodes_shard_count.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_nodes_shard_count.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/shards/get_nodes_shard_count.test.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_nodes_shard_count.test.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/shards/get_nodes_shard_count.test.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_nodes_shard_count.test.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_allocation.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_allocation.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_allocation.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_allocation.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_allocation.test.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_allocation.test.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_allocation.test.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_allocation.test.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_stat_aggs.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_stat_aggs.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_stat_aggs.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_stat_aggs.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_stats.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_stats.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_stats.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_stats.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/shards/get_unassigned_shards.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_unassigned_shards.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/shards/get_unassigned_shards.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_unassigned_shards.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/shards/index.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/shards/index.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/shards/index.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/shards/normalize_shard_objects.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/normalize_shard_objects.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/shards/normalize_shard_objects.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/shards/normalize_shard_objects.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/verify_ccs_availability.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/verify_ccs_availability.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/verify_ccs_availability.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/verify_ccs_availability.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/verify_monitoring_auth.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/verify_monitoring_auth.js similarity index 95% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/verify_monitoring_auth.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch/verify_monitoring_auth.js index 96a0354556093..6d2a853ee24d2 100644 --- a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch/verify_monitoring_auth.js +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/verify_monitoring_auth.js @@ -19,10 +19,10 @@ export async function verifyMonitoringAuth(req) { const xpackInfo = get(req.server.plugins.monitoring, 'info'); if (xpackInfo) { - const security = xpackInfo.feature('security'); + const security = xpackInfo.getSecurityFeature(); // we only need to verify permissions if we're using X-Pack Security - if (security.isAvailable() && security.isEnabled()) { + if (security.isAvailable && security.isEnabled) { await verifyHasPrivileges(req); } } diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch_settings/__tests__/cluster.js b/x-pack/plugins/monitoring/server/lib/elasticsearch_settings/__tests__/cluster.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch_settings/__tests__/cluster.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch_settings/__tests__/cluster.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch_settings/__tests__/find_reason.js b/x-pack/plugins/monitoring/server/lib/elasticsearch_settings/__tests__/find_reason.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch_settings/__tests__/find_reason.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch_settings/__tests__/find_reason.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch_settings/__tests__/nodes.js b/x-pack/plugins/monitoring/server/lib/elasticsearch_settings/__tests__/nodes.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch_settings/__tests__/nodes.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch_settings/__tests__/nodes.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch_settings/cluster.js b/x-pack/plugins/monitoring/server/lib/elasticsearch_settings/cluster.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch_settings/cluster.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch_settings/cluster.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch_settings/find_reason.js b/x-pack/plugins/monitoring/server/lib/elasticsearch_settings/find_reason.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch_settings/find_reason.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch_settings/find_reason.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch_settings/index.js b/x-pack/plugins/monitoring/server/lib/elasticsearch_settings/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch_settings/index.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch_settings/index.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch_settings/nodes.js b/x-pack/plugins/monitoring/server/lib/elasticsearch_settings/nodes.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch_settings/nodes.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch_settings/nodes.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch_settings/set/collection_disabled.js b/x-pack/plugins/monitoring/server/lib/elasticsearch_settings/set/collection_disabled.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch_settings/set/collection_disabled.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch_settings/set/collection_disabled.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch_settings/set/collection_enabled.js b/x-pack/plugins/monitoring/server/lib/elasticsearch_settings/set/collection_enabled.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch_settings/set/collection_enabled.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch_settings/set/collection_enabled.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/elasticsearch_settings/set/collection_interval.js b/x-pack/plugins/monitoring/server/lib/elasticsearch_settings/set/collection_interval.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/elasticsearch_settings/set/collection_interval.js rename to x-pack/plugins/monitoring/server/lib/elasticsearch_settings/set/collection_interval.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/error_missing_required.js b/x-pack/plugins/monitoring/server/lib/error_missing_required.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/error_missing_required.js rename to x-pack/plugins/monitoring/server/lib/error_missing_required.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/errors/__tests__/auth_errors.js b/x-pack/plugins/monitoring/server/lib/errors/__tests__/auth_errors.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/errors/__tests__/auth_errors.js rename to x-pack/plugins/monitoring/server/lib/errors/__tests__/auth_errors.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/errors/__tests__/known_errors.js b/x-pack/plugins/monitoring/server/lib/errors/__tests__/known_errors.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/errors/__tests__/known_errors.js rename to x-pack/plugins/monitoring/server/lib/errors/__tests__/known_errors.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/errors/auth_errors.js b/x-pack/plugins/monitoring/server/lib/errors/auth_errors.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/errors/auth_errors.js rename to x-pack/plugins/monitoring/server/lib/errors/auth_errors.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/errors/custom_errors.js b/x-pack/plugins/monitoring/server/lib/errors/custom_errors.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/errors/custom_errors.js rename to x-pack/plugins/monitoring/server/lib/errors/custom_errors.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/errors/handle_error.js b/x-pack/plugins/monitoring/server/lib/errors/handle_error.js similarity index 91% rename from x-pack/legacy/plugins/monitoring/server/lib/errors/handle_error.js rename to x-pack/plugins/monitoring/server/lib/errors/handle_error.js index 319f93d4cd190..d6549a8fa98e9 100644 --- a/x-pack/legacy/plugins/monitoring/server/lib/errors/handle_error.js +++ b/x-pack/plugins/monitoring/server/lib/errors/handle_error.js @@ -7,10 +7,9 @@ import { boomify } from 'boom'; import { isKnownError, handleKnownError } from './known_errors'; import { isAuthError, handleAuthError } from './auth_errors'; -import { LOGGING_TAG } from '../../../common/constants'; export function handleError(err, req) { - req.log(['error', LOGGING_TAG], err); + req.logger.error(err); // specially handle auth errors if (isAuthError(err)) { diff --git a/x-pack/legacy/plugins/monitoring/server/lib/errors/handle_settings_error.js b/x-pack/plugins/monitoring/server/lib/errors/handle_settings_error.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/errors/handle_settings_error.js rename to x-pack/plugins/monitoring/server/lib/errors/handle_settings_error.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/errors/index.js b/x-pack/plugins/monitoring/server/lib/errors/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/errors/index.js rename to x-pack/plugins/monitoring/server/lib/errors/index.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/errors/known_errors.js b/x-pack/plugins/monitoring/server/lib/errors/known_errors.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/errors/known_errors.js rename to x-pack/plugins/monitoring/server/lib/errors/known_errors.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/filter_partial_buckets.js b/x-pack/plugins/monitoring/server/lib/filter_partial_buckets.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/filter_partial_buckets.js rename to x-pack/plugins/monitoring/server/lib/filter_partial_buckets.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/format_timezone.js b/x-pack/plugins/monitoring/server/lib/format_timezone.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/format_timezone.js rename to x-pack/plugins/monitoring/server/lib/format_timezone.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/get_timezone.js b/x-pack/plugins/monitoring/server/lib/get_timezone.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/get_timezone.js rename to x-pack/plugins/monitoring/server/lib/get_timezone.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/kibana/__tests__/get_kibana_info.js b/x-pack/plugins/monitoring/server/lib/kibana/__tests__/get_kibana_info.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/kibana/__tests__/get_kibana_info.js rename to x-pack/plugins/monitoring/server/lib/kibana/__tests__/get_kibana_info.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/kibana/get_kibana_info.js b/x-pack/plugins/monitoring/server/lib/kibana/get_kibana_info.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/kibana/get_kibana_info.js rename to x-pack/plugins/monitoring/server/lib/kibana/get_kibana_info.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/kibana/get_kibanas.js b/x-pack/plugins/monitoring/server/lib/kibana/get_kibanas.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/kibana/get_kibanas.js rename to x-pack/plugins/monitoring/server/lib/kibana/get_kibanas.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/kibana/get_kibanas_for_clusters.js b/x-pack/plugins/monitoring/server/lib/kibana/get_kibanas_for_clusters.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/kibana/get_kibanas_for_clusters.js rename to x-pack/plugins/monitoring/server/lib/kibana/get_kibanas_for_clusters.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/kibana/index.js b/x-pack/plugins/monitoring/server/lib/kibana/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/kibana/index.js rename to x-pack/plugins/monitoring/server/lib/kibana/index.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/logs/detect_reason.js b/x-pack/plugins/monitoring/server/lib/logs/detect_reason.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/logs/detect_reason.js rename to x-pack/plugins/monitoring/server/lib/logs/detect_reason.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/logs/detect_reason_from_exception.js b/x-pack/plugins/monitoring/server/lib/logs/detect_reason_from_exception.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/logs/detect_reason_from_exception.js rename to x-pack/plugins/monitoring/server/lib/logs/detect_reason_from_exception.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/logs/get_log_types.js b/x-pack/plugins/monitoring/server/lib/logs/get_log_types.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/logs/get_log_types.js rename to x-pack/plugins/monitoring/server/lib/logs/get_log_types.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/logs/get_logs.js b/x-pack/plugins/monitoring/server/lib/logs/get_logs.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/logs/get_logs.js rename to x-pack/plugins/monitoring/server/lib/logs/get_logs.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/logs/index.js b/x-pack/plugins/monitoring/server/lib/logs/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/logs/index.js rename to x-pack/plugins/monitoring/server/lib/logs/index.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/logs/init_infra_source.js b/x-pack/plugins/monitoring/server/lib/logs/init_infra_source.ts similarity index 63% rename from x-pack/legacy/plugins/monitoring/server/lib/logs/init_infra_source.js rename to x-pack/plugins/monitoring/server/lib/logs/init_infra_source.ts index 7ca36e8b29553..b6be7bbe13985 100644 --- a/x-pack/legacy/plugins/monitoring/server/lib/logs/init_infra_source.js +++ b/x-pack/plugins/monitoring/server/lib/logs/init_infra_source.ts @@ -4,16 +4,15 @@ * you may not use this file except in compliance with the Elastic License. */ +// @ts-ignore import { prefixIndexPattern } from '../ccs_utils'; import { INFRA_SOURCE_ID } from '../../../common/constants'; +import { MonitoringConfig } from '../../config'; +import { InfraPluginSetup } from '../../../../infra/server'; -export const initInfraSource = (config, infraPlugin) => { +export const initInfraSource = (config: MonitoringConfig, infraPlugin: InfraPluginSetup) => { if (infraPlugin) { - const filebeatIndexPattern = prefixIndexPattern( - config, - config.get('monitoring.ui.logs.index'), - '*' - ); + const filebeatIndexPattern = prefixIndexPattern(config, config.ui.logs.index, '*'); infraPlugin.defineInternalSourceConfiguration(INFRA_SOURCE_ID, { name: 'Elastic Stack Logs', logAlias: filebeatIndexPattern, diff --git a/x-pack/legacy/plugins/monitoring/server/lib/logstash/__tests__/get_node_info.js b/x-pack/plugins/monitoring/server/lib/logstash/__tests__/get_node_info.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/logstash/__tests__/get_node_info.js rename to x-pack/plugins/monitoring/server/lib/logstash/__tests__/get_node_info.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/logstash/__tests__/get_pipeline.js b/x-pack/plugins/monitoring/server/lib/logstash/__tests__/get_pipeline.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/logstash/__tests__/get_pipeline.js rename to x-pack/plugins/monitoring/server/lib/logstash/__tests__/get_pipeline.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/logstash/get_cluster_status.js b/x-pack/plugins/monitoring/server/lib/logstash/get_cluster_status.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/logstash/get_cluster_status.js rename to x-pack/plugins/monitoring/server/lib/logstash/get_cluster_status.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/logstash/get_logstash_for_clusters.js b/x-pack/plugins/monitoring/server/lib/logstash/get_logstash_for_clusters.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/logstash/get_logstash_for_clusters.js rename to x-pack/plugins/monitoring/server/lib/logstash/get_logstash_for_clusters.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/logstash/get_node_info.js b/x-pack/plugins/monitoring/server/lib/logstash/get_node_info.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/logstash/get_node_info.js rename to x-pack/plugins/monitoring/server/lib/logstash/get_node_info.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/logstash/get_nodes.js b/x-pack/plugins/monitoring/server/lib/logstash/get_nodes.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/logstash/get_nodes.js rename to x-pack/plugins/monitoring/server/lib/logstash/get_nodes.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/logstash/get_paginated_pipelines.js b/x-pack/plugins/monitoring/server/lib/logstash/get_paginated_pipelines.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/logstash/get_paginated_pipelines.js rename to x-pack/plugins/monitoring/server/lib/logstash/get_paginated_pipelines.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/logstash/get_pipeline.js b/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/logstash/get_pipeline.js rename to x-pack/plugins/monitoring/server/lib/logstash/get_pipeline.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/logstash/get_pipeline_ids.js b/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_ids.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/logstash/get_pipeline_ids.js rename to x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_ids.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/logstash/get_pipeline_state_document.js b/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_state_document.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/logstash/get_pipeline_state_document.js rename to x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_state_document.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/logstash/get_pipeline_stats_aggregation.js b/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_stats_aggregation.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/logstash/get_pipeline_stats_aggregation.js rename to x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_stats_aggregation.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/logstash/get_pipeline_versions.js b/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_versions.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/logstash/get_pipeline_versions.js rename to x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_versions.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/logstash/get_pipeline_vertex.js b/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_vertex.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/logstash/get_pipeline_vertex.js rename to x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_vertex.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/logstash/get_pipeline_vertex_stats_aggregation.js b/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_vertex_stats_aggregation.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/logstash/get_pipeline_vertex_stats_aggregation.js rename to x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_vertex_stats_aggregation.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/logstash/index.js b/x-pack/plugins/monitoring/server/lib/logstash/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/logstash/index.js rename to x-pack/plugins/monitoring/server/lib/logstash/index.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/logstash/sort_pipelines.js b/x-pack/plugins/monitoring/server/lib/logstash/sort_pipelines.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/logstash/sort_pipelines.js rename to x-pack/plugins/monitoring/server/lib/logstash/sort_pipelines.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/metrics/__test__/__snapshots__/metrics.test.js.snap b/x-pack/plugins/monitoring/server/lib/metrics/__test__/__snapshots__/metrics.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/metrics/__test__/__snapshots__/metrics.test.js.snap rename to x-pack/plugins/monitoring/server/lib/metrics/__test__/__snapshots__/metrics.test.js.snap diff --git a/x-pack/legacy/plugins/monitoring/server/lib/metrics/__test__/metrics.test.js b/x-pack/plugins/monitoring/server/lib/metrics/__test__/metrics.test.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/metrics/__test__/metrics.test.js rename to x-pack/plugins/monitoring/server/lib/metrics/__test__/metrics.test.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/metrics/apm/classes.js b/x-pack/plugins/monitoring/server/lib/metrics/apm/classes.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/metrics/apm/classes.js rename to x-pack/plugins/monitoring/server/lib/metrics/apm/classes.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/metrics/apm/metrics.js b/x-pack/plugins/monitoring/server/lib/metrics/apm/metrics.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/metrics/apm/metrics.js rename to x-pack/plugins/monitoring/server/lib/metrics/apm/metrics.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/metrics/beats/__test__/cpu_utilization_calculation.test.js b/x-pack/plugins/monitoring/server/lib/metrics/beats/__test__/cpu_utilization_calculation.test.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/metrics/beats/__test__/cpu_utilization_calculation.test.js rename to x-pack/plugins/monitoring/server/lib/metrics/beats/__test__/cpu_utilization_calculation.test.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/metrics/beats/classes.js b/x-pack/plugins/monitoring/server/lib/metrics/beats/classes.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/metrics/beats/classes.js rename to x-pack/plugins/monitoring/server/lib/metrics/beats/classes.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/metrics/beats/metrics.js b/x-pack/plugins/monitoring/server/lib/metrics/beats/metrics.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/metrics/beats/metrics.js rename to x-pack/plugins/monitoring/server/lib/metrics/beats/metrics.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/metrics/classes/__test__/latency_metric_calculation.test.js b/x-pack/plugins/monitoring/server/lib/metrics/classes/__test__/latency_metric_calculation.test.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/metrics/classes/__test__/latency_metric_calculation.test.js rename to x-pack/plugins/monitoring/server/lib/metrics/classes/__test__/latency_metric_calculation.test.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/metrics/classes/__test__/quota_metric_calculation.test.js b/x-pack/plugins/monitoring/server/lib/metrics/classes/__test__/quota_metric_calculation.test.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/metrics/classes/__test__/quota_metric_calculation.test.js rename to x-pack/plugins/monitoring/server/lib/metrics/classes/__test__/quota_metric_calculation.test.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/metrics/classes/cluster_metric.js b/x-pack/plugins/monitoring/server/lib/metrics/classes/cluster_metric.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/metrics/classes/cluster_metric.js rename to x-pack/plugins/monitoring/server/lib/metrics/classes/cluster_metric.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/metrics/classes/index.js b/x-pack/plugins/monitoring/server/lib/metrics/classes/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/metrics/classes/index.js rename to x-pack/plugins/monitoring/server/lib/metrics/classes/index.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/metrics/classes/metric.js b/x-pack/plugins/monitoring/server/lib/metrics/classes/metric.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/metrics/classes/metric.js rename to x-pack/plugins/monitoring/server/lib/metrics/classes/metric.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/metrics/classes/quota_metric.js b/x-pack/plugins/monitoring/server/lib/metrics/classes/quota_metric.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/metrics/classes/quota_metric.js rename to x-pack/plugins/monitoring/server/lib/metrics/classes/quota_metric.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/metrics/elasticsearch/__test__/latency_calculation.test.js b/x-pack/plugins/monitoring/server/lib/metrics/elasticsearch/__test__/latency_calculation.test.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/metrics/elasticsearch/__test__/latency_calculation.test.js rename to x-pack/plugins/monitoring/server/lib/metrics/elasticsearch/__test__/latency_calculation.test.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/metrics/elasticsearch/classes.js b/x-pack/plugins/monitoring/server/lib/metrics/elasticsearch/classes.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/metrics/elasticsearch/classes.js rename to x-pack/plugins/monitoring/server/lib/metrics/elasticsearch/classes.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/metrics/elasticsearch/metrics.js b/x-pack/plugins/monitoring/server/lib/metrics/elasticsearch/metrics.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/metrics/elasticsearch/metrics.js rename to x-pack/plugins/monitoring/server/lib/metrics/elasticsearch/metrics.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/metrics/index.js b/x-pack/plugins/monitoring/server/lib/metrics/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/metrics/index.js rename to x-pack/plugins/monitoring/server/lib/metrics/index.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/metrics/kibana/classes.js b/x-pack/plugins/monitoring/server/lib/metrics/kibana/classes.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/metrics/kibana/classes.js rename to x-pack/plugins/monitoring/server/lib/metrics/kibana/classes.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/metrics/kibana/metrics.js b/x-pack/plugins/monitoring/server/lib/metrics/kibana/metrics.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/metrics/kibana/metrics.js rename to x-pack/plugins/monitoring/server/lib/metrics/kibana/metrics.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/metrics/logstash/classes.js b/x-pack/plugins/monitoring/server/lib/metrics/logstash/classes.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/metrics/logstash/classes.js rename to x-pack/plugins/monitoring/server/lib/metrics/logstash/classes.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/metrics/logstash/metrics.js b/x-pack/plugins/monitoring/server/lib/metrics/logstash/metrics.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/metrics/logstash/metrics.js rename to x-pack/plugins/monitoring/server/lib/metrics/logstash/metrics.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/metrics/metrics.js b/x-pack/plugins/monitoring/server/lib/metrics/metrics.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/metrics/metrics.js rename to x-pack/plugins/monitoring/server/lib/metrics/metrics.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/normalize_version_string.js b/x-pack/plugins/monitoring/server/lib/normalize_version_string.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/normalize_version_string.js rename to x-pack/plugins/monitoring/server/lib/normalize_version_string.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/pagination/filter.js b/x-pack/plugins/monitoring/server/lib/pagination/filter.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/pagination/filter.js rename to x-pack/plugins/monitoring/server/lib/pagination/filter.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/pagination/paginate.js b/x-pack/plugins/monitoring/server/lib/pagination/paginate.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/pagination/paginate.js rename to x-pack/plugins/monitoring/server/lib/pagination/paginate.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/setup/collection/__test__/get_collection_status.test.js b/x-pack/plugins/monitoring/server/lib/setup/collection/__test__/get_collection_status.test.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/setup/collection/__test__/get_collection_status.test.js rename to x-pack/plugins/monitoring/server/lib/setup/collection/__test__/get_collection_status.test.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/setup/collection/get_collection_status.js b/x-pack/plugins/monitoring/server/lib/setup/collection/get_collection_status.js similarity index 98% rename from x-pack/legacy/plugins/monitoring/server/lib/setup/collection/get_collection_status.js rename to x-pack/plugins/monitoring/server/lib/setup/collection/get_collection_status.js index 0029aaa9ce8ee..22fd117595a84 100644 --- a/x-pack/legacy/plugins/monitoring/server/lib/setup/collection/get_collection_status.js +++ b/x-pack/plugins/monitoring/server/lib/setup/collection/get_collection_status.js @@ -12,15 +12,15 @@ import { KIBANA_SYSTEM_ID, BEATS_SYSTEM_ID, LOGSTASH_SYSTEM_ID, + KIBANA_STATS_TYPE_MONITORING, } from '../../../../common/constants'; import { getLivesNodes } from '../../elasticsearch/nodes/get_nodes/get_live_nodes'; -import { KIBANA_STATS_TYPE } from '../../../../../../../../src/legacy/server/status/constants'; const NUMBER_OF_SECONDS_AGO_TO_LOOK = 30; const getRecentMonitoringDocuments = async (req, indexPatterns, clusterUuid, nodeUuid) => { - const start = get(req.payload, 'timeRange.min', `now-${NUMBER_OF_SECONDS_AGO_TO_LOOK}s`); - const end = get(req.payload, 'timeRange.max', 'now'); + const start = get(req.payload, 'timeRange.min') || `now-${NUMBER_OF_SECONDS_AGO_TO_LOOK}s`; + const end = get(req.payload, 'timeRange.max') || 'now'; const filters = [ { @@ -274,7 +274,7 @@ async function getLiveKibanaInstance(usageCollection) { if (!usageCollection) { return null; } - const kibanaStatsCollector = usageCollection.getCollectorByType(KIBANA_STATS_TYPE); + const kibanaStatsCollector = usageCollection.getCollectorByType(KIBANA_STATS_TYPE_MONITORING); if (!(await kibanaStatsCollector.isReady())) { return null; } diff --git a/x-pack/legacy/plugins/monitoring/server/lib/setup/collection/index.js b/x-pack/plugins/monitoring/server/lib/setup/collection/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/setup/collection/index.js rename to x-pack/plugins/monitoring/server/lib/setup/collection/index.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/standalone_clusters/get_standalone_cluster_definition.js b/x-pack/plugins/monitoring/server/lib/standalone_clusters/get_standalone_cluster_definition.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/standalone_clusters/get_standalone_cluster_definition.js rename to x-pack/plugins/monitoring/server/lib/standalone_clusters/get_standalone_cluster_definition.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/standalone_clusters/has_standalone_clusters.js b/x-pack/plugins/monitoring/server/lib/standalone_clusters/has_standalone_clusters.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/standalone_clusters/has_standalone_clusters.js rename to x-pack/plugins/monitoring/server/lib/standalone_clusters/has_standalone_clusters.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/standalone_clusters/index.js b/x-pack/plugins/monitoring/server/lib/standalone_clusters/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/standalone_clusters/index.js rename to x-pack/plugins/monitoring/server/lib/standalone_clusters/index.js diff --git a/x-pack/legacy/plugins/monitoring/server/lib/standalone_clusters/standalone_cluster_query_filter.js b/x-pack/plugins/monitoring/server/lib/standalone_clusters/standalone_cluster_query_filter.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/lib/standalone_clusters/standalone_cluster_query_filter.js rename to x-pack/plugins/monitoring/server/lib/standalone_clusters/standalone_cluster_query_filter.js diff --git a/x-pack/plugins/monitoring/server/license_service.ts b/x-pack/plugins/monitoring/server/license_service.ts new file mode 100644 index 0000000000000..01746a550ced6 --- /dev/null +++ b/x-pack/plugins/monitoring/server/license_service.ts @@ -0,0 +1,59 @@ +/* + * 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. + */ +import { Subscription } from 'rxjs'; +import { ICustomClusterClient } from 'kibana/server'; +import { ILicense, LicenseFeature } from '../../licensing/common/types'; +import { LicensingPluginSetup } from '../../licensing/server'; +import { MonitoringConfig } from './config'; +import { Logger } from '../../../../src/core/server'; +import { MonitoringLicenseService } from './types'; + +interface SetupDeps { + licensing: LicensingPluginSetup; + monitoringClient: ICustomClusterClient; + config: MonitoringConfig; + log: Logger; +} + +const defaultLicenseFeature: LicenseFeature = { + isAvailable: false, + isEnabled: false, +}; + +export class LicenseService { + public setup({ licensing, monitoringClient, config, log }: SetupDeps): MonitoringLicenseService { + const { refresh, license$ } = licensing.createLicensePoller( + monitoringClient, + config.licensing.api_polling_frequency.asMilliseconds() + ); + + let rawLicense: Readonly | undefined; + let licenseSubscription: Subscription | undefined = license$.subscribe(nextRawLicense => { + rawLicense = nextRawLicense; + }); + + if (!rawLicense?.isAvailable) { + log.warn( + `X-Pack Monitoring Cluster Alerts will not be available: ${rawLicense?.getUnavailableReason()}` + ); + } + + return { + refresh, + license$, + getMessage: () => rawLicense?.getUnavailableReason() || 'N/A', + getMonitoringFeature: () => rawLicense?.getFeature('monitoring') || defaultLicenseFeature, + getWatcherFeature: () => rawLicense?.getFeature('monitoring') || defaultLicenseFeature, + getSecurityFeature: () => rawLicense?.getFeature('security') || defaultLicenseFeature, + stop: () => { + if (licenseSubscription) { + licenseSubscription.unsubscribe(); + licenseSubscription = undefined; + } + }, + }; + } +} diff --git a/x-pack/plugins/monitoring/server/plugin.ts b/x-pack/plugins/monitoring/server/plugin.ts new file mode 100644 index 0000000000000..bd1455a2c582f --- /dev/null +++ b/x-pack/plugins/monitoring/server/plugin.ts @@ -0,0 +1,378 @@ +/* + * 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. + */ +import Boom from 'boom'; +import { combineLatest } from 'rxjs'; +import { first } from 'rxjs/operators'; +import { i18n } from '@kbn/i18n'; +import { has, get } from 'lodash'; +import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; +import { TelemetryCollectionManager } from 'src/legacy/core_plugins/telemetry/server/collection_manager'; +import { + LOGGING_TAG, + KIBANA_MONITORING_LOGGING_TAG, + KIBANA_ALERTING_ENABLED, + KIBANA_STATS_TYPE_MONITORING, +} from '../common/constants'; +import { + Logger, + PluginInitializerContext, + RequestHandlerContext, + KibanaRequest, + KibanaResponseFactory, + CoreSetup, + ICustomClusterClient, + CoreStart, + IRouter, + IClusterClient, +} from '../../../../src/core/server'; +import { MonitoringConfig } from './config'; +// @ts-ignore +import { requireUIRoutes } from './routes'; +// @ts-ignore +import { initBulkUploader } from './kibana_monitoring'; +// @ts-ignore +import { initInfraSource } from './lib/logs/init_infra_source'; +import { instantiateClient } from './es_client/instantiate_client'; +import { registerCollectors } from './kibana_monitoring/collectors'; +import { registerMonitoringCollection } from './telemetry_collection'; +import { LicensingPluginSetup } from '../../licensing/server'; +import { PluginSetupContract as FeaturesPluginSetupContract } from '../../features/server'; +import { LicenseService } from './license_service'; +import { MonitoringLicenseService } from './types'; +import { + PluginStartContract as AlertingPluginStartContract, + PluginSetupContract as AlertingPluginSetupContract, +} from '../../alerting/server'; +import { getLicenseExpiration } from './alerts/license_expiration'; +import { InfraPluginSetup } from '../../infra/server'; + +export interface LegacyAPI { + telemetryCollectionManager: TelemetryCollectionManager; + getServerStatus: () => string; + infra: any; +} + +interface PluginsSetup { + usageCollection: UsageCollectionSetup; + licensing: LicensingPluginSetup; + features: FeaturesPluginSetupContract; + alerting: AlertingPluginSetupContract; + infra: InfraPluginSetup; +} + +interface PluginsStart { + alerting: AlertingPluginStartContract; +} + +interface MonitoringCoreConfig { + get: (key: string) => string | undefined; +} + +interface MonitoringCore { + config: () => MonitoringCoreConfig; + log: Logger; + route: (options: any) => void; +} + +interface LegacyShimDependencies { + router: IRouter; + instanceUuid: string; + esDataClient: IClusterClient; + kibanaStatsCollector: any; +} + +interface IBulkUploader { + setKibanaStatusGetter: (getter: () => string | undefined) => void; + getKibanaStats: () => any; +} + +// This is used to test the version of kibana +const snapshotRegex = /-snapshot/i; + +export class Plugin { + private readonly initializerContext: PluginInitializerContext; + private readonly log: Logger; + private readonly getLogger: (...scopes: string[]) => Logger; + private cluster = {} as ICustomClusterClient; + private licenseService = {} as MonitoringLicenseService; + private monitoringCore = {} as MonitoringCore; + private legacyShimDependencies = {} as LegacyShimDependencies; + private bulkUploader = {} as IBulkUploader; + + constructor(initializerContext: PluginInitializerContext) { + this.initializerContext = initializerContext; + this.log = initializerContext.logger.get(LOGGING_TAG); + this.getLogger = (...scopes: string[]) => initializerContext.logger.get(LOGGING_TAG, ...scopes); + } + + async setup(core: CoreSetup, plugins: PluginsSetup) { + const [config, legacyConfig] = await combineLatest([ + this.initializerContext.config.create(), + this.initializerContext.config.legacy.globalConfig$, + ]) + .pipe(first()) + .toPromise(); + + this.legacyShimDependencies = { + router: core.http.createRouter(), + instanceUuid: core.uuid.getInstanceUuid(), + esDataClient: core.elasticsearch.dataClient, + kibanaStatsCollector: plugins.usageCollection.getCollectorByType( + KIBANA_STATS_TYPE_MONITORING + ), + }; + + // Monitoring creates and maintains a connection to a potentially + // separate ES cluster - create this first + const cluster = (this.cluster = instantiateClient( + config.ui.elasticsearch, + this.log, + core.elasticsearch.createClient + )); + + // Start our license service which will ensure + // the appropriate licenses are present + this.licenseService = new LicenseService().setup({ + licensing: plugins.licensing, + monitoringClient: cluster, + config, + log: this.log, + }); + await this.licenseService.refresh(); + + if (KIBANA_ALERTING_ENABLED) { + plugins.alerting.registerType( + getLicenseExpiration( + async () => { + const coreStart = (await core.getStartServices())[0]; + return coreStart.uiSettings; + }, + cluster, + this.getLogger, + config.ui.ccs.enabled + ) + ); + } + + // Register collector objects for stats to show up in the APIs + registerCollectors( + plugins.usageCollection, + config, + core.metrics.getOpsMetrics$(), + get(legacyConfig, 'kibana.index') + ); + + // If collection is enabled, create the bulk uploader + const kibanaMonitoringLog = this.getLogger(KIBANA_MONITORING_LOGGING_TAG); + const kibanaCollectionEnabled = config.kibana.collection.enabled; + if (kibanaCollectionEnabled) { + // Start kibana internal collection + const serverInfo = core.http.getServerInfo(); + const bulkUploader = (this.bulkUploader = initBulkUploader({ + elasticsearch: core.elasticsearch, + config, + log: kibanaMonitoringLog, + kibanaStats: { + uuid: core.uuid.getInstanceUuid(), + name: serverInfo.name, + index: get(legacyConfig, 'kibana.index'), + host: serverInfo.host, + transport_address: `${serverInfo.host}:${serverInfo.port}`, + port: serverInfo.port.toString(), + version: this.initializerContext.env.packageInfo.version, + snapshot: snapshotRegex.test(this.initializerContext.env.packageInfo.version), + }, + })); + + // Do not use `this.licenseService` as that looks at the monitoring cluster + // whereas we want to check the production cluster here + if (plugins.licensing) { + plugins.licensing.license$.subscribe((license: any) => { + // use updated xpack license info to start/stop bulk upload + const mainMonitoring = license.getFeature('monitoring'); + const monitoringBulkEnabled = + mainMonitoring && mainMonitoring.isAvailable && mainMonitoring.isEnabled; + if (monitoringBulkEnabled) { + bulkUploader.start(plugins.usageCollection); + } else { + bulkUploader.handleNotEnabled(); + } + }); + } + } else { + kibanaMonitoringLog.info( + 'Internal collection for Kibana monitoring is disabled per configuration.' + ); + } + + // If the UI is enabled, then we want to register it so it shows up + // and start any other UI-related setup tasks + if (config.ui.enabled) { + // Create our shim which is currently used to power our routing + this.monitoringCore = this.getLegacyShim( + config, + legacyConfig, + core.getStartServices as () => Promise<[CoreStart, PluginsStart]>, + this.licenseService, + this.cluster + ); + + this.registerPluginInUI(plugins); + requireUIRoutes(this.monitoringCore); + initInfraSource(config, plugins.infra); + } + + return { + // The legacy plugin calls this to register certain legacy dependencies + // that are necessary for the plugin to properly run + registerLegacyAPI: (legacyAPI: LegacyAPI) => { + this.setupLegacy(legacyAPI); + }, + // OSS stats api needs to call this in order to centralize how + // we fetch kibana specific stats + getKibanaStats: () => this.bulkUploader.getKibanaStats(), + }; + } + + start() {} + + stop() { + if (this.cluster) { + this.cluster.close(); + } + if (this.licenseService) { + this.licenseService.stop(); + } + } + + registerPluginInUI(plugins: PluginsSetup) { + plugins.features.registerFeature({ + id: 'monitoring', + name: i18n.translate('xpack.monitoring.featureRegistry.monitoringFeatureName', { + defaultMessage: 'Stack Monitoring', + }), + icon: 'monitoringApp', + navLinkId: 'monitoring', + app: ['monitoring', 'kibana'], + catalogue: ['monitoring'], + privileges: {}, + reserved: { + privilege: { + savedObject: { + all: [], + read: [], + }, + ui: [], + }, + description: i18n.translate('xpack.monitoring.feature.reserved.description', { + defaultMessage: 'To grant users access, you should also assign the monitoring_user role.', + }), + }, + }); + } + + async setupLegacy(legacyAPI: LegacyAPI) { + // Initialize telemetry + registerMonitoringCollection(this.cluster, legacyAPI.telemetryCollectionManager); + + // Set the stats getter + this.bulkUploader.setKibanaStatusGetter(() => legacyAPI.getServerStatus()); + } + + getLegacyShim( + config: MonitoringConfig, + legacyConfig: any, + getCoreServices: () => Promise<[CoreStart, PluginsStart]>, + licenseService: MonitoringLicenseService, + cluster: ICustomClusterClient + ): MonitoringCore { + const router = this.legacyShimDependencies.router; + const legacyConfigWrapper = () => ({ + get: (_key: string): string | undefined => { + const key = _key.includes('monitoring.') ? _key.split('monitoring.')[1] : _key; + if (has(config, key)) { + return get(config, key); + } + if (has(legacyConfig, key)) { + return get(legacyConfig, key); + } + + if (key === 'server.uuid') { + return this.legacyShimDependencies.instanceUuid; + } + + throw new Error(`Unknown key '${_key}'`); + }, + }); + return { + config: legacyConfigWrapper, + log: this.log, + route: (options: any) => { + const method = options.method; + const handler = async ( + context: RequestHandlerContext, + req: KibanaRequest, + res: KibanaResponseFactory + ) => { + const plugins = (await getCoreServices())[1]; + const legacyRequest = { + ...req, + logger: this.log, + getLogger: this.getLogger, + payload: req.body, + getKibanaStatsCollector: () => this.legacyShimDependencies.kibanaStatsCollector, + getUiSettingsService: () => context.core.uiSettings.client, + getAlertsClient: () => plugins.alerting.getAlertsClientWithRequest(req), + server: { + config: legacyConfigWrapper, + newPlatform: { + setup: { + plugins, + }, + }, + plugins: { + monitoring: { + info: licenseService, + }, + elasticsearch: { + getCluster: (name: string) => ({ + callWithRequest: async (_req: any, endpoint: string, params: any) => { + const client = + name === 'monitoring' ? cluster : this.legacyShimDependencies.esDataClient; + return client.asScoped(req).callAsCurrentUser(endpoint, params); + }, + }), + }, + }, + }, + }; + + const result = await options.handler(legacyRequest); + if (Boom.isBoom(result)) { + return res.customError({ statusCode: result.output.statusCode, body: result }); + } + return res.ok({ body: result }); + }; + + const validate: any = get(options, 'config.validate', false); + if (validate && validate.payload) { + validate.body = validate.payload; + } + options.validate = validate; + + if (method === 'POST') { + router.post(options, handler); + } else if (method === 'GET') { + router.get(options, handler); + } else if (method === 'PUT') { + router.put(options, handler); + } else { + throw new Error('Unsupport API method: ' + method); + } + }, + }; + } +} diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/alerts/alerts.js b/x-pack/plugins/monitoring/server/routes/api/v1/alerts/alerts.js similarity index 93% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/alerts/alerts.js rename to x-pack/plugins/monitoring/server/routes/api/v1/alerts/alerts.js index f87683effe437..56922bd8e87e2 100644 --- a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/alerts/alerts.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/alerts/alerts.js @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import Joi from 'joi'; +import { schema } from '@kbn/config-schema'; import { isFunction } from 'lodash'; import { ALERT_TYPE_LICENSE_EXPIRATION, @@ -65,9 +65,9 @@ export function createKibanaAlertsRoute(server) { path: '/api/monitoring/v1/alerts', config: { validate: { - payload: Joi.object({ - selectedEmailActionId: Joi.string().required(), - emailAddress: Joi.string().required(), + payload: schema.object({ + selectedEmailActionId: schema.string(), + emailAddress: schema.string(), }), }, }, diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/alerts/index.js b/x-pack/plugins/monitoring/server/routes/api/v1/alerts/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/alerts/index.js rename to x-pack/plugins/monitoring/server/routes/api/v1/alerts/index.js diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/alerts/legacy_alerts.js b/x-pack/plugins/monitoring/server/routes/api/v1/alerts/legacy_alerts.js similarity index 83% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/alerts/legacy_alerts.js rename to x-pack/plugins/monitoring/server/routes/api/v1/alerts/legacy_alerts.js index a3049f0f3e2d2..14f3ca8b5cb55 100644 --- a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/alerts/legacy_alerts.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/alerts/legacy_alerts.js @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import Joi from 'joi'; +import { schema } from '@kbn/config-schema'; import { alertsClusterSearch } from '../../../../cluster_alerts/alerts_cluster_search'; import { checkLicense } from '../../../../cluster_alerts/check_license'; import { getClusterLicense } from '../../../../lib/cluster/get_cluster_license'; @@ -20,15 +20,15 @@ export function legacyClusterAlertsRoute(server) { path: '/api/monitoring/v1/clusters/{clusterUuid}/legacy_alerts', config: { validate: { - params: Joi.object({ - clusterUuid: Joi.string().required(), + params: schema.object({ + clusterUuid: schema.string(), }), - payload: Joi.object({ - ccs: Joi.string().optional(), - timeRange: Joi.object({ - min: Joi.date().required(), - max: Joi.date().required(), - }).required(), + payload: schema.object({ + ccs: schema.maybe(schema.string()), + timeRange: schema.object({ + min: schema.string(), + max: schema.string(), + }), }), }, }, diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/apm/_get_apm_cluster_status.js b/x-pack/plugins/monitoring/server/routes/api/v1/apm/_get_apm_cluster_status.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/apm/_get_apm_cluster_status.js rename to x-pack/plugins/monitoring/server/routes/api/v1/apm/_get_apm_cluster_status.js diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/apm/index.js b/x-pack/plugins/monitoring/server/routes/api/v1/apm/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/apm/index.js rename to x-pack/plugins/monitoring/server/routes/api/v1/apm/index.js diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/apm/instance.js b/x-pack/plugins/monitoring/server/routes/api/v1/apm/instance.js similarity index 81% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/apm/instance.js rename to x-pack/plugins/monitoring/server/routes/api/v1/apm/instance.js index 4be5fc6719e6c..0ff9e834b924c 100644 --- a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/apm/instance.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/apm/instance.js @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import Joi from 'joi'; +import { schema } from '@kbn/config-schema'; import { prefixIndexPattern } from '../../../../lib/ccs_utils'; import { getMetrics } from '../../../../lib/details/get_metrics'; import { metricSet } from './metric_set_overview'; @@ -18,16 +18,16 @@ export function apmInstanceRoute(server) { path: '/api/monitoring/v1/clusters/{clusterUuid}/apm/{apmUuid}', config: { validate: { - params: Joi.object({ - clusterUuid: Joi.string().required(), - apmUuid: Joi.string().required(), + params: schema.object({ + clusterUuid: schema.string(), + apmUuid: schema.string(), }), - payload: Joi.object({ - ccs: Joi.string().optional(), - timeRange: Joi.object({ - min: Joi.date().required(), - max: Joi.date().required(), - }).required(), + payload: schema.object({ + ccs: schema.maybe(schema.string()), + timeRange: schema.object({ + min: schema.string(), + max: schema.string(), + }), }), }, }, diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/apm/instances.js b/x-pack/plugins/monitoring/server/routes/api/v1/apm/instances.js similarity index 80% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/apm/instances.js rename to x-pack/plugins/monitoring/server/routes/api/v1/apm/instances.js index f3c3c42f83985..7083e2600bee9 100644 --- a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/apm/instances.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/apm/instances.js @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import Joi from 'joi'; +import { schema } from '@kbn/config-schema'; import { prefixIndexPattern } from '../../../../lib/ccs_utils'; import { getStats, getApms } from '../../../../lib/apm'; import { handleError } from '../../../../lib/errors'; @@ -16,15 +16,15 @@ export function apmInstancesRoute(server) { path: '/api/monitoring/v1/clusters/{clusterUuid}/apm/instances', config: { validate: { - params: Joi.object({ - clusterUuid: Joi.string().required(), + params: schema.object({ + clusterUuid: schema.string(), }), - payload: Joi.object({ - ccs: Joi.string().optional(), - timeRange: Joi.object({ - min: Joi.date().required(), - max: Joi.date().required(), - }).required(), + payload: schema.object({ + ccs: schema.maybe(schema.string()), + timeRange: schema.object({ + min: schema.string(), + max: schema.string(), + }), }), }, }, diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/apm/metric_set_instance.js b/x-pack/plugins/monitoring/server/routes/api/v1/apm/metric_set_instance.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/apm/metric_set_instance.js rename to x-pack/plugins/monitoring/server/routes/api/v1/apm/metric_set_instance.js diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/apm/metric_set_overview.js b/x-pack/plugins/monitoring/server/routes/api/v1/apm/metric_set_overview.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/apm/metric_set_overview.js rename to x-pack/plugins/monitoring/server/routes/api/v1/apm/metric_set_overview.js diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/apm/overview.js b/x-pack/plugins/monitoring/server/routes/api/v1/apm/overview.js similarity index 81% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/apm/overview.js rename to x-pack/plugins/monitoring/server/routes/api/v1/apm/overview.js index 7f12a9cac8412..f2dfa0b450769 100644 --- a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/apm/overview.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/apm/overview.js @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import Joi from 'joi'; +import { schema } from '@kbn/config-schema'; import { prefixIndexPattern } from '../../../../lib/ccs_utils'; import { getMetrics } from '../../../../lib/details/get_metrics'; import { metricSet } from './metric_set_overview'; @@ -18,15 +18,15 @@ export function apmOverviewRoute(server) { path: '/api/monitoring/v1/clusters/{clusterUuid}/apm', config: { validate: { - params: Joi.object({ - clusterUuid: Joi.string().required(), + params: schema.object({ + clusterUuid: schema.string(), }), - payload: Joi.object({ - ccs: Joi.string().optional(), - timeRange: Joi.object({ - min: Joi.date().required(), - max: Joi.date().required(), - }).required(), + payload: schema.object({ + ccs: schema.maybe(schema.string()), + timeRange: schema.object({ + min: schema.string(), + max: schema.string(), + }), }), }, }, diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/beats/beat_detail.js b/x-pack/plugins/monitoring/server/routes/api/v1/beats/beat_detail.js similarity index 82% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/beats/beat_detail.js rename to x-pack/plugins/monitoring/server/routes/api/v1/beats/beat_detail.js index 638795fd6b647..6f2c3b5f6f213 100644 --- a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/beats/beat_detail.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/beats/beat_detail.js @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import Joi from 'joi'; +import { schema } from '@kbn/config-schema'; import { prefixIndexPattern } from '../../../../lib/ccs_utils'; import { getBeatSummary } from '../../../../lib/beats'; import { getMetrics } from '../../../../lib/details/get_metrics'; @@ -18,16 +18,16 @@ export function beatsDetailRoute(server) { path: '/api/monitoring/v1/clusters/{clusterUuid}/beats/beat/{beatUuid}', config: { validate: { - params: Joi.object({ - clusterUuid: Joi.string().required(), - beatUuid: Joi.string().required(), + params: schema.object({ + clusterUuid: schema.string(), + beatUuid: schema.string(), }), - payload: Joi.object({ - ccs: Joi.string().optional(), - timeRange: Joi.object({ - min: Joi.date().required(), - max: Joi.date().required(), - }).required(), + payload: schema.object({ + ccs: schema.maybe(schema.string()), + timeRange: schema.object({ + min: schema.string(), + max: schema.string(), + }), }), }, }, diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/beats/beats.js b/x-pack/plugins/monitoring/server/routes/api/v1/beats/beats.js similarity index 80% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/beats/beats.js rename to x-pack/plugins/monitoring/server/routes/api/v1/beats/beats.js index 6d681e697b334..425058934604e 100644 --- a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/beats/beats.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/beats/beats.js @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import Joi from 'joi'; +import { schema } from '@kbn/config-schema'; import { prefixIndexPattern } from '../../../../lib/ccs_utils'; import { getStats, getBeats } from '../../../../lib/beats'; import { handleError } from '../../../../lib/errors'; @@ -16,15 +16,15 @@ export function beatsListingRoute(server) { path: '/api/monitoring/v1/clusters/{clusterUuid}/beats/beats', config: { validate: { - params: Joi.object({ - clusterUuid: Joi.string().required(), + params: schema.object({ + clusterUuid: schema.string(), }), - payload: Joi.object({ - ccs: Joi.string().optional(), - timeRange: Joi.object({ - min: Joi.date().required(), - max: Joi.date().required(), - }).required(), + payload: schema.object({ + ccs: schema.maybe(schema.string()), + timeRange: schema.object({ + min: schema.string(), + max: schema.string(), + }), }), }, }, diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/beats/index.js b/x-pack/plugins/monitoring/server/routes/api/v1/beats/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/beats/index.js rename to x-pack/plugins/monitoring/server/routes/api/v1/beats/index.js diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/beats/metric_set_detail.js b/x-pack/plugins/monitoring/server/routes/api/v1/beats/metric_set_detail.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/beats/metric_set_detail.js rename to x-pack/plugins/monitoring/server/routes/api/v1/beats/metric_set_detail.js diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/beats/metric_set_overview.js b/x-pack/plugins/monitoring/server/routes/api/v1/beats/metric_set_overview.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/beats/metric_set_overview.js rename to x-pack/plugins/monitoring/server/routes/api/v1/beats/metric_set_overview.js diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/beats/overview.js b/x-pack/plugins/monitoring/server/routes/api/v1/beats/overview.js similarity index 82% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/beats/overview.js rename to x-pack/plugins/monitoring/server/routes/api/v1/beats/overview.js index b6cdc8e2588e5..f4722acdf8255 100644 --- a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/beats/overview.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/beats/overview.js @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import Joi from 'joi'; +import { schema } from '@kbn/config-schema'; import { prefixIndexPattern } from '../../../../lib/ccs_utils'; import { getMetrics } from '../../../../lib/details/get_metrics'; import { getLatestStats, getStats } from '../../../../lib/beats'; @@ -18,15 +18,15 @@ export function beatsOverviewRoute(server) { path: '/api/monitoring/v1/clusters/{clusterUuid}/beats', config: { validate: { - params: Joi.object({ - clusterUuid: Joi.string().required(), + params: schema.object({ + clusterUuid: schema.string(), }), - payload: Joi.object({ - ccs: Joi.string().optional(), - timeRange: Joi.object({ - min: Joi.date().required(), - max: Joi.date().required(), - }).required(), + payload: schema.object({ + ccs: schema.maybe(schema.string()), + timeRange: schema.object({ + min: schema.string(), + max: schema.string(), + }), }), }, }, diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/check_access/check_access.js b/x-pack/plugins/monitoring/server/routes/api/v1/check_access/check_access.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/check_access/check_access.js rename to x-pack/plugins/monitoring/server/routes/api/v1/check_access/check_access.js diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/check_access/index.js b/x-pack/plugins/monitoring/server/routes/api/v1/check_access/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/check_access/index.js rename to x-pack/plugins/monitoring/server/routes/api/v1/check_access/index.js diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/cluster/cluster.js b/x-pack/plugins/monitoring/server/routes/api/v1/cluster/cluster.js similarity index 77% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/cluster/cluster.js rename to x-pack/plugins/monitoring/server/routes/api/v1/cluster/cluster.js index b2c2db7ea793e..8d6fe04cdb7bd 100644 --- a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/cluster/cluster.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/cluster/cluster.js @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import Joi from 'joi'; +import { schema } from '@kbn/config-schema'; import { getClustersFromRequest } from '../../../../lib/cluster/get_clusters_from_request'; import { handleError } from '../../../../lib/errors'; import { getIndexPatterns } from '../../../../lib/cluster/get_index_patterns'; @@ -19,24 +19,22 @@ export function clusterRoute(server) { path: '/api/monitoring/v1/clusters/{clusterUuid}', config: { validate: { - params: Joi.object({ - clusterUuid: Joi.string().required(), + params: schema.object({ + clusterUuid: schema.string(), }), - payload: Joi.object({ - ccs: Joi.string().optional(), - timeRange: Joi.object({ - min: Joi.date().required(), - max: Joi.date().required(), - }).required(), - codePaths: Joi.array() - .items(Joi.string().required()) - .required(), + payload: schema.object({ + ccs: schema.maybe(schema.string()), + timeRange: schema.object({ + min: schema.string(), + max: schema.string(), + }), + codePaths: schema.arrayOf(schema.string()), }), }, }, handler: async req => { - await verifyCcsAvailability(req); const config = server.config(); + await verifyCcsAvailability(req); const indexPatterns = getIndexPatterns(server, { filebeatIndexPattern: config.get('monitoring.ui.logs.index'), diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/cluster/clusters.js b/x-pack/plugins/monitoring/server/routes/api/v1/cluster/clusters.js similarity index 85% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/cluster/clusters.js rename to x-pack/plugins/monitoring/server/routes/api/v1/cluster/clusters.js index 92f0367097228..014f22c1ffe19 100644 --- a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/cluster/clusters.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/cluster/clusters.js @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import Joi from 'joi'; +import { schema } from '@kbn/config-schema'; import { getClustersFromRequest } from '../../../../lib/cluster/get_clusters_from_request'; import { verifyMonitoringAuth } from '../../../../lib/elasticsearch/verify_monitoring_auth'; import { verifyCcsAvailability } from '../../../../lib/elasticsearch/verify_ccs_availability'; @@ -21,20 +21,18 @@ export function clustersRoute(server) { path: '/api/monitoring/v1/clusters', config: { validate: { - payload: Joi.object({ - timeRange: Joi.object({ - min: Joi.date().required(), - max: Joi.date().required(), - }).required(), - codePaths: Joi.array() - .items(Joi.string().required()) - .required(), + body: schema.object({ + timeRange: schema.object({ + min: schema.string(), + max: schema.string(), + }), + codePaths: schema.arrayOf(schema.string()), }), }, }, handler: async req => { - const config = server.config(); let clusters = []; + const config = server.config(); // NOTE using try/catch because checkMonitoringAuth is expected to throw // an error when current logged-in user doesn't have permission to read diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/cluster/index.js b/x-pack/plugins/monitoring/server/routes/api/v1/cluster/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/cluster/index.js rename to x-pack/plugins/monitoring/server/routes/api/v1/cluster/index.js diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr.js b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr.js similarity index 96% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr.js rename to x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr.js index fcdf4ad8a706c..b16a83199a728 100644 --- a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr.js @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import Joi from 'joi'; +import { schema } from '@kbn/config-schema'; import moment from 'moment'; import { get, groupBy } from 'lodash'; import { handleError } from '../../../../lib/errors/handle_error'; @@ -174,15 +174,15 @@ export function ccrRoute(server) { path: '/api/monitoring/v1/clusters/{clusterUuid}/elasticsearch/ccr', config: { validate: { - params: Joi.object({ - clusterUuid: Joi.string().required(), + params: schema.object({ + clusterUuid: schema.string(), }), - payload: Joi.object({ - ccs: Joi.string().optional(), - timeRange: Joi.object({ - min: Joi.date().required(), - max: Joi.date().required(), - }).required(), + payload: schema.object({ + ccs: schema.maybe(schema.string()), + timeRange: schema.object({ + min: schema.string(), + max: schema.string(), + }), }), }, }, diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr_shard.js b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr_shard.js similarity index 90% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr_shard.js rename to x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr_shard.js index 9dc2f62d74b35..4ee6cfe7fc54f 100644 --- a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr_shard.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr_shard.js @@ -6,7 +6,7 @@ import { get } from 'lodash'; import moment from 'moment'; -import Joi from 'joi'; +import { schema } from '@kbn/config-schema'; import { handleError } from '../../../../lib/errors/handle_error'; import { prefixIndexPattern } from '../../../../lib/ccs_utils'; import { getMetrics } from '../../../../lib/details/get_metrics'; @@ -74,17 +74,17 @@ export function ccrShardRoute(server) { path: '/api/monitoring/v1/clusters/{clusterUuid}/elasticsearch/ccr/{index}/shard/{shardId}', config: { validate: { - params: Joi.object({ - clusterUuid: Joi.string().required(), - index: Joi.string().required(), - shardId: Joi.string().required(), + params: schema.object({ + clusterUuid: schema.string(), + index: schema.string(), + shardId: schema.string(), }), - payload: Joi.object({ - ccs: Joi.string().optional(), - timeRange: Joi.object({ - min: Joi.date().required(), - max: Joi.date().required(), - }).required(), + payload: schema.object({ + ccs: schema.maybe(schema.string()), + timeRange: schema.object({ + min: schema.string(), + max: schema.string(), + }), }), }, }, diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/elasticsearch/index.js b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/elasticsearch/index.js rename to x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/index.js diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/elasticsearch/index_detail.js b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/index_detail.js similarity index 90% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/elasticsearch/index_detail.js rename to x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/index_detail.js index 6f03459acf285..0d589146878de 100644 --- a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/elasticsearch/index_detail.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/index_detail.js @@ -5,7 +5,7 @@ */ import { get } from 'lodash'; -import Joi from 'joi'; +import { schema } from '@kbn/config-schema'; import { getClusterStats } from '../../../../lib/cluster/get_cluster_stats'; import { getIndexSummary } from '../../../../lib/elasticsearch/indices'; import { getMetrics } from '../../../../lib/details/get_metrics'; @@ -24,17 +24,17 @@ export function esIndexRoute(server) { path: '/api/monitoring/v1/clusters/{clusterUuid}/elasticsearch/indices/{id}', config: { validate: { - params: Joi.object({ - clusterUuid: Joi.string().required(), - id: Joi.string().required(), + params: schema.object({ + clusterUuid: schema.string(), + id: schema.string(), }), - payload: Joi.object({ - ccs: Joi.string().optional(), - timeRange: Joi.object({ - min: Joi.date().required(), - max: Joi.date().required(), - }).required(), - is_advanced: Joi.boolean().required(), + payload: schema.object({ + ccs: schema.maybe(schema.string()), + timeRange: schema.object({ + min: schema.string(), + max: schema.string(), + }), + is_advanced: schema.boolean(), }), }, }, @@ -50,7 +50,7 @@ export function esIndexRoute(server) { const filebeatIndexPattern = prefixIndexPattern( config, config.get('monitoring.ui.logs.index'), - ccs + '*' ); const isAdvanced = req.payload.is_advanced; const metricSet = isAdvanced ? metricSetAdvanced : metricSetOverview; diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/elasticsearch/indices.js b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/indices.js similarity index 83% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/elasticsearch/indices.js rename to x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/indices.js index 241b54fbf0c2a..2911f13e459c5 100644 --- a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/elasticsearch/indices.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/indices.js @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import Joi from 'joi'; +import { schema } from '@kbn/config-schema'; import { getClusterStats } from '../../../../lib/cluster/get_cluster_stats'; import { getClusterStatus } from '../../../../lib/cluster/get_cluster_status'; import { getIndices } from '../../../../lib/elasticsearch/indices'; @@ -19,18 +19,18 @@ export function esIndicesRoute(server) { path: '/api/monitoring/v1/clusters/{clusterUuid}/elasticsearch/indices', config: { validate: { - params: Joi.object({ - clusterUuid: Joi.string().required(), + params: schema.object({ + clusterUuid: schema.string(), }), - query: Joi.object({ - show_system_indices: Joi.boolean(), + query: schema.object({ + show_system_indices: schema.boolean(), }), - payload: Joi.object({ - ccs: Joi.string().optional(), - timeRange: Joi.object({ - min: Joi.date().required(), - max: Joi.date().required(), - }).required(), + payload: schema.object({ + ccs: schema.maybe(schema.string()), + timeRange: schema.object({ + min: schema.string(), + max: schema.string(), + }), }), }, }, diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/elasticsearch/metric_set_index_detail.js b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/metric_set_index_detail.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/elasticsearch/metric_set_index_detail.js rename to x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/metric_set_index_detail.js diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/elasticsearch/metric_set_node_detail.js b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/metric_set_node_detail.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/elasticsearch/metric_set_node_detail.js rename to x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/metric_set_node_detail.js diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/elasticsearch/metric_set_overview.js b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/metric_set_overview.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/elasticsearch/metric_set_overview.js rename to x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/metric_set_overview.js diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/elasticsearch/ml_jobs.js b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ml_jobs.js similarity index 85% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/elasticsearch/ml_jobs.js rename to x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ml_jobs.js index de3b9863d9141..c24b5bc2d080c 100644 --- a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/elasticsearch/ml_jobs.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ml_jobs.js @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import Joi from 'joi'; +import { schema } from '@kbn/config-schema'; import { getClusterStats } from '../../../../lib/cluster/get_cluster_stats'; import { getClusterStatus } from '../../../../lib/cluster/get_cluster_status'; import { getMlJobs } from '../../../../lib/elasticsearch/get_ml_jobs'; @@ -19,15 +19,15 @@ export function mlJobRoute(server) { path: '/api/monitoring/v1/clusters/{clusterUuid}/elasticsearch/ml_jobs', config: { validate: { - params: Joi.object({ - clusterUuid: Joi.string().required(), + params: schema.object({ + clusterUuid: schema.string(), }), - payload: Joi.object({ - ccs: Joi.string().optional(), - timeRange: Joi.object({ - min: Joi.date().required(), - max: Joi.date().required(), - }).required(), + payload: schema.object({ + ccs: schema.maybe(schema.string()), + timeRange: schema.object({ + min: schema.string(), + max: schema.string(), + }), }), }, }, diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/elasticsearch/node_detail.js b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/node_detail.js similarity index 89% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/elasticsearch/node_detail.js rename to x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/node_detail.js index 364214d45c2da..0156ea2222171 100644 --- a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/elasticsearch/node_detail.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/node_detail.js @@ -5,7 +5,7 @@ */ import { get } from 'lodash'; -import Joi from 'joi'; +import { schema } from '@kbn/config-schema'; import { getClusterStats } from '../../../../lib/cluster/get_cluster_stats'; import { getNodeSummary } from '../../../../lib/elasticsearch/nodes'; import { getShardStats, getShardAllocation } from '../../../../lib/elasticsearch/shards'; @@ -24,18 +24,18 @@ export function esNodeRoute(server) { path: '/api/monitoring/v1/clusters/{clusterUuid}/elasticsearch/nodes/{nodeUuid}', config: { validate: { - params: Joi.object({ - clusterUuid: Joi.string().required(), - nodeUuid: Joi.string().required(), + params: schema.object({ + clusterUuid: schema.string(), + nodeUuid: schema.string(), }), - payload: Joi.object({ - ccs: Joi.string().optional(), - showSystemIndices: Joi.boolean().default(false), // show/hide system indices in shard allocation table - timeRange: Joi.object({ - min: Joi.date().required(), - max: Joi.date().required(), - }).required(), - is_advanced: Joi.boolean().required(), + payload: schema.object({ + ccs: schema.maybe(schema.string()), + showSystemIndices: schema.boolean({ defaultValue: false }), // show/hide system indices in shard allocation table + timeRange: schema.object({ + min: schema.string(), + max: schema.string(), + }), + is_advanced: schema.boolean(), }), }, }, diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/elasticsearch/nodes.js b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/nodes.js similarity index 79% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/elasticsearch/nodes.js rename to x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/nodes.js index fb2d04ecc041d..36951f08975c8 100644 --- a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/elasticsearch/nodes.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/nodes.js @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import Joi from 'joi'; +import { schema } from '@kbn/config-schema'; import { getClusterStats } from '../../../../lib/cluster/get_cluster_stats'; import { getClusterStatus } from '../../../../lib/cluster/get_cluster_status'; import { getNodes } from '../../../../lib/elasticsearch/nodes'; @@ -22,27 +22,24 @@ export function esNodesRoute(server) { path: '/api/monitoring/v1/clusters/{clusterUuid}/elasticsearch/nodes', config: { validate: { - params: Joi.object({ - clusterUuid: Joi.string().required(), + params: schema.object({ + clusterUuid: schema.string(), }), - payload: Joi.object({ - ccs: Joi.string().optional(), - timeRange: Joi.object({ - min: Joi.date().required(), - max: Joi.date().required(), - }).required(), - pagination: Joi.object({ - index: Joi.number().required(), - size: Joi.number().required(), - }).required(), - sort: Joi.object({ - field: Joi.string().required(), - direction: Joi.string().required(), - }).optional(), - queryText: Joi.string() - .default('') - .allow('') - .optional(), + payload: schema.object({ + ccs: schema.maybe(schema.string()), + timeRange: schema.object({ + min: schema.string(), + max: schema.string(), + }), + pagination: schema.object({ + index: schema.number(), + size: schema.number(), + }), + sort: schema.object({ + field: schema.string({ defaultValue: '' }), + direction: schema.string({ defaultValue: '' }), + }), + queryText: schema.string({ defaultValue: '' }), }), }, }, diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/elasticsearch/overview.js b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/overview.js similarity index 88% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/elasticsearch/overview.js rename to x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/overview.js index df1e847c16606..33220b040d8d7 100644 --- a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/elasticsearch/overview.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/overview.js @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import Joi from 'joi'; +import { schema } from '@kbn/config-schema'; import { getClusterStats } from '../../../../lib/cluster/get_cluster_stats'; import { getClusterStatus } from '../../../../lib/cluster/get_cluster_status'; import { getLastRecovery } from '../../../../lib/elasticsearch/get_last_recovery'; @@ -22,15 +22,15 @@ export function esOverviewRoute(server) { path: '/api/monitoring/v1/clusters/{clusterUuid}/elasticsearch', config: { validate: { - params: Joi.object({ - clusterUuid: Joi.string().required(), + params: schema.object({ + clusterUuid: schema.string(), }), - payload: Joi.object({ - ccs: Joi.string().optional(), - timeRange: Joi.object({ - min: Joi.date().required(), - max: Joi.date().required(), - }).required(), + payload: schema.object({ + ccs: schema.maybe(schema.string()), + timeRange: schema.object({ + min: schema.string(), + max: schema.string(), + }), }), }, }, diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/elasticsearch_settings/check/cluster.js b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch_settings/check/cluster.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/elasticsearch_settings/check/cluster.js rename to x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch_settings/check/cluster.js diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/elasticsearch_settings/check/nodes.js b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch_settings/check/nodes.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/elasticsearch_settings/check/nodes.js rename to x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch_settings/check/nodes.js diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/elasticsearch_settings/index.js b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch_settings/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/elasticsearch_settings/index.js rename to x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch_settings/index.js diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/elasticsearch_settings/set/collection_enabled.js b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch_settings/set/collection_enabled.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/elasticsearch_settings/set/collection_enabled.js rename to x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch_settings/set/collection_enabled.js diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/elasticsearch_settings/set/collection_interval.js b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch_settings/set/collection_interval.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/elasticsearch_settings/set/collection_interval.js rename to x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch_settings/set/collection_interval.js diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/kibana/_get_kibana_cluster_status.js b/x-pack/plugins/monitoring/server/routes/api/v1/kibana/_get_kibana_cluster_status.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/kibana/_get_kibana_cluster_status.js rename to x-pack/plugins/monitoring/server/routes/api/v1/kibana/_get_kibana_cluster_status.js diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/kibana/index.js b/x-pack/plugins/monitoring/server/routes/api/v1/kibana/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/kibana/index.js rename to x-pack/plugins/monitoring/server/routes/api/v1/kibana/index.js diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/kibana/instance.js b/x-pack/plugins/monitoring/server/routes/api/v1/kibana/instance.js similarity index 82% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/kibana/instance.js rename to x-pack/plugins/monitoring/server/routes/api/v1/kibana/instance.js index 4135757860fe7..02229de372862 100644 --- a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/kibana/instance.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/kibana/instance.js @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import Joi from 'joi'; +import { schema } from '@kbn/config-schema'; import { getKibanaInfo } from '../../../../lib/kibana/get_kibana_info'; import { handleError } from '../../../../lib/errors'; import { getMetrics } from '../../../../lib/details/get_metrics'; @@ -24,16 +24,16 @@ export function kibanaInstanceRoute(server) { path: '/api/monitoring/v1/clusters/{clusterUuid}/kibana/{kibanaUuid}', config: { validate: { - params: Joi.object({ - clusterUuid: Joi.string().required(), - kibanaUuid: Joi.string().required(), + params: schema.object({ + clusterUuid: schema.string(), + kibanaUuid: schema.string(), }), - payload: Joi.object({ - ccs: Joi.string().optional(), - timeRange: Joi.object({ - min: Joi.date().required(), - max: Joi.date().required(), - }).required(), + payload: schema.object({ + ccs: schema.maybe(schema.string()), + timeRange: schema.object({ + min: schema.string(), + max: schema.string(), + }), }), }, }, diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/kibana/instances.js b/x-pack/plugins/monitoring/server/routes/api/v1/kibana/instances.js similarity index 82% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/kibana/instances.js rename to x-pack/plugins/monitoring/server/routes/api/v1/kibana/instances.js index 3136940dd253a..3fde25578947a 100644 --- a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/kibana/instances.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/kibana/instances.js @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import Joi from 'joi'; +import { schema } from '@kbn/config-schema'; import { prefixIndexPattern } from '../../../../lib/ccs_utils'; import { getKibanaClusterStatus } from './_get_kibana_cluster_status'; import { getKibanas } from '../../../../lib/kibana/get_kibanas'; @@ -20,15 +20,15 @@ export function kibanaInstancesRoute(server) { path: '/api/monitoring/v1/clusters/{clusterUuid}/kibana/instances', config: { validate: { - params: Joi.object({ - clusterUuid: Joi.string().required(), + params: schema.object({ + clusterUuid: schema.string(), }), - payload: Joi.object({ - ccs: Joi.string().optional(), - timeRange: Joi.object({ - min: Joi.date().required(), - max: Joi.date().required(), - }).required(), + payload: schema.object({ + ccs: schema.maybe(schema.string()), + timeRange: schema.object({ + min: schema.string(), + max: schema.string(), + }), }), }, }, diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/kibana/metric_set_instance.js b/x-pack/plugins/monitoring/server/routes/api/v1/kibana/metric_set_instance.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/kibana/metric_set_instance.js rename to x-pack/plugins/monitoring/server/routes/api/v1/kibana/metric_set_instance.js diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/kibana/metric_set_overview.js b/x-pack/plugins/monitoring/server/routes/api/v1/kibana/metric_set_overview.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/kibana/metric_set_overview.js rename to x-pack/plugins/monitoring/server/routes/api/v1/kibana/metric_set_overview.js diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/kibana/overview.js b/x-pack/plugins/monitoring/server/routes/api/v1/kibana/overview.js similarity index 82% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/kibana/overview.js rename to x-pack/plugins/monitoring/server/routes/api/v1/kibana/overview.js index 208cc5d55ab8c..f47a8f791fa0a 100644 --- a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/kibana/overview.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/kibana/overview.js @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import Joi from 'joi'; +import { schema } from '@kbn/config-schema'; import { prefixIndexPattern } from '../../../../lib/ccs_utils'; import { getKibanaClusterStatus } from './_get_kibana_cluster_status'; import { getMetrics } from '../../../../lib/details/get_metrics'; @@ -21,15 +21,15 @@ export function kibanaOverviewRoute(server) { path: '/api/monitoring/v1/clusters/{clusterUuid}/kibana', config: { validate: { - params: Joi.object({ - clusterUuid: Joi.string().required(), + params: schema.object({ + clusterUuid: schema.string(), }), - payload: Joi.object({ - ccs: Joi.string().optional(), - timeRange: Joi.object({ - min: Joi.date().required(), - max: Joi.date().required(), - }).required(), + payload: schema.object({ + ccs: schema.maybe(schema.string()), + timeRange: schema.object({ + min: schema.string(), + max: schema.string(), + }), }), }, }, diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/logstash/index.js b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/logstash/index.js rename to x-pack/plugins/monitoring/server/routes/api/v1/logstash/index.js diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/logstash/metric_set_node.js b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/metric_set_node.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/logstash/metric_set_node.js rename to x-pack/plugins/monitoring/server/routes/api/v1/logstash/metric_set_node.js diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/logstash/metric_set_overview.js b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/metric_set_overview.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/logstash/metric_set_overview.js rename to x-pack/plugins/monitoring/server/routes/api/v1/logstash/metric_set_overview.js diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/logstash/node.js b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/node.js similarity index 85% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/logstash/node.js rename to x-pack/plugins/monitoring/server/routes/api/v1/logstash/node.js index bd3ae5f5c2679..f2a337b3cfa20 100644 --- a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/logstash/node.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/node.js @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import Joi from 'joi'; +import { schema } from '@kbn/config-schema'; import { getNodeInfo } from '../../../../lib/logstash/get_node_info'; import { handleError } from '../../../../lib/errors'; import { getMetrics } from '../../../../lib/details/get_metrics'; @@ -33,17 +33,17 @@ export function logstashNodeRoute(server) { path: '/api/monitoring/v1/clusters/{clusterUuid}/logstash/node/{logstashUuid}', config: { validate: { - params: Joi.object({ - clusterUuid: Joi.string().required(), - logstashUuid: Joi.string().required(), + params: schema.object({ + clusterUuid: schema.string(), + logstashUuid: schema.string(), }), - payload: Joi.object({ - ccs: Joi.string().optional(), - timeRange: Joi.object({ - min: Joi.date().required(), - max: Joi.date().required(), - }).required(), - is_advanced: Joi.boolean().required(), + payload: schema.object({ + ccs: schema.maybe(schema.string()), + timeRange: schema.object({ + min: schema.string(), + max: schema.string(), + }), + is_advanced: schema.boolean(), }), }, }, diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/logstash/nodes.js b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/nodes.js similarity index 83% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/logstash/nodes.js rename to x-pack/plugins/monitoring/server/routes/api/v1/logstash/nodes.js index f2d396913f94a..009aab6c18eea 100644 --- a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/logstash/nodes.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/nodes.js @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import Joi from 'joi'; +import { schema } from '@kbn/config-schema'; import { getClusterStatus } from '../../../../lib/logstash/get_cluster_status'; import { getNodes } from '../../../../lib/logstash/get_nodes'; import { handleError } from '../../../../lib/errors'; @@ -30,15 +30,15 @@ export function logstashNodesRoute(server) { path: '/api/monitoring/v1/clusters/{clusterUuid}/logstash/nodes', config: { validate: { - params: Joi.object({ - clusterUuid: Joi.string().required(), + params: schema.object({ + clusterUuid: schema.string(), }), - payload: Joi.object({ - ccs: Joi.string().optional(), - timeRange: Joi.object({ - min: Joi.date().required(), - max: Joi.date().required(), - }).required(), + payload: schema.object({ + ccs: schema.maybe(schema.string()), + timeRange: schema.object({ + min: schema.string(), + max: schema.string(), + }), }), }, }, diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/logstash/overview.js b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/overview.js similarity index 84% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/logstash/overview.js rename to x-pack/plugins/monitoring/server/routes/api/v1/logstash/overview.js index 35ef337a3faf7..c90bee294f903 100644 --- a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/logstash/overview.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/overview.js @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import Joi from 'joi'; +import { schema } from '@kbn/config-schema'; import { getClusterStatus } from '../../../../lib/logstash/get_cluster_status'; import { getMetrics } from '../../../../lib/details/get_metrics'; import { handleError } from '../../../../lib/errors'; @@ -31,15 +31,15 @@ export function logstashOverviewRoute(server) { path: '/api/monitoring/v1/clusters/{clusterUuid}/logstash', config: { validate: { - params: Joi.object({ - clusterUuid: Joi.string().required(), + params: schema.object({ + clusterUuid: schema.string(), }), - payload: Joi.object({ - ccs: Joi.string().optional(), - timeRange: Joi.object({ - min: Joi.date().required(), - max: Joi.date().required(), - }).required(), + payload: schema.object({ + ccs: schema.maybe(schema.string()), + timeRange: schema.object({ + min: schema.string(), + max: schema.string(), + }), }), }, }, diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/logstash/pipeline.js b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/pipeline.js similarity index 88% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/logstash/pipeline.js rename to x-pack/plugins/monitoring/server/routes/api/v1/logstash/pipeline.js index 2999fb73d2df1..8f19d164ad5d3 100644 --- a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/logstash/pipeline.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/pipeline.js @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import Joi from 'joi'; +import { schema } from '@kbn/config-schema'; import { handleError } from '../../../../lib/errors'; import { getPipelineVersions } from '../../../../lib/logstash/get_pipeline_versions'; import { getPipeline } from '../../../../lib/logstash/get_pipeline'; @@ -35,14 +35,14 @@ export function logstashPipelineRoute(server) { '/api/monitoring/v1/clusters/{clusterUuid}/logstash/pipeline/{pipelineId}/{pipelineHash?}', config: { validate: { - params: Joi.object({ - clusterUuid: Joi.string().required(), - pipelineId: Joi.string().required(), - pipelineHash: Joi.string().optional(), + params: schema.object({ + clusterUuid: schema.string(), + pipelineId: schema.string(), + pipelineHash: schema.maybe(schema.string()), }), - payload: Joi.object({ - ccs: Joi.string().optional(), - detailVertexId: Joi.string().optional(), + payload: schema.object({ + ccs: schema.maybe(schema.string()), + detailVertexId: schema.maybe(schema.string()), }), }, }, diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/logstash/pipelines/cluster_pipeline_ids.js b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/pipelines/cluster_pipeline_ids.js similarity index 80% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/logstash/pipelines/cluster_pipeline_ids.js rename to x-pack/plugins/monitoring/server/routes/api/v1/logstash/pipelines/cluster_pipeline_ids.js index 93330880babcc..f96a534a1eab0 100644 --- a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/logstash/pipelines/cluster_pipeline_ids.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/pipelines/cluster_pipeline_ids.js @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import Joi from 'joi'; +import { schema } from '@kbn/config-schema'; import { handleError } from '../../../../../lib/errors'; import { prefixIndexPattern } from '../../../../../lib/ccs_utils'; import { INDEX_PATTERN_LOGSTASH } from '../../../../../../common/constants'; @@ -19,15 +19,15 @@ export function logstashClusterPipelineIdsRoute(server) { path: '/api/monitoring/v1/clusters/{clusterUuid}/logstash/pipeline_ids', config: { validate: { - params: Joi.object({ - clusterUuid: Joi.string().required(), + params: schema.object({ + clusterUuid: schema.string(), }), - payload: Joi.object({ - ccs: Joi.string().optional(), - timeRange: Joi.object({ - min: Joi.date().required(), - max: Joi.date().required(), - }).required(), + payload: schema.object({ + ccs: schema.maybe(schema.string()), + timeRange: schema.object({ + min: schema.string(), + max: schema.string(), + }), }), }, }, diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/logstash/pipelines/cluster_pipelines.js b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/pipelines/cluster_pipelines.js similarity index 74% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/logstash/pipelines/cluster_pipelines.js rename to x-pack/plugins/monitoring/server/routes/api/v1/logstash/pipelines/cluster_pipelines.js index 87c8b85193602..4491b0289dcf7 100644 --- a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/logstash/pipelines/cluster_pipelines.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/pipelines/cluster_pipelines.js @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import Joi from 'joi'; +import { schema } from '@kbn/config-schema'; import { getClusterStatus } from '../../../../../lib/logstash/get_cluster_status'; import { handleError } from '../../../../../lib/errors'; import { prefixIndexPattern } from '../../../../../lib/ccs_utils'; @@ -20,27 +20,26 @@ export function logstashClusterPipelinesRoute(server) { path: '/api/monitoring/v1/clusters/{clusterUuid}/logstash/pipelines', config: { validate: { - params: Joi.object({ - clusterUuid: Joi.string().required(), + params: schema.object({ + clusterUuid: schema.string(), }), - payload: Joi.object({ - ccs: Joi.string().optional(), - timeRange: Joi.object({ - min: Joi.date().required(), - max: Joi.date().required(), - }).required(), - pagination: Joi.object({ - index: Joi.number().required(), - size: Joi.number().required(), - }).required(), - sort: Joi.object({ - field: Joi.string().required(), - direction: Joi.string().required(), - }).optional(), - queryText: Joi.string() - .default('') - .allow('') - .optional(), + payload: schema.object({ + ccs: schema.maybe(schema.string()), + timeRange: schema.object({ + min: schema.string(), + max: schema.string(), + }), + pagination: schema.object({ + index: schema.number(), + size: schema.number(), + }), + sort: schema.maybe( + schema.object({ + field: schema.string(), + direction: schema.string(), + }) + ), + queryText: schema.string({ defaultValue: '' }), }), }, }, diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/logstash/pipelines/node_pipelines.js b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/pipelines/node_pipelines.js similarity index 73% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/logstash/pipelines/node_pipelines.js rename to x-pack/plugins/monitoring/server/routes/api/v1/logstash/pipelines/node_pipelines.js index 089cf36b8b267..b14b24ba3e81a 100644 --- a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/logstash/pipelines/node_pipelines.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/pipelines/node_pipelines.js @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import Joi from 'joi'; +import { schema } from '@kbn/config-schema'; import { getNodeInfo } from '../../../../../lib/logstash/get_node_info'; import { handleError } from '../../../../../lib/errors'; import { prefixIndexPattern } from '../../../../../lib/ccs_utils'; @@ -20,28 +20,27 @@ export function logstashNodePipelinesRoute(server) { path: '/api/monitoring/v1/clusters/{clusterUuid}/logstash/node/{logstashUuid}/pipelines', config: { validate: { - params: Joi.object({ - clusterUuid: Joi.string().required(), - logstashUuid: Joi.string().required(), + params: schema.object({ + clusterUuid: schema.string(), + logstashUuid: schema.string(), }), - payload: Joi.object({ - ccs: Joi.string().optional(), - timeRange: Joi.object({ - min: Joi.date().required(), - max: Joi.date().required(), - }).required(), - pagination: Joi.object({ - index: Joi.number().required(), - size: Joi.number().required(), - }).required(), - sort: Joi.object({ - field: Joi.string().required(), - direction: Joi.string().required(), - }).optional(), - queryText: Joi.string() - .default('') - .allow('') - .optional(), + payload: schema.object({ + ccs: schema.maybe(schema.string()), + timeRange: schema.object({ + min: schema.string(), + max: schema.string(), + }), + pagination: schema.object({ + index: schema.number(), + size: schema.number(), + }), + sort: schema.maybe( + schema.object({ + field: schema.string(), + direction: schema.string(), + }) + ), + queryText: schema.string({ defaultValue: '' }), }), }, }, diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/setup/cluster_setup_status.js b/x-pack/plugins/monitoring/server/routes/api/v1/setup/cluster_setup_status.js similarity index 80% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/setup/cluster_setup_status.js rename to x-pack/plugins/monitoring/server/routes/api/v1/setup/cluster_setup_status.js index 2b6f3b6e71d0f..a4b811b88ee84 100644 --- a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/setup/cluster_setup_status.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/setup/cluster_setup_status.js @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import Joi from 'joi'; +import { schema } from '@kbn/config-schema'; import { verifyMonitoringAuth } from '../../../../lib/elasticsearch/verify_monitoring_auth'; import { handleError } from '../../../../lib/errors'; import { getCollectionStatus } from '../../../../lib/setup/collection'; @@ -19,10 +19,10 @@ export function clusterSetupStatusRoute(server) { path: '/api/monitoring/v1/setup/collection/cluster/{clusterUuid?}', config: { validate: { - params: Joi.object({ - clusterUuid: Joi.string().optional(), + params: schema.object({ + clusterUuid: schema.maybe(schema.string()), }), - query: Joi.object({ + query: schema.object({ // This flag is not intended to be used in production. It was introduced // as a way to ensure consistent API testing - the typical data source // for API tests are archived data, where the cluster configuration and data @@ -31,15 +31,17 @@ export function clusterSetupStatusRoute(server) { // which will vary from environment to environment making it difficult // to write tests against. Therefore, this flag exists and should only be used // in our testing environment. - skipLiveData: Joi.boolean().default(false), + skipLiveData: schema.boolean({ defaultValue: false }), }), - payload: Joi.object({ - ccs: Joi.string().optional(), - timeRange: Joi.object({ - min: Joi.date().required(), - max: Joi.date().required(), - }).optional(), - }).allow(null), + payload: schema.nullable( + schema.object({ + ccs: schema.maybe(schema.string()), + timeRange: schema.object({ + min: schema.string({ defaultValue: '' }), + max: schema.string({ defaultValue: '' }), + }), + }) + ), }, }, handler: async req => { diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/setup/disable_elasticsearch_internal_collection.js b/x-pack/plugins/monitoring/server/routes/api/v1/setup/disable_elasticsearch_internal_collection.js similarity index 91% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/setup/disable_elasticsearch_internal_collection.js rename to x-pack/plugins/monitoring/server/routes/api/v1/setup/disable_elasticsearch_internal_collection.js index c6a3ce8438b79..d3bb5523c1a94 100644 --- a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/setup/disable_elasticsearch_internal_collection.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/setup/disable_elasticsearch_internal_collection.js @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import Joi from 'joi'; +import { schema } from '@kbn/config-schema'; import { verifyMonitoringAuth } from '../../../../lib/elasticsearch/verify_monitoring_auth'; import { handleError } from '../../../../lib/errors'; import { setCollectionDisabled } from '../../../../lib/elasticsearch_settings/set/collection_disabled'; @@ -14,8 +14,8 @@ export function disableElasticsearchInternalCollectionRoute(server) { path: '/api/monitoring/v1/setup/collection/{clusterUuid}/disable_internal_collection', config: { validate: { - params: Joi.object({ - clusterUuid: Joi.string().required(), + params: schema.object({ + clusterUuid: schema.string(), }), }, }, diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/setup/index.js b/x-pack/plugins/monitoring/server/routes/api/v1/setup/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/setup/index.js rename to x-pack/plugins/monitoring/server/routes/api/v1/setup/index.js diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/setup/node_setup_status.js b/x-pack/plugins/monitoring/server/routes/api/v1/setup/node_setup_status.js similarity index 81% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/setup/node_setup_status.js rename to x-pack/plugins/monitoring/server/routes/api/v1/setup/node_setup_status.js index 2a615b887500d..1612e501faa5f 100644 --- a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/setup/node_setup_status.js +++ b/x-pack/plugins/monitoring/server/routes/api/v1/setup/node_setup_status.js @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import Joi from 'joi'; +import { schema } from '@kbn/config-schema'; import { verifyMonitoringAuth } from '../../../../lib/elasticsearch/verify_monitoring_auth'; import { handleError } from '../../../../lib/errors'; import { getCollectionStatus } from '../../../../lib/setup/collection'; @@ -19,10 +19,10 @@ export function nodeSetupStatusRoute(server) { path: '/api/monitoring/v1/setup/collection/node/{nodeUuid}', config: { validate: { - params: Joi.object({ - nodeUuid: Joi.string().required(), + params: schema.object({ + nodeUuid: schema.string(), }), - query: Joi.object({ + query: schema.object({ // This flag is not intended to be used in production. It was introduced // as a way to ensure consistent API testing - the typical data source // for API tests are archived data, where the cluster configuration and data @@ -31,15 +31,19 @@ export function nodeSetupStatusRoute(server) { // which will vary from environment to environment making it difficult // to write tests against. Therefore, this flag exists and should only be used // in our testing environment. - skipLiveData: Joi.boolean().default(false), + skipLiveData: schema.boolean({ defaultValue: false }), }), - payload: Joi.object({ - ccs: Joi.string().optional(), - timeRange: Joi.object({ - min: Joi.date().required(), - max: Joi.date().required(), - }).optional(), - }).allow(null), + payload: schema.nullable( + schema.object({ + ccs: schema.maybe(schema.string()), + timeRange: schema.maybe( + schema.object({ + min: schema.string(), + max: schema.string(), + }) + ), + }) + ), }, }, handler: async req => { diff --git a/x-pack/legacy/plugins/monitoring/server/routes/api/v1/ui.js b/x-pack/plugins/monitoring/server/routes/api/v1/ui.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/routes/api/v1/ui.js rename to x-pack/plugins/monitoring/server/routes/api/v1/ui.js diff --git a/x-pack/legacy/plugins/monitoring/server/routes/index.js b/x-pack/plugins/monitoring/server/routes/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/routes/index.js rename to x-pack/plugins/monitoring/server/routes/index.js diff --git a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/__mocks__/fixtures/beats_stats_results.json b/x-pack/plugins/monitoring/server/telemetry_collection/__mocks__/fixtures/beats_stats_results.json similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/telemetry_collection/__mocks__/fixtures/beats_stats_results.json rename to x-pack/plugins/monitoring/server/telemetry_collection/__mocks__/fixtures/beats_stats_results.json diff --git a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/create_query.test.ts b/x-pack/plugins/monitoring/server/telemetry_collection/create_query.test.ts similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/telemetry_collection/create_query.test.ts rename to x-pack/plugins/monitoring/server/telemetry_collection/create_query.test.ts diff --git a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/create_query.ts b/x-pack/plugins/monitoring/server/telemetry_collection/create_query.ts similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/telemetry_collection/create_query.ts rename to x-pack/plugins/monitoring/server/telemetry_collection/create_query.ts diff --git a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_all_stats.test.ts b/x-pack/plugins/monitoring/server/telemetry_collection/get_all_stats.test.ts similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_all_stats.test.ts rename to x-pack/plugins/monitoring/server/telemetry_collection/get_all_stats.test.ts diff --git a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_all_stats.ts b/x-pack/plugins/monitoring/server/telemetry_collection/get_all_stats.ts similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_all_stats.ts rename to x-pack/plugins/monitoring/server/telemetry_collection/get_all_stats.ts diff --git a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_beats_stats.test.ts b/x-pack/plugins/monitoring/server/telemetry_collection/get_beats_stats.test.ts similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_beats_stats.test.ts rename to x-pack/plugins/monitoring/server/telemetry_collection/get_beats_stats.test.ts diff --git a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_beats_stats.ts b/x-pack/plugins/monitoring/server/telemetry_collection/get_beats_stats.ts similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_beats_stats.ts rename to x-pack/plugins/monitoring/server/telemetry_collection/get_beats_stats.ts diff --git a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_cluster_uuids.test.ts b/x-pack/plugins/monitoring/server/telemetry_collection/get_cluster_uuids.test.ts similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_cluster_uuids.test.ts rename to x-pack/plugins/monitoring/server/telemetry_collection/get_cluster_uuids.test.ts diff --git a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_cluster_uuids.ts b/x-pack/plugins/monitoring/server/telemetry_collection/get_cluster_uuids.ts similarity index 91% rename from x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_cluster_uuids.ts rename to x-pack/plugins/monitoring/server/telemetry_collection/get_cluster_uuids.ts index 4738ab5b8af83..46b3007ae80e2 100644 --- a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_cluster_uuids.ts +++ b/x-pack/plugins/monitoring/server/telemetry_collection/get_cluster_uuids.ts @@ -14,12 +14,12 @@ import { ClusterDetailsGetter, StatsCollectionConfig, ClusterDetails, -} from '../../../../../../src/legacy/core_plugins/telemetry/server/collection_manager'; +} from '../../../../../src/legacy/core_plugins/telemetry/server/collection_manager'; /** * Get a list of Cluster UUIDs that exist within the specified timespan. */ -export const getClusterUuids: ClusterDetailsGetter = async config => { +export const getClusterUuids: ClusterDetailsGetter = async (config: any) => { const response = await fetchClusterUuids(config); return handleClusterUuidsResponse(response); }; diff --git a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_es_stats.test.ts b/x-pack/plugins/monitoring/server/telemetry_collection/get_es_stats.test.ts similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_es_stats.test.ts rename to x-pack/plugins/monitoring/server/telemetry_collection/get_es_stats.test.ts diff --git a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_es_stats.ts b/x-pack/plugins/monitoring/server/telemetry_collection/get_es_stats.ts similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_es_stats.ts rename to x-pack/plugins/monitoring/server/telemetry_collection/get_es_stats.ts diff --git a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_high_level_stats.test.ts b/x-pack/plugins/monitoring/server/telemetry_collection/get_high_level_stats.test.ts similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_high_level_stats.test.ts rename to x-pack/plugins/monitoring/server/telemetry_collection/get_high_level_stats.test.ts diff --git a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_high_level_stats.ts b/x-pack/plugins/monitoring/server/telemetry_collection/get_high_level_stats.ts similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_high_level_stats.ts rename to x-pack/plugins/monitoring/server/telemetry_collection/get_high_level_stats.ts diff --git a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_kibana_stats.test.ts b/x-pack/plugins/monitoring/server/telemetry_collection/get_kibana_stats.test.ts similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_kibana_stats.test.ts rename to x-pack/plugins/monitoring/server/telemetry_collection/get_kibana_stats.test.ts diff --git a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_kibana_stats.ts b/x-pack/plugins/monitoring/server/telemetry_collection/get_kibana_stats.ts similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_kibana_stats.ts rename to x-pack/plugins/monitoring/server/telemetry_collection/get_kibana_stats.ts diff --git a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_licenses.test.ts b/x-pack/plugins/monitoring/server/telemetry_collection/get_licenses.test.ts similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_licenses.test.ts rename to x-pack/plugins/monitoring/server/telemetry_collection/get_licenses.test.ts diff --git a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_licenses.ts b/x-pack/plugins/monitoring/server/telemetry_collection/get_licenses.ts similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/telemetry_collection/get_licenses.ts rename to x-pack/plugins/monitoring/server/telemetry_collection/get_licenses.ts diff --git a/x-pack/legacy/plugins/monitoring/server/telemetry_collection/index.ts b/x-pack/plugins/monitoring/server/telemetry_collection/index.ts similarity index 100% rename from x-pack/legacy/plugins/monitoring/server/telemetry_collection/index.ts rename to x-pack/plugins/monitoring/server/telemetry_collection/index.ts diff --git a/x-pack/plugins/monitoring/server/telemetry_collection/register_monitoring_collection.ts b/x-pack/plugins/monitoring/server/telemetry_collection/register_monitoring_collection.ts new file mode 100644 index 0000000000000..7bc4e9cbf7558 --- /dev/null +++ b/x-pack/plugins/monitoring/server/telemetry_collection/register_monitoring_collection.ts @@ -0,0 +1,33 @@ +/* + * 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. + */ + +import { ICustomClusterClient } from 'kibana/server'; +import { Cluster } from 'src/legacy/core_plugins/elasticsearch'; +// @ts-ignore +import { getAllStats } from './get_all_stats'; +import { getClusterUuids } from './get_cluster_uuids'; +import { getLicenses } from './get_licenses'; + +export function registerMonitoringCollection( + cluster: ICustomClusterClient, + telemetryCollectionManager: any +) { + // Create a legacy wrapper since telemetry is still in the legacy plugins + const legacyCluster: Cluster = { + callWithRequest: async (req: any, endpoint: string, params: any) => + cluster.asScoped(req).callAsCurrentUser(endpoint, params), + callWithInternalUser: (endpoint: string, params: any) => + cluster.callAsInternalUser(endpoint, params), + }; + telemetryCollectionManager.setCollection({ + esCluster: legacyCluster, + title: 'monitoring', + priority: 2, + statsGetter: getAllStats, + clusterDetailsGetter: getClusterUuids, + licenseGetter: getLicenses, + }); +} diff --git a/x-pack/plugins/monitoring/server/types.ts b/x-pack/plugins/monitoring/server/types.ts new file mode 100644 index 0000000000000..9f30ed1ba5035 --- /dev/null +++ b/x-pack/plugins/monitoring/server/types.ts @@ -0,0 +1,21 @@ +/* + * 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. + */ +import { Observable } from 'rxjs'; +import { LicenseFeature, ILicense } from '../../licensing/server'; + +export interface MonitoringLicenseService { + refresh: () => Promise; + license$: Observable; + getMessage: () => string | undefined; + getWatcherFeature: () => LicenseFeature; + getMonitoringFeature: () => LicenseFeature; + getSecurityFeature: () => LicenseFeature; + stop: () => void; +} + +export interface MonitoringElasticsearchConfig { + hosts: string[]; +} diff --git a/x-pack/test/api_integration/apis/monitoring/common/mappings_exist.js b/x-pack/test/api_integration/apis/monitoring/common/mappings_exist.js index 73b3f5f97c6fa..d5a72fa0ae3c8 100644 --- a/x-pack/test/api_integration/apis/monitoring/common/mappings_exist.js +++ b/x-pack/test/api_integration/apis/monitoring/common/mappings_exist.js @@ -6,11 +6,11 @@ import expect from '@kbn/expect'; import { get } from 'lodash'; -import * as esMetrics from '../../../../../legacy/plugins/monitoring/server/lib/metrics/elasticsearch/metrics'; -import * as kibanaMetrics from '../../../../../legacy/plugins/monitoring/server/lib/metrics/kibana/metrics'; -import * as logstashMetrics from '../../../../../legacy/plugins/monitoring/server/lib/metrics/logstash/metrics'; -import * as beatsMetrics from '../../../../../legacy/plugins/monitoring/server/lib/metrics/beats/metrics'; -import * as apmMetrics from '../../../../../legacy/plugins/monitoring/server/lib/metrics/apm/metrics'; +import * as esMetrics from '../../../../../plugins/monitoring/server/lib/metrics/elasticsearch/metrics'; +import * as kibanaMetrics from '../../../../../plugins/monitoring/server/lib/metrics/kibana/metrics'; +import * as logstashMetrics from '../../../../../plugins/monitoring/server/lib/metrics/logstash/metrics'; +import * as beatsMetrics from '../../../../../plugins/monitoring/server/lib/metrics/beats/metrics'; +import * as apmMetrics from '../../../../../plugins/monitoring/server/lib/metrics/apm/metrics'; export default function({ getService }) { const es = getService('legacyEs'); From b5f460fb6e7fc551aceabded65f4a2f148e324a0 Mon Sep 17 00:00:00 2001 From: Nathan L Smith Date: Fri, 20 Mar 2020 13:14:39 -0500 Subject: [PATCH 02/31] Remove all client-side map munging (#60701) Remove the getCytoscapeElements function. On the server: * Replace `source` with `sourceData`, `destination` with `targetData`, `source.id` with `source`, and `destination.id` with `target`. * Return a single array as an `elements` property instead of `nodes` and `connections` * Map all of the items data to be inside of a `data` object * Replace SERVICE_AGENT_NAME with AGENT_NAME * Add some missing constants On the client: * Remove getCytoscapeElements * Move all presentation-specific data transformation to use the original attributes in the place where they're needed * Remove `href` since it wasn't being used * Move BetaBadge to its own file * Move cytoscapeDivStyle to cytoscapeOptions * Fix storybook to work with new data formats --- .../components/app/ServiceMap/BetaBadge.tsx | 37 + .../app/ServiceMap/Cytoscape.stories.tsx | 80 +- .../components/app/ServiceMap/Cytoscape.tsx | 19 +- .../app/ServiceMap/Popover/Contents.tsx | 3 +- .../app/ServiceMap/Popover/Info.tsx | 13 +- .../app/ServiceMap/Popover/index.tsx | 3 +- .../cytoscape-layout-test-response.json | 860 +++++++++++++++++- .../app/ServiceMap/cytoscapeOptions.ts | 38 +- .../app/ServiceMap/get_cytoscape_elements.ts | 77 -- .../public/components/app/ServiceMap/icons.ts | 15 +- .../components/app/ServiceMap/index.tsx | 61 +- .../elasticsearch_fieldnames.test.ts.snap | 12 +- .../apm/common/elasticsearch_fieldnames.ts | 2 +- x-pack/plugins/apm/common/service_map.ts | 23 +- .../java/gc/fetch_and_transform_gc_metrics.ts | 4 +- .../by_agent/java/heap_memory/index.ts | 4 +- .../by_agent/java/non_heap_memory/index.ts | 4 +- .../by_agent/java/thread_count/index.ts | 4 +- .../lib/service_map/dedupe_connections.ts | 51 +- .../server/lib/service_map/get_service_map.ts | 27 +- .../get_service_map_from_trace_ids.ts | 23 +- .../lib/services/get_service_agent_name.ts | 4 +- .../get_services/get_services_items.ts | 4 +- .../get_agent_name_by_service.ts | 4 +- .../lib/ui_filters/local_ui_filters/config.ts | 4 +- 25 files changed, 1110 insertions(+), 266 deletions(-) create mode 100644 x-pack/legacy/plugins/apm/public/components/app/ServiceMap/BetaBadge.tsx delete mode 100644 x-pack/legacy/plugins/apm/public/components/app/ServiceMap/get_cytoscape_elements.ts diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/BetaBadge.tsx b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/BetaBadge.tsx new file mode 100644 index 0000000000000..b40efce020a63 --- /dev/null +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/BetaBadge.tsx @@ -0,0 +1,37 @@ +/* + * 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. + */ + +import { EuiBetaBadge } from '@elastic/eui'; +import theme from '@elastic/eui/dist/eui_theme_light.json'; +import { i18n } from '@kbn/i18n'; +import React from 'react'; +import styled from 'styled-components'; + +const BetaBadgeContainer = styled.div` + right: ${theme.gutterTypes.gutterMedium}; + position: absolute; + top: ${theme.gutterTypes.gutterSmall}; + z-index: 1; /* The element containing the cytoscape canvas has z-index = 0. */ +`; + +export function BetaBadge() { + return ( + + + + ); +} diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Cytoscape.stories.tsx b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Cytoscape.stories.tsx index b18f462b54171..155695f7596dd 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Cytoscape.stories.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Cytoscape.stories.tsx @@ -9,11 +9,10 @@ import { storiesOf } from '@storybook/react'; import cytoscape from 'cytoscape'; import React from 'react'; import { Cytoscape } from './Cytoscape'; -import { getCytoscapeElements } from './get_cytoscape_elements'; import serviceMapResponse from './cytoscape-layout-test-response.json'; import { iconForNode } from './icons'; -const elementsFromResponses = getCytoscapeElements(serviceMapResponse, ''); +const elementsFromResponses = serviceMapResponse.elements; storiesOf('app/ServiceMap/Cytoscape', module).add( 'example', @@ -22,25 +21,22 @@ storiesOf('app/ServiceMap/Cytoscape', module).add( { data: { id: 'opbeans-python', - label: 'opbeans-python', - agentName: 'python', - type: 'service' + 'service.name': 'opbeans-python', + 'agent.name': 'python' } }, { data: { id: 'opbeans-node', - label: 'opbeans-node', - agentName: 'nodejs', - type: 'service' + 'service.name': 'opbeans-node', + 'agent.name': 'nodejs' } }, { data: { id: 'opbeans-ruby', - label: 'opbeans-ruby', - agentName: 'ruby', - type: 'service' + 'service.name': 'opbeans-ruby', + 'agent.name': 'ruby' } }, { data: { source: 'opbeans-python', target: 'opbeans-node' } }, @@ -78,74 +74,74 @@ storiesOf('app/ServiceMap/Cytoscape', module) () => { const cy = cytoscape(); const elements = [ - { data: { id: 'default', label: 'default', type: undefined } }, - { data: { id: 'cache', label: 'cache', type: 'cache' } }, - { data: { id: 'database', label: 'database', type: 'database' } }, - { data: { id: 'external', label: 'external', type: 'external' } }, - { data: { id: 'messaging', label: 'messaging', type: 'messaging' } }, + { data: { id: 'default' } }, + { data: { id: 'cache', label: 'cache', 'span.type': 'cache' } }, + { data: { id: 'database', label: 'database', 'span.type': 'db' } }, + { + data: { id: 'external', label: 'external', 'span.type': 'external' } + }, + { + data: { + id: 'messaging', + label: 'messaging', + 'span.type': 'messaging' + } + }, { data: { id: 'dotnet', - label: 'dotnet service', - type: 'service', - agentName: 'dotnet' + 'service.name': 'dotnet service', + 'agent.name': 'dotnet' } }, { data: { id: 'go', - label: 'go service', - type: 'service', - agentName: 'go' + 'service.name': 'go service', + 'agent.name': 'go' } }, { data: { id: 'java', - label: 'java service', - type: 'service', - agentName: 'java' + 'service.name': 'java service', + 'agent.name': 'java' } }, { data: { id: 'js-base', - label: 'js-base service', - type: 'service', - agentName: 'js-base' + 'service.name': 'js-base service', + 'agent.name': 'js-base' } }, { data: { id: 'nodejs', - label: 'nodejs service', - type: 'service', - agentName: 'nodejs' + 'service.name': 'nodejs service', + 'agent.name': 'nodejs' } }, { data: { id: 'php', - label: 'php service', - type: 'service', - agentName: 'php' + 'service.name': 'php service', + 'agent.name': 'php' } }, { data: { id: 'python', - label: 'python service', - type: 'service', - agentName: 'python' + 'service.name': 'python service', + 'agent.name': 'python' } }, { data: { id: 'ruby', - label: 'ruby service', - type: 'service', - agentName: 'ruby' + 'service.name': 'ruby service', + 'agent.name': 'ruby' } } ]; @@ -158,8 +154,8 @@ storiesOf('app/ServiceMap/Cytoscape', module) - agentName: {node.data('agentName') || 'undefined'}, type:{' '} - {node.data('type') || 'undefined'} + agent.name: {node.data('agent.name') || 'undefined'}, + span.type: {node.data('span.type') || 'undefined'} } icon={ diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Cytoscape.tsx b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Cytoscape.tsx index ae6b06b10fd1d..3197c269fd90c 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Cytoscape.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Cytoscape.tsx @@ -4,21 +4,22 @@ * you may not use this file except in compliance with the Elastic License. */ +import cytoscape from 'cytoscape'; import React, { + createContext, CSSProperties, - useState, - useRef, - useEffect, ReactNode, - createContext, - useCallback + useCallback, + useEffect, + useRef, + useState } from 'react'; -import cytoscape from 'cytoscape'; import { isRumAgentName } from '../../../../../../../plugins/apm/common/agent_name'; +import { AGENT_NAME } from '../../../../../../../plugins/apm/common/elasticsearch_fieldnames'; import { + animationOptions, cytoscapeOptions, - nodeHeight, - animationOptions + nodeHeight } from './cytoscapeOptions'; export const CytoscapeContext = createContext( @@ -81,7 +82,7 @@ function getLayoutOptions( function selectRoots(cy: cytoscape.Core): string[] { const nodes = cy.nodes(); const roots = nodes.roots(); - const rumNodes = nodes.filter(node => isRumAgentName(node.data('agentName'))); + const rumNodes = nodes.filter(node => isRumAgentName(node.data(AGENT_NAME))); return rumNodes.union(roots).map(node => node.id()); } diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/Contents.tsx b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/Contents.tsx index 7db064632a7f1..52263878ca915 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/Contents.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/Contents.tsx @@ -12,6 +12,7 @@ import { } from '@elastic/eui'; import cytoscape from 'cytoscape'; import React from 'react'; +import { SERVICE_FRAMEWORK_NAME } from '../../../../../../../../plugins/apm/common/elasticsearch_fieldnames'; import { Buttons } from './Buttons'; import { Info } from './Info'; import { ServiceMetricFetcher } from './ServiceMetricFetcher'; @@ -33,7 +34,7 @@ export function Contents({ onFocusClick, selectedNodeServiceName }: ContentsProps) { - const frameworkName = selectedNodeData.frameworkName; + const frameworkName = selectedNodeData[SERVICE_FRAMEWORK_NAME]; return ( 172.17.0.1", + "id": "apm-server~>172.17.0.1", + "sourceData": { + "service.environment": null, + "service.name": "apm-server", + "agent.name": "go", + "id": "apm-server" + }, + "targetData": { + "destination.address": "172.17.0.1", + "span.subtype": "http", + "span.type": "external", + "id": ">172.17.0.1" + } + } + }, + { + "data": { + "source": "client", + "target": ">opbeans-node", + "id": "client~>opbeans-node", + "sourceData": { + "service.environment": null, + "service.name": "client", + "agent.name": "js-base", + "id": "client" + }, + "targetData": { + "destination.address": "opbeans-node", + "span.subtype": null, + "span.type": "resource", + "id": ">opbeans-node" + } + } + }, + { + "data": { + "source": "client", + "target": "opbeans-node", + "id": "client~opbeans-node", + "sourceData": { + "service.environment": null, + "service.name": "client", + "agent.name": "js-base", + "id": "client" + }, + "targetData": { + "service.environment": "production", + "service.name": "opbeans-node", + "agent.name": "nodejs", + "id": "opbeans-node" + } + } + }, + { + "data": { + "source": "opbeans-dotnet", + "target": "opbeans-go", + "id": "opbeans-dotnet~opbeans-go", + "sourceData": { + "service.environment": "production", + "service.name": "opbeans-dotnet", + "agent.name": "dotnet", + "id": "opbeans-dotnet" + }, + "targetData": { + "service.environment": "production", + "service.name": "opbeans-go", + "agent.name": "go", + "id": "opbeans-go" + }, + "bidirectional": true + } + }, + { + "data": { + "source": "opbeans-dotnet", + "target": "opbeans-java", + "id": "opbeans-dotnet~opbeans-java", + "sourceData": { + "service.environment": "production", + "service.name": "opbeans-dotnet", + "agent.name": "dotnet", + "id": "opbeans-dotnet" + }, + "targetData": { + "service.environment": "production", + "service.name": "opbeans-java", + "agent.name": "java", + "id": "opbeans-java" + }, + "bidirectional": true + } + }, + { + "data": { + "source": "opbeans-dotnet", + "target": "opbeans-node", + "id": "opbeans-dotnet~opbeans-node", + "sourceData": { + "service.environment": "production", + "service.name": "opbeans-dotnet", + "agent.name": "dotnet", + "id": "opbeans-dotnet" + }, + "targetData": { + "service.environment": "production", + "service.name": "opbeans-node", + "agent.name": "nodejs", + "id": "opbeans-node" + }, + "bidirectional": true + } + }, + { + "data": { + "source": "opbeans-dotnet", + "target": "opbeans-python", + "id": "opbeans-dotnet~opbeans-python", + "sourceData": { + "service.environment": "production", + "service.name": "opbeans-dotnet", + "agent.name": "dotnet", + "id": "opbeans-dotnet" + }, + "targetData": { + "service.environment": "production", + "service.name": "opbeans-python", + "agent.name": "python", + "id": "opbeans-python" + }, + "bidirectional": true + } + }, + { + "data": { + "source": "opbeans-dotnet", + "target": "opbeans-ruby", + "id": "opbeans-dotnet~opbeans-ruby", + "sourceData": { + "service.environment": "production", + "service.name": "opbeans-dotnet", + "agent.name": "dotnet", + "id": "opbeans-dotnet" + }, + "targetData": { + "service.environment": "production", + "service.name": "opbeans-ruby", + "agent.name": "ruby", + "id": "opbeans-ruby" + }, + "bidirectional": true + } + }, + { + "data": { + "source": "opbeans-go", + "target": ">postgres", + "id": "opbeans-go~>postgres", + "sourceData": { + "service.environment": "production", + "service.name": "opbeans-go", + "agent.name": "go", + "id": "opbeans-go" + }, + "targetData": { + "destination.address": "postgres", + "span.subtype": "postgresql", + "span.type": "db", + "id": ">postgres" + } + } + }, + { + "data": { + "source": "opbeans-go", + "target": "opbeans-dotnet", + "id": "opbeans-go~opbeans-dotnet", + "sourceData": { + "service.environment": "production", + "service.name": "opbeans-go", + "agent.name": "go", + "id": "opbeans-go" + }, + "targetData": { + "service.environment": "production", + "service.name": "opbeans-dotnet", + "agent.name": "dotnet", + "id": "opbeans-dotnet" + }, + "isInverseEdge": true + } + }, + { + "data": { + "source": "opbeans-go", + "target": "opbeans-java", + "id": "opbeans-go~opbeans-java", + "sourceData": { + "service.environment": "production", + "service.name": "opbeans-go", + "agent.name": "go", + "id": "opbeans-go" + }, + "targetData": { + "service.environment": "production", + "service.name": "opbeans-java", + "agent.name": "java", + "id": "opbeans-java" + }, + "bidirectional": true + } + }, + { + "data": { + "source": "opbeans-go", + "target": "opbeans-node", + "id": "opbeans-go~opbeans-node", + "sourceData": { + "service.environment": "production", + "service.name": "opbeans-go", + "agent.name": "go", + "id": "opbeans-go" + }, + "targetData": { + "service.environment": "production", + "service.name": "opbeans-node", + "agent.name": "nodejs", + "id": "opbeans-node" + }, + "bidirectional": true + } + }, + { + "data": { + "source": "opbeans-go", + "target": "opbeans-python", + "id": "opbeans-go~opbeans-python", + "sourceData": { + "service.environment": "production", + "service.name": "opbeans-go", + "agent.name": "go", + "id": "opbeans-go" + }, + "targetData": { + "service.environment": "production", + "service.name": "opbeans-python", + "agent.name": "python", + "id": "opbeans-python" + }, + "bidirectional": true + } + }, + { + "data": { + "source": "opbeans-go", + "target": "opbeans-ruby", + "id": "opbeans-go~opbeans-ruby", + "sourceData": { + "service.environment": "production", + "service.name": "opbeans-go", + "agent.name": "go", + "id": "opbeans-go" + }, + "targetData": { + "service.environment": "production", + "service.name": "opbeans-ruby", + "agent.name": "ruby", + "id": "opbeans-ruby" + }, + "bidirectional": true + } + }, + { + "data": { + "source": "opbeans-java", + "target": ">postgres", + "id": "opbeans-java~>postgres", + "sourceData": { + "service.environment": "production", + "service.name": "opbeans-java", + "agent.name": "java", + "id": "opbeans-java" + }, + "targetData": { + "destination.address": "postgres", + "span.subtype": "postgresql", + "span.type": "db", + "id": ">postgres" + } + } + }, + { + "data": { + "source": "opbeans-java", + "target": "opbeans-dotnet", + "id": "opbeans-java~opbeans-dotnet", + "sourceData": { + "service.environment": "production", + "service.name": "opbeans-java", + "agent.name": "java", + "id": "opbeans-java" + }, + "targetData": { + "service.environment": "production", + "service.name": "opbeans-dotnet", + "agent.name": "dotnet", + "id": "opbeans-dotnet" + }, + "isInverseEdge": true + } + }, + { + "data": { + "source": "opbeans-java", + "target": "opbeans-go", + "id": "opbeans-java~opbeans-go", + "sourceData": { + "service.environment": "production", + "service.name": "opbeans-java", + "agent.name": "java", + "id": "opbeans-java" + }, + "targetData": { + "service.environment": "production", + "service.name": "opbeans-go", + "agent.name": "go", + "id": "opbeans-go" + }, + "isInverseEdge": true + } + }, + { + "data": { + "source": "opbeans-java", + "target": "opbeans-node", + "id": "opbeans-java~opbeans-node", + "sourceData": { + "service.environment": "production", + "service.name": "opbeans-java", + "agent.name": "java", + "id": "opbeans-java" + }, + "targetData": { + "service.environment": "production", + "service.name": "opbeans-node", + "agent.name": "nodejs", + "id": "opbeans-node" + }, + "bidirectional": true + } + }, + { + "data": { + "source": "opbeans-java", + "target": "opbeans-python", + "id": "opbeans-java~opbeans-python", + "sourceData": { + "service.environment": "production", + "service.name": "opbeans-java", + "agent.name": "java", + "id": "opbeans-java" + }, + "targetData": { + "service.environment": "production", + "service.name": "opbeans-python", + "agent.name": "python", + "id": "opbeans-python" + }, + "bidirectional": true + } + }, + { + "data": { + "source": "opbeans-java", + "target": "opbeans-ruby", + "id": "opbeans-java~opbeans-ruby", + "sourceData": { + "service.environment": "production", + "service.name": "opbeans-java", + "agent.name": "java", + "id": "opbeans-java" + }, + "targetData": { + "service.environment": "production", + "service.name": "opbeans-ruby", + "agent.name": "ruby", + "id": "opbeans-ruby" + }, + "bidirectional": true + } + }, + { + "data": { + "source": "opbeans-node", + "target": "opbeans-dotnet", + "id": "opbeans-node~opbeans-dotnet", + "sourceData": { + "service.environment": "production", + "service.name": "opbeans-node", + "agent.name": "nodejs", + "id": "opbeans-node" + }, + "targetData": { + "service.environment": "production", + "service.name": "opbeans-dotnet", + "agent.name": "dotnet", + "id": "opbeans-dotnet" + }, + "isInverseEdge": true + } + }, + { + "data": { + "source": "opbeans-node", + "target": "opbeans-go", + "id": "opbeans-node~opbeans-go", + "sourceData": { + "service.environment": "production", + "service.name": "opbeans-node", + "agent.name": "nodejs", + "id": "opbeans-node" + }, + "targetData": { + "service.environment": "production", + "service.name": "opbeans-go", + "agent.name": "go", + "id": "opbeans-go" + }, + "isInverseEdge": true + } + }, + { + "data": { + "source": "opbeans-node", + "target": "opbeans-java", + "id": "opbeans-node~opbeans-java", + "sourceData": { + "service.environment": "production", + "service.name": "opbeans-node", + "agent.name": "nodejs", + "id": "opbeans-node" + }, + "targetData": { + "service.environment": "production", + "service.name": "opbeans-java", + "agent.name": "java", + "id": "opbeans-java" + }, + "isInverseEdge": true + } + }, + { + "data": { + "source": "opbeans-node", + "target": "opbeans-python", + "id": "opbeans-node~opbeans-python", + "sourceData": { + "service.environment": "production", + "service.name": "opbeans-node", + "agent.name": "nodejs", + "id": "opbeans-node" + }, + "targetData": { + "service.environment": "production", + "service.name": "opbeans-python", + "agent.name": "python", + "id": "opbeans-python" + }, + "bidirectional": true + } + }, + { + "data": { + "source": "opbeans-node", + "target": "opbeans-ruby", + "id": "opbeans-node~opbeans-ruby", + "sourceData": { + "service.environment": "production", + "service.name": "opbeans-node", + "agent.name": "nodejs", + "id": "opbeans-node" + }, + "targetData": { + "service.environment": "production", + "service.name": "opbeans-ruby", + "agent.name": "ruby", + "id": "opbeans-ruby" + }, + "bidirectional": true + } + }, + { + "data": { + "source": "opbeans-python", + "target": "opbeans-dotnet", + "id": "opbeans-python~opbeans-dotnet", + "sourceData": { + "service.environment": "production", + "service.name": "opbeans-python", + "agent.name": "python", + "id": "opbeans-python" + }, + "targetData": { + "service.environment": "production", + "service.name": "opbeans-dotnet", + "agent.name": "dotnet", + "id": "opbeans-dotnet" + }, + "isInverseEdge": true + } + }, + { + "data": { + "source": "opbeans-python", + "target": "opbeans-go", + "id": "opbeans-python~opbeans-go", + "sourceData": { + "service.environment": "production", + "service.name": "opbeans-python", + "agent.name": "python", + "id": "opbeans-python" + }, + "targetData": { + "service.environment": "production", + "service.name": "opbeans-go", + "agent.name": "go", + "id": "opbeans-go" + }, + "isInverseEdge": true + } + }, + { + "data": { + "source": "opbeans-python", + "target": "opbeans-java", + "id": "opbeans-python~opbeans-java", + "sourceData": { + "service.environment": "production", + "service.name": "opbeans-python", + "agent.name": "python", + "id": "opbeans-python" + }, + "targetData": { + "service.environment": "production", + "service.name": "opbeans-java", + "agent.name": "java", + "id": "opbeans-java" + }, + "isInverseEdge": true + } + }, + { + "data": { + "source": "opbeans-python", + "target": "opbeans-node", + "id": "opbeans-python~opbeans-node", + "sourceData": { + "service.environment": "production", + "service.name": "opbeans-python", + "agent.name": "python", + "id": "opbeans-python" + }, + "targetData": { + "service.environment": "production", + "service.name": "opbeans-node", + "agent.name": "nodejs", + "id": "opbeans-node" + }, + "isInverseEdge": true + } + }, + { + "data": { + "source": "opbeans-python", + "target": "opbeans-ruby", + "id": "opbeans-python~opbeans-ruby", + "sourceData": { + "service.environment": "production", + "service.name": "opbeans-python", + "agent.name": "python", + "id": "opbeans-python" + }, + "targetData": { + "service.environment": "production", + "service.name": "opbeans-ruby", + "agent.name": "ruby", + "id": "opbeans-ruby" + }, + "bidirectional": true + } + }, + { + "data": { + "source": "opbeans-ruby", + "target": "opbeans-dotnet", + "id": "opbeans-ruby~opbeans-dotnet", + "sourceData": { + "service.environment": "production", + "service.name": "opbeans-ruby", + "agent.name": "ruby", + "id": "opbeans-ruby" + }, + "targetData": { + "service.environment": "production", + "service.name": "opbeans-dotnet", + "agent.name": "dotnet", + "id": "opbeans-dotnet" + }, + "isInverseEdge": true + } + }, + { + "data": { + "source": "opbeans-ruby", + "target": "opbeans-go", + "id": "opbeans-ruby~opbeans-go", + "sourceData": { + "service.environment": "production", + "service.name": "opbeans-ruby", + "agent.name": "ruby", + "id": "opbeans-ruby" + }, + "targetData": { + "service.environment": "production", + "service.name": "opbeans-go", + "agent.name": "go", + "id": "opbeans-go" + }, + "isInverseEdge": true + } + }, + { + "data": { + "source": "opbeans-ruby", + "target": "opbeans-java", + "id": "opbeans-ruby~opbeans-java", + "sourceData": { + "service.environment": "production", + "service.name": "opbeans-ruby", + "agent.name": "ruby", + "id": "opbeans-ruby" + }, + "targetData": { + "service.environment": "production", + "service.name": "opbeans-java", + "agent.name": "java", + "id": "opbeans-java" + }, + "isInverseEdge": true + } + }, + { + "data": { + "source": "opbeans-ruby", + "target": "opbeans-node", + "id": "opbeans-ruby~opbeans-node", + "sourceData": { + "service.environment": "production", + "service.name": "opbeans-ruby", + "agent.name": "ruby", + "id": "opbeans-ruby" + }, + "targetData": { + "service.environment": "production", + "service.name": "opbeans-node", + "agent.name": "nodejs", + "id": "opbeans-node" + }, + "isInverseEdge": true + } + }, + { + "data": { + "source": "opbeans-ruby", + "target": "opbeans-python", + "id": "opbeans-ruby~opbeans-python", + "sourceData": { + "service.environment": "production", + "service.name": "opbeans-ruby", + "agent.name": "ruby", + "id": "opbeans-ruby" + }, + "targetData": { + "service.environment": "production", + "service.name": "opbeans-python", + "agent.name": "python", + "id": "opbeans-python" + }, + "isInverseEdge": true + } + }, + { + "data": { + "service.environment": null, + "service.name": "client", + "agent.name": "js-base", + "id": "client" + } + }, + { + "data": { + "service.environment": "production", + "service.name": "opbeans-node", + "agent.name": "nodejs", + "id": "opbeans-node" + } + }, + { + "data": { + "service.environment": "production", + "service.name": "opbeans-go", + "agent.name": "go", + "id": "opbeans-go" + } + }, + { + "data": { + "service.environment": "production", + "service.name": "opbeans-java", + "agent.name": "java", + "id": "opbeans-java" + } + }, + { + "data": { + "destination.address": "postgres", + "span.subtype": "postgresql", + "span.type": "db", + "id": ">postgres" + } + }, + { + "data": { + "service.environment": "production", + "service.name": "opbeans-ruby", + "agent.name": "ruby", + "id": "opbeans-ruby" + } + }, + { + "data": { + "service.environment": "production", + "service.name": "opbeans-dotnet", + "agent.name": "dotnet", + "id": "opbeans-dotnet" + } + }, + { + "data": { + "service.environment": "production", + "service.name": "opbeans-python", + "agent.name": "python", + "id": "opbeans-python" + } + }, + { + "data": { + "destination.address": "opbeans-node", + "span.subtype": null, + "span.type": "resource", + "id": ">opbeans-node" + } + }, + { + "data": { + "service.environment": null, + "service.name": "apm-server", + "agent.name": "go", + "id": "apm-server" + } + }, + { + "data": { + "destination.address": "172.17.0.1", + "span.subtype": "http", + "span.type": "external", + "id": ">172.17.0.1" + } + }, + { + "data": { + "service.name": "apm-server", + "agent.name": "go", + "service.environment": null, + "service.framework.name": null, + "id": "apm-server" + } + }, + { + "data": { + "service.name": "opbeans-python", + "agent.name": "python", + "service.environment": null, + "service.framework.name": "django", + "id": "opbeans-python" + } + }, + { + "data": { + "service.name": "opbeans-ruby", + "agent.name": "ruby", + "service.environment": null, + "service.framework.name": "Ruby on Rails", + "id": "opbeans-ruby" + } + }, + { + "data": { + "service.name": "opbeans-node", + "agent.name": "nodejs", + "service.environment": null, + "service.framework.name": "express", + "id": "opbeans-node" + } + }, + { + "data": { + "service.name": "opbeans-go", + "agent.name": "go", + "service.environment": null, + "service.framework.name": "gin", + "id": "opbeans-go" + } + }, + { + "data": { + "service.name": "opbeans-java", + "agent.name": "java", + "service.environment": null, + "service.framework.name": null, + "id": "opbeans-java" + } + }, + { + "data": { + "service.name": "opbeans-dotnet", + "agent.name": "dotnet", + "service.environment": null, + "service.framework.name": "ASP.NET Core", + "id": "opbeans-dotnet" + } + }, + { + "data": { + "service.name": "client", + "agent.name": "js-base", + "service.environment": null, + "service.framework.name": null, + "id": "client" + } + } + ] +} diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/cytoscapeOptions.ts b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/cytoscapeOptions.ts index 87008d8790788..30b36b58cb001 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/cytoscapeOptions.ts +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/cytoscapeOptions.ts @@ -5,6 +5,11 @@ */ import theme from '@elastic/eui/dist/eui_theme_light.json'; import cytoscape from 'cytoscape'; +import { CSSProperties } from 'react'; +import { + DESTINATION_ADDRESS, + SERVICE_NAME +} from '../../../../../../../plugins/apm/common/elasticsearch_fieldnames'; import { defaultIcon, iconForNode } from './icons'; export const animationOptions: cytoscape.AnimationOptions = { @@ -20,7 +25,7 @@ const zIndexEdgeHover = 120; export const nodeHeight = parseInt(theme.avatarSizing.l.size, 10); function isService(el: cytoscape.NodeSingular) { - return el.data('type') === 'service'; + return el.data(SERVICE_NAME) !== undefined; } const style: cytoscape.Stylesheet[] = [ @@ -53,7 +58,8 @@ const style: cytoscape.Stylesheet[] = [ 'ghost-offset-y': 2, 'ghost-opacity': 0.15, height: nodeHeight, - label: 'data(label)', + label: (el: cytoscape.NodeSingular) => + isService(el) ? el.data(SERVICE_NAME) : el.data(DESTINATION_ADDRESS), 'min-zoomed-font-size': theme.euiSizeL, 'overlay-opacity': 0, shape: (el: cytoscape.NodeSingular) => @@ -101,6 +107,12 @@ const style: cytoscape.Stylesheet[] = [ 'target-distance-from-node': theme.paddingSizes.xs } }, + // @ts-ignore DefinitelyTyped says visibility is "none" but it's + // actually "hidden" + { + selector: 'edge[isInverseEdge]', + style: { visibility: 'hidden' } + }, // @ts-ignore { selector: '.invisible', @@ -133,6 +145,28 @@ const style: cytoscape.Stylesheet[] = [ } ]; +// The CSS styles for the div containing the cytoscape element. Makes a +// background grid of dots. +export const cytoscapeDivStyle: CSSProperties = { + background: `linear-gradient( + 90deg, + ${theme.euiPageBackgroundColor} + calc(${theme.euiSizeL} - calc(${theme.euiSizeXS} / 2)), + transparent 1% +) +center, +linear-gradient( + ${theme.euiPageBackgroundColor} + calc(${theme.euiSizeL} - calc(${theme.euiSizeXS} / 2)), + transparent 1% +) +center, +${theme.euiColorLightShade}`, + backgroundSize: `${theme.euiSizeL} ${theme.euiSizeL}`, + margin: `-${theme.gutterTypes.gutterLarge}`, + marginTop: 0 +}; + export const cytoscapeOptions: cytoscape.CytoscapeOptions = { autoungrabify: true, boxSelectionEnabled: false, diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/get_cytoscape_elements.ts b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/get_cytoscape_elements.ts deleted file mode 100644 index 4017aa2e3cdd9..0000000000000 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/get_cytoscape_elements.ts +++ /dev/null @@ -1,77 +0,0 @@ -/* - * 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. - */ -import { ValuesType } from 'utility-types'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { ServiceMapAPIResponse } from '../../../../../../../plugins/apm/server/lib/service_map/get_service_map'; -import { getAPMHref } from '../../shared/Links/apm/APMLink'; - -export function getCytoscapeElements( - response: ServiceMapAPIResponse, - search: string -) { - const { nodes, connections } = response; - - const nodesById = nodes.reduce((nodeMap, node) => { - return { - ...nodeMap, - [node.id]: node - }; - }, {} as Record>); - - const cyNodes = (Object.values(nodesById) as Array< - ValuesType - >).map(node => { - let data = {}; - - if ('service.name' in node) { - data = { - href: getAPMHref( - `/services/${node['service.name']}/service-map`, - search - ), - agentName: node['agent.name'], - frameworkName: node['service.framework.name'], - type: 'service' - }; - } - - if ('span.type' in node) { - data = { - // For nodes with span.type "db", convert it to "database". Otherwise leave it as-is. - type: node['span.type'] === 'db' ? 'database' : node['span.type'], - // Externals should not have a subtype so make it undefined if the type is external. - subtype: node['span.type'] !== 'external' && node['span.subtype'] - }; - } - - return { - group: 'nodes' as const, - data: { - id: node.id, - label: - 'service.name' in node - ? node['service.name'] - : node['destination.address'], - ...data - } - }; - }); - - const cyEdges = connections.map(connection => { - return { - group: 'edges' as const, - classes: connection.isInverseEdge ? 'invisible' : undefined, - data: { - id: connection.id, - source: connection.source.id, - target: connection.destination.id, - bidirectional: connection.bidirectional ? true : undefined - } - }; - }, []); - - return [...cyNodes, ...cyEdges]; -} diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons.ts b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons.ts index 1b57cd52082d8..5102dfc02f757 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons.ts +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons.ts @@ -5,7 +5,13 @@ */ import cytoscape from 'cytoscape'; +import { + AGENT_NAME, + SERVICE_NAME, + SPAN_TYPE +} from '../../../../../../../plugins/apm/common/elasticsearch_fieldnames'; import databaseIcon from './icons/database.svg'; +import defaultIconImport from './icons/default.svg'; import documentsIcon from './icons/documents.svg'; import dotNetIcon from './icons/dot-net.svg'; import globeIcon from './icons/globe.svg'; @@ -16,14 +22,13 @@ import phpIcon from './icons/php.svg'; import pythonIcon from './icons/python.svg'; import rubyIcon from './icons/ruby.svg'; import rumJsIcon from './icons/rumjs.svg'; -import defaultIconImport from './icons/default.svg'; export const defaultIcon = defaultIconImport; // The colors here are taken from the logos of the corresponding technologies const icons: { [key: string]: string } = { cache: databaseIcon, - database: databaseIcon, + db: databaseIcon, external: globeIcon, messaging: documentsIcon, resource: globeIcon @@ -52,10 +57,10 @@ const serviceIcons: { [key: string]: string } = { const isIE11 = !!window.MSInputMethodContext && !!document.documentMode; export function iconForNode(node: cytoscape.NodeSingular) { - const type = node.data('type'); + const type = node.data(SPAN_TYPE); - if (type === 'service') { - return serviceIcons[node.data('agentName') as string]; + if (node.data(SERVICE_NAME)) { + return serviceIcons[node.data(AGENT_NAME) as string]; } else if (isIE11) { return defaultIcon; } else if (icons[type]) { diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/index.tsx b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/index.tsx index 6222a00a9e888..7040c27765a8d 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/index.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/index.tsx @@ -4,22 +4,19 @@ * you may not use this file except in compliance with the Elastic License. */ -import { EuiBetaBadge } from '@elastic/eui'; import theme from '@elastic/eui/dist/eui_theme_light.json'; -import { i18n } from '@kbn/i18n'; -import React, { useMemo } from 'react'; -import styled from 'styled-components'; +import React from 'react'; import { isValidPlatinumLicense } from '../../../../../../../plugins/apm/common/service_map'; import { useDeepObjectIdentity } from '../../../hooks/useDeepObjectIdentity'; import { useFetcher } from '../../../hooks/useFetcher'; import { useLicense } from '../../../hooks/useLicense'; -import { useLocation } from '../../../hooks/useLocation'; import { useUrlParams } from '../../../hooks/useUrlParams'; import { callApmApi } from '../../../services/rest/createCallApmApi'; +import { BetaBadge } from './BetaBadge'; import { Controls } from './Controls'; import { Cytoscape } from './Cytoscape'; +import { cytoscapeDivStyle } from './cytoscapeOptions'; import { EmptyBanner } from './EmptyBanner'; -import { getCytoscapeElements } from './get_cytoscape_elements'; import { PlatinumLicensePrompt } from './PlatinumLicensePrompt'; import { Popover } from './Popover'; import { useRefDimensions } from './useRefDimensions'; @@ -28,35 +25,8 @@ interface ServiceMapProps { serviceName?: string; } -const cytoscapeDivStyle = { - background: `linear-gradient( - 90deg, - ${theme.euiPageBackgroundColor} - calc(${theme.euiSizeL} - calc(${theme.euiSizeXS} / 2)), - transparent 1% -) -center, -linear-gradient( - ${theme.euiPageBackgroundColor} - calc(${theme.euiSizeL} - calc(${theme.euiSizeXS} / 2)), - transparent 1% -) -center, -${theme.euiColorLightShade}`, - backgroundSize: `${theme.euiSizeL} ${theme.euiSizeL}`, - margin: `-${theme.gutterTypes.gutterLarge}`, - marginTop: 0 -}; -const BetaBadgeContainer = styled.div` - right: ${theme.gutterTypes.gutterMedium}; - position: absolute; - top: ${theme.gutterTypes.gutterSmall}; - z-index: 1; /* The element containing the cytoscape canvas has z-index = 0. */ -`; - export function ServiceMap({ serviceName }: ServiceMapProps) { const license = useLicense(); - const { search } = useLocation(); const { urlParams, uiFilters } = useUrlParams(); const params = useDeepObjectIdentity({ start: urlParams.start, @@ -86,10 +56,6 @@ export function ServiceMap({ serviceName }: ServiceMapProps) { } }, [params]); - const elements = useMemo(() => { - return data ? getCytoscapeElements(data as any, search) : []; - }, [data, search]); - const { ref, height, width } = useRefDimensions(); if (!license) { @@ -102,29 +68,16 @@ export function ServiceMap({ serviceName }: ServiceMapProps) { ref={ref} > + {serviceName && } - - - ) : ( diff --git a/x-pack/plugins/apm/common/__snapshots__/elasticsearch_fieldnames.test.ts.snap b/x-pack/plugins/apm/common/__snapshots__/elasticsearch_fieldnames.test.ts.snap index b4b4e7866e9b7..9a557532aae93 100644 --- a/x-pack/plugins/apm/common/__snapshots__/elasticsearch_fieldnames.test.ts.snap +++ b/x-pack/plugins/apm/common/__snapshots__/elasticsearch_fieldnames.test.ts.snap @@ -1,5 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`Error AGENT_NAME 1`] = `"java"`; + exports[`Error CLIENT_GEO_COUNTRY_ISO_CODE 1`] = `undefined`; exports[`Error CONTAINER_ID 1`] = `undefined`; @@ -62,8 +64,6 @@ exports[`Error POD_NAME 1`] = `undefined`; exports[`Error PROCESSOR_EVENT 1`] = `"error"`; -exports[`Error SERVICE_AGENT_NAME 1`] = `"java"`; - exports[`Error SERVICE_ENVIRONMENT 1`] = `undefined`; exports[`Error SERVICE_FRAMEWORK_NAME 1`] = `undefined`; @@ -112,6 +112,8 @@ exports[`Error USER_AGENT_NAME 1`] = `undefined`; exports[`Error USER_ID 1`] = `undefined`; +exports[`Span AGENT_NAME 1`] = `"java"`; + exports[`Span CLIENT_GEO_COUNTRY_ISO_CODE 1`] = `undefined`; exports[`Span CONTAINER_ID 1`] = `undefined`; @@ -174,8 +176,6 @@ exports[`Span POD_NAME 1`] = `undefined`; exports[`Span PROCESSOR_EVENT 1`] = `"span"`; -exports[`Span SERVICE_AGENT_NAME 1`] = `"java"`; - exports[`Span SERVICE_ENVIRONMENT 1`] = `undefined`; exports[`Span SERVICE_FRAMEWORK_NAME 1`] = `undefined`; @@ -224,6 +224,8 @@ exports[`Span USER_AGENT_NAME 1`] = `undefined`; exports[`Span USER_ID 1`] = `undefined`; +exports[`Transaction AGENT_NAME 1`] = `"java"`; + exports[`Transaction CLIENT_GEO_COUNTRY_ISO_CODE 1`] = `undefined`; exports[`Transaction CONTAINER_ID 1`] = `"container1234567890abcdef"`; @@ -286,8 +288,6 @@ exports[`Transaction POD_NAME 1`] = `undefined`; exports[`Transaction PROCESSOR_EVENT 1`] = `"transaction"`; -exports[`Transaction SERVICE_AGENT_NAME 1`] = `"java"`; - exports[`Transaction SERVICE_ENVIRONMENT 1`] = `undefined`; exports[`Transaction SERVICE_FRAMEWORK_NAME 1`] = `undefined`; diff --git a/x-pack/plugins/apm/common/elasticsearch_fieldnames.ts b/x-pack/plugins/apm/common/elasticsearch_fieldnames.ts index 14233aad0f53c..8f1b306a34eb0 100644 --- a/x-pack/plugins/apm/common/elasticsearch_fieldnames.ts +++ b/x-pack/plugins/apm/common/elasticsearch_fieldnames.ts @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ +export const AGENT_NAME = 'agent.name'; export const SERVICE_NAME = 'service.name'; export const SERVICE_ENVIRONMENT = 'service.environment'; -export const SERVICE_AGENT_NAME = 'agent.name'; export const SERVICE_FRAMEWORK_NAME = 'service.framework.name'; export const SERVICE_NODE_NAME = 'service.node.name'; export const SERVICE_VERSION = 'service.version'; diff --git a/x-pack/plugins/apm/common/service_map.ts b/x-pack/plugins/apm/common/service_map.ts index f4354baa97655..8c749cd00bd32 100644 --- a/x-pack/plugins/apm/common/service_map.ts +++ b/x-pack/plugins/apm/common/service_map.ts @@ -6,17 +6,26 @@ import { i18n } from '@kbn/i18n'; import { ILicense } from '../../licensing/public'; +import { + AGENT_NAME, + DESTINATION_ADDRESS, + SERVICE_ENVIRONMENT, + SERVICE_FRAMEWORK_NAME, + SERVICE_NAME, + SPAN_SUBTYPE, + SPAN_TYPE +} from './elasticsearch_fieldnames'; export interface ServiceConnectionNode { - 'service.name': string; - 'service.environment': string | null; - 'service.framework.name': string | null; - 'agent.name': string; + [SERVICE_NAME]: string; + [SERVICE_ENVIRONMENT]: string | null; + [SERVICE_FRAMEWORK_NAME]: string | null; + [AGENT_NAME]: string; } export interface ExternalConnectionNode { - 'destination.address': string; - 'span.type': string; - 'span.subtype': string; + [DESTINATION_ADDRESS]: string; + [SPAN_TYPE]: string; + [SPAN_SUBTYPE]: string; } export type ConnectionNode = ServiceConnectionNode | ExternalConnectionNode; diff --git a/x-pack/plugins/apm/server/lib/metrics/by_agent/java/gc/fetch_and_transform_gc_metrics.ts b/x-pack/plugins/apm/server/lib/metrics/by_agent/java/gc/fetch_and_transform_gc_metrics.ts index 8ffc115a19348..881993610feee 100644 --- a/x-pack/plugins/apm/server/lib/metrics/by_agent/java/gc/fetch_and_transform_gc_metrics.ts +++ b/x-pack/plugins/apm/server/lib/metrics/by_agent/java/gc/fetch_and_transform_gc_metrics.ts @@ -21,7 +21,7 @@ import { ChartBase } from '../../../types'; import { getMetricsProjection } from '../../../../../../common/projections/metrics'; import { mergeProjection } from '../../../../../../common/projections/util/merge_projection'; import { - SERVICE_AGENT_NAME, + AGENT_NAME, LABEL_NAME, METRIC_JAVA_GC_COUNT, METRIC_JAVA_GC_TIME @@ -64,7 +64,7 @@ export async function fetchAndTransformGcMetrics({ filter: [ ...projection.body.query.bool.filter, { exists: { field: fieldName } }, - { term: { [SERVICE_AGENT_NAME]: 'java' } } + { term: { [AGENT_NAME]: 'java' } } ] } }, diff --git a/x-pack/plugins/apm/server/lib/metrics/by_agent/java/heap_memory/index.ts b/x-pack/plugins/apm/server/lib/metrics/by_agent/java/heap_memory/index.ts index 901812815b3f3..c910a2371f4b1 100644 --- a/x-pack/plugins/apm/server/lib/metrics/by_agent/java/heap_memory/index.ts +++ b/x-pack/plugins/apm/server/lib/metrics/by_agent/java/heap_memory/index.ts @@ -10,7 +10,7 @@ import { METRIC_JAVA_HEAP_MEMORY_MAX, METRIC_JAVA_HEAP_MEMORY_COMMITTED, METRIC_JAVA_HEAP_MEMORY_USED, - SERVICE_AGENT_NAME + AGENT_NAME } from '../../../../../../common/elasticsearch_fieldnames'; import { Setup, @@ -71,6 +71,6 @@ export async function getHeapMemoryChart( }, heapMemoryUsed: { avg: { field: METRIC_JAVA_HEAP_MEMORY_USED } } }, - additionalFilters: [{ term: { [SERVICE_AGENT_NAME]: 'java' } }] + additionalFilters: [{ term: { [AGENT_NAME]: 'java' } }] }); } diff --git a/x-pack/plugins/apm/server/lib/metrics/by_agent/java/non_heap_memory/index.ts b/x-pack/plugins/apm/server/lib/metrics/by_agent/java/non_heap_memory/index.ts index 7ff4e073e919b..d997e5b97d516 100644 --- a/x-pack/plugins/apm/server/lib/metrics/by_agent/java/non_heap_memory/index.ts +++ b/x-pack/plugins/apm/server/lib/metrics/by_agent/java/non_heap_memory/index.ts @@ -10,7 +10,7 @@ import { METRIC_JAVA_NON_HEAP_MEMORY_MAX, METRIC_JAVA_NON_HEAP_MEMORY_COMMITTED, METRIC_JAVA_NON_HEAP_MEMORY_USED, - SERVICE_AGENT_NAME + AGENT_NAME } from '../../../../../../common/elasticsearch_fieldnames'; import { Setup, @@ -70,6 +70,6 @@ export async function getNonHeapMemoryChart( avg: { field: METRIC_JAVA_NON_HEAP_MEMORY_USED } } }, - additionalFilters: [{ term: { [SERVICE_AGENT_NAME]: 'java' } }] + additionalFilters: [{ term: { [AGENT_NAME]: 'java' } }] }); } diff --git a/x-pack/plugins/apm/server/lib/metrics/by_agent/java/thread_count/index.ts b/x-pack/plugins/apm/server/lib/metrics/by_agent/java/thread_count/index.ts index cf8e120b00e0d..0f54b3afdff77 100644 --- a/x-pack/plugins/apm/server/lib/metrics/by_agent/java/thread_count/index.ts +++ b/x-pack/plugins/apm/server/lib/metrics/by_agent/java/thread_count/index.ts @@ -8,7 +8,7 @@ import theme from '@elastic/eui/dist/eui_theme_light.json'; import { i18n } from '@kbn/i18n'; import { METRIC_JAVA_THREAD_COUNT, - SERVICE_AGENT_NAME + AGENT_NAME } from '../../../../../../common/elasticsearch_fieldnames'; import { Setup, @@ -57,6 +57,6 @@ export async function getThreadCountChart( threadCount: { avg: { field: METRIC_JAVA_THREAD_COUNT } }, threadCountMax: { max: { field: METRIC_JAVA_THREAD_COUNT } } }, - additionalFilters: [{ term: { [SERVICE_AGENT_NAME]: 'java' } }] + additionalFilters: [{ term: { [AGENT_NAME]: 'java' } }] }); } diff --git a/x-pack/plugins/apm/server/lib/service_map/dedupe_connections.ts b/x-pack/plugins/apm/server/lib/service_map/dedupe_connections.ts index 21f48bd589999..485958cc17afd 100644 --- a/x-pack/plugins/apm/server/lib/service_map/dedupe_connections.ts +++ b/x-pack/plugins/apm/server/lib/service_map/dedupe_connections.ts @@ -5,15 +5,24 @@ */ import { isEqual, sortBy } from 'lodash'; import { ValuesType } from 'utility-types'; -import { ConnectionNode, Connection } from '../../../common/service_map'; +import { + DESTINATION_ADDRESS, + SERVICE_NAME +} from '../../../common/elasticsearch_fieldnames'; +import { + Connection, + ConnectionNode, + ExternalConnectionNode, + ServiceConnectionNode +} from '../../../common/service_map'; import { ConnectionsResponse, ServicesResponse } from './get_service_map'; function getConnectionNodeId(node: ConnectionNode): string { - if ('destination.address' in node) { + if (DESTINATION_ADDRESS in node) { // use a prefix to distinguish exernal destination ids from services - return `>${node['destination.address']}`; + return `>${(node as ExternalConnectionNode)[DESTINATION_ADDRESS]}`; } - return node['service.name']; + return (node as ServiceConnectionNode)[SERVICE_NAME]; } function getConnectionId(connection: Connection) { @@ -29,14 +38,14 @@ export function dedupeConnections(response: ServiceMapResponse) { const serviceNodes = services.map(service => ({ ...service, - id: service['service.name'] + id: service[SERVICE_NAME] })); // maps destination.address to service.name if possible function getConnectionNode(node: ConnectionNode) { let mappedNode: ConnectionNode | undefined; - if ('destination.address' in node) { + if (DESTINATION_ADDRESS in node) { mappedNode = discoveredServices.find(map => isEqual(map.from, node))?.to; } @@ -53,19 +62,21 @@ export function dedupeConnections(response: ServiceMapResponse) { // build connections with mapped nodes const mappedConnections = connections .map(connection => { - const source = getConnectionNode(connection.source); - const destination = getConnectionNode(connection.destination); + const sourceData = getConnectionNode(connection.source); + const targetData = getConnectionNode(connection.destination); return { - source, - destination, - id: getConnectionId({ source, destination }) + source: sourceData.id, + target: targetData.id, + id: getConnectionId({ source: sourceData, destination: targetData }), + sourceData, + targetData }; }) - .filter(connection => connection.source.id !== connection.destination.id); + .filter(connection => connection.source !== connection.target); const nodes = mappedConnections - .flatMap(connection => [connection.source, connection.destination]) + .flatMap(connection => [connection.sourceData, connection.targetData]) .concat(serviceNodes); const dedupedNodes: typeof nodes = []; @@ -100,9 +111,7 @@ export function dedupeConnections(response: ServiceMapResponse) { > >((prev, connection) => { const reversedConnection = prev.find( - c => - c.destination.id === connection.source.id && - c.source.id === connection.destination.id + c => c.target === connection.source && c.source === connection.target ); if (reversedConnection) { @@ -116,8 +125,10 @@ export function dedupeConnections(response: ServiceMapResponse) { return prev.concat(connection); }, []); - return { - nodes: dedupedNodes, - connections: dedupedConnections - }; + // Put everything together in elements, with everything in the "data" property + const elements = [...dedupedConnections, ...dedupedNodes].map(element => ({ + data: element + })); + + return { elements }; } diff --git a/x-pack/plugins/apm/server/lib/service_map/get_service_map.ts b/x-pack/plugins/apm/server/lib/service_map/get_service_map.ts index 96acfb7986c68..1414f743e8a03 100644 --- a/x-pack/plugins/apm/server/lib/service_map/get_service_map.ts +++ b/x-pack/plugins/apm/server/lib/service_map/get_service_map.ts @@ -4,22 +4,23 @@ * you may not use this file except in compliance with the Elastic License. */ import { chunk } from 'lodash'; +import { + AGENT_NAME, + SERVICE_ENVIRONMENT, + SERVICE_FRAMEWORK_NAME, + SERVICE_NAME +} from '../../../common/elasticsearch_fieldnames'; +import { getServicesProjection } from '../../../common/projections/services'; +import { mergeProjection } from '../../../common/projections/util/merge_projection'; import { PromiseReturnType } from '../../../typings/common'; import { Setup, SetupTimeRange, SetupUIFilters } from '../helpers/setup_request'; +import { dedupeConnections } from './dedupe_connections'; import { getServiceMapFromTraceIds } from './get_service_map_from_trace_ids'; import { getTraceSampleIds } from './get_trace_sample_ids'; -import { getServicesProjection } from '../../../common/projections/services'; -import { mergeProjection } from '../../../common/projections/util/merge_projection'; -import { - SERVICE_AGENT_NAME, - SERVICE_NAME, - SERVICE_FRAMEWORK_NAME -} from '../../../common/elasticsearch_fieldnames'; -import { dedupeConnections } from './dedupe_connections'; export interface IEnvOptions { setup: Setup & SetupTimeRange & SetupUIFilters; @@ -104,7 +105,7 @@ async function getServicesData(options: IEnvOptions) { aggs: { agent_name: { terms: { - field: SERVICE_AGENT_NAME + field: AGENT_NAME } }, service_framework_name: { @@ -125,11 +126,11 @@ async function getServicesData(options: IEnvOptions) { return ( response.aggregations?.services.buckets.map(bucket => { return { - 'service.name': bucket.key as string, - 'agent.name': + [SERVICE_NAME]: bucket.key as string, + [AGENT_NAME]: (bucket.agent_name.buckets[0]?.key as string | undefined) || '', - 'service.environment': options.environment || null, - 'service.framework.name': + [SERVICE_ENVIRONMENT]: options.environment || null, + [SERVICE_FRAMEWORK_NAME]: (bucket.service_framework_name.buckets[0]?.key as | string | undefined) || null diff --git a/x-pack/plugins/apm/server/lib/service_map/get_service_map_from_trace_ids.ts b/x-pack/plugins/apm/server/lib/service_map/get_service_map_from_trace_ids.ts index d3711e9582d15..d6d9e9b875408 100644 --- a/x-pack/plugins/apm/server/lib/service_map/get_service_map_from_trace_ids.ts +++ b/x-pack/plugins/apm/server/lib/service_map/get_service_map_from_trace_ids.ts @@ -3,18 +3,20 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { uniq, find } from 'lodash'; -import { Setup } from '../helpers/setup_request'; +import { find, uniq } from 'lodash'; import { - TRACE_ID, - PROCESSOR_EVENT + PROCESSOR_EVENT, + SERVICE_ENVIRONMENT, + SERVICE_NAME, + TRACE_ID } from '../../../common/elasticsearch_fieldnames'; import { Connection, - ServiceConnectionNode, ConnectionNode, - ExternalConnectionNode + ExternalConnectionNode, + ServiceConnectionNode } from '../../../common/service_map'; +import { Setup } from '../helpers/setup_request'; export async function getServiceMapFromTraceIds({ setup, @@ -242,14 +244,15 @@ export async function getServiceMapFromTraceIds({ if (serviceName) { matches = matches && - 'service.name' in node && - node['service.name'] === serviceName; + SERVICE_NAME in node && + (node as ServiceConnectionNode)[SERVICE_NAME] === serviceName; } if (environment) { matches = matches && - 'service.environment' in node && - node['service.environment'] === environment; + SERVICE_ENVIRONMENT in node && + (node as ServiceConnectionNode)[SERVICE_ENVIRONMENT] === + environment; } return matches; }); diff --git a/x-pack/plugins/apm/server/lib/services/get_service_agent_name.ts b/x-pack/plugins/apm/server/lib/services/get_service_agent_name.ts index a1a2c1a38b3d4..a8ed296ea4145 100644 --- a/x-pack/plugins/apm/server/lib/services/get_service_agent_name.ts +++ b/x-pack/plugins/apm/server/lib/services/get_service_agent_name.ts @@ -5,7 +5,7 @@ */ import { PROCESSOR_EVENT, - SERVICE_AGENT_NAME, + AGENT_NAME, SERVICE_NAME } from '../../../common/elasticsearch_fieldnames'; import { rangeFilter } from '../helpers/range_filter'; @@ -39,7 +39,7 @@ export async function getServiceAgentName( }, aggs: { agents: { - terms: { field: SERVICE_AGENT_NAME, size: 1 } + terms: { field: AGENT_NAME, size: 1 } } } } diff --git a/x-pack/plugins/apm/server/lib/services/get_services/get_services_items.ts b/x-pack/plugins/apm/server/lib/services/get_services/get_services_items.ts index 2f44b9231eae2..81fd39a8a8255 100644 --- a/x-pack/plugins/apm/server/lib/services/get_services/get_services_items.ts +++ b/x-pack/plugins/apm/server/lib/services/get_services/get_services_items.ts @@ -7,7 +7,7 @@ import { mergeProjection } from '../../../../common/projections/util/merge_projection'; import { PROCESSOR_EVENT, - SERVICE_AGENT_NAME, + AGENT_NAME, SERVICE_ENVIRONMENT, TRANSACTION_DURATION } from '../../../../common/elasticsearch_fieldnames'; @@ -41,7 +41,7 @@ export async function getServicesItems( avg: { field: TRANSACTION_DURATION } }, agents: { - terms: { field: SERVICE_AGENT_NAME, size: 1 } + terms: { field: AGENT_NAME, size: 1 } }, events: { terms: { field: PROCESSOR_EVENT } diff --git a/x-pack/plugins/apm/server/lib/settings/agent_configuration/get_agent_name_by_service.ts b/x-pack/plugins/apm/server/lib/settings/agent_configuration/get_agent_name_by_service.ts index a9af1f6174fd5..1601aa09df230 100644 --- a/x-pack/plugins/apm/server/lib/settings/agent_configuration/get_agent_name_by_service.ts +++ b/x-pack/plugins/apm/server/lib/settings/agent_configuration/get_agent_name_by_service.ts @@ -9,7 +9,7 @@ import { PROCESSOR_EVENT, SERVICE_NAME } from '../../../../common/elasticsearch_fieldnames'; -import { SERVICE_AGENT_NAME } from '../../../../common/elasticsearch_fieldnames'; +import { AGENT_NAME } from '../../../../common/elasticsearch_fieldnames'; export async function getAgentNameByService({ serviceName, @@ -41,7 +41,7 @@ export async function getAgentNameByService({ }, aggs: { agent_names: { - terms: { field: SERVICE_AGENT_NAME, size: 1 } + terms: { field: AGENT_NAME, size: 1 } } } } diff --git a/x-pack/plugins/apm/server/lib/ui_filters/local_ui_filters/config.ts b/x-pack/plugins/apm/server/lib/ui_filters/local_ui_filters/config.ts index 06e701e9928f6..86ba5e654d0ee 100644 --- a/x-pack/plugins/apm/server/lib/ui_filters/local_ui_filters/config.ts +++ b/x-pack/plugins/apm/server/lib/ui_filters/local_ui_filters/config.ts @@ -7,7 +7,7 @@ import { i18n } from '@kbn/i18n'; import { CONTAINER_ID, POD_NAME, - SERVICE_AGENT_NAME, + AGENT_NAME, HOST_NAME, TRANSACTION_RESULT, SERVICE_VERSION @@ -24,7 +24,7 @@ const filtersByName = { title: i18n.translate('xpack.apm.localFilters.titles.agentName', { defaultMessage: 'Agent name' }), - fieldName: SERVICE_AGENT_NAME + fieldName: AGENT_NAME }, containerId: { title: i18n.translate('xpack.apm.localFilters.titles.containerId', { From ce0722b558a5d8bbf945570e79e8a2eb1d21deb7 Mon Sep 17 00:00:00 2001 From: Gidi Meir Morris Date: Fri, 20 Mar 2020 18:49:16 +0000 Subject: [PATCH 03/31] [Alerting] retains empty AlertsList when filter has removed all items (#60501) Ensure that when the filtering on the AlertList removes all items we show the empty list rather than the Create Your First Alert CTA --- .../alerts_list/components/alerts_list.tsx | 22 ++++++++++++++----- .../apps/triggers_actions_ui/alerts.ts | 14 ++++++++---- .../page_objects/triggers_actions_ui_page.ts | 17 ++++++++++++++ 3 files changed, 43 insertions(+), 10 deletions(-) diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx index a69e276a5fed5..18e79a1d93a10 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx @@ -21,6 +21,7 @@ import { } from '@elastic/eui'; import { useHistory } from 'react-router-dom'; +import { isEmpty } from 'lodash'; import { AlertsContextProvider } from '../../../context/alerts_context'; import { useAppDependencies } from '../../../app_context'; import { ActionType, Alert, AlertTableItem, AlertTypeIndex, Pagination } from '../../../../types'; @@ -411,15 +412,24 @@ export const AlertsList: React.FunctionComponent = () => { ); + const loadedItems = convertAlertsToTableItems(alertsState.data, alertTypesState.data); + + const isFilterApplied = !( + isEmpty(searchText) && + isEmpty(typesFilter) && + isEmpty(actionTypesFilter) + ); + return (
- {convertAlertsToTableItems(alertsState.data, alertTypesState.data).length !== 0 && table} - {convertAlertsToTableItems(alertsState.data, alertTypesState.data).length === 0 && - !alertTypesState.isLoading && - !alertsState.isLoading && - emptyPrompt} - {(alertTypesState.isLoading || alertsState.isLoading) && } + {loadedItems.length || isFilterApplied ? ( + table + ) : alertTypesState.isLoading || alertsState.isLoading ? ( + + ) : ( + emptyPrompt + )} { ]); }); + it('should display an empty list when search removes all alerts', async () => { + await pageObjects.common.navigateToApp('triggersActions'); + await pageObjects.triggersActionsUI.searchAlerts(`An Alert That For Sure Doesn't Exist!`); + + expect(await pageObjects.triggersActionsUI.isAlertsListDisplayed()).to.eql(true); + }); + it('should disable single alert', async () => { const createdAlert = await createAlert(); await pageObjects.common.navigateToApp('triggersActions'); @@ -332,8 +339,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await testSubjects.click('collapsedItemActions'); await testSubjects.click('deleteAlert'); - const emptyPrompt = await testSubjects.find('createFirstAlertEmptyPrompt'); - expect(await emptyPrompt.elementHasClass('euiEmptyPrompt')).to.be(true); + + expect(await pageObjects.triggersActionsUI.isAnEmptyAlertsListDisplayed()).to.be(true); }); it('should mute all selection', async () => { @@ -443,8 +450,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await testSubjects.click('deleteAll'); - const emptyPrompt = await testSubjects.find('createFirstAlertEmptyPrompt'); - expect(await emptyPrompt.elementHasClass('euiEmptyPrompt')).to.be(true); + expect(await pageObjects.triggersActionsUI.isAnEmptyAlertsListDisplayed()).to.be(true); }); }); }; diff --git a/x-pack/test/functional_with_es_ssl/page_objects/triggers_actions_ui_page.ts b/x-pack/test/functional_with_es_ssl/page_objects/triggers_actions_ui_page.ts index 8d90d3c84b181..6c41c2cab801e 100644 --- a/x-pack/test/functional_with_es_ssl/page_objects/triggers_actions_ui_page.ts +++ b/x-pack/test/functional_with_es_ssl/page_objects/triggers_actions_ui_page.ts @@ -102,6 +102,23 @@ export function TriggersActionsPageProvider({ getService }: FtrProviderContext) }; }); }, + async isAlertsListDisplayed() { + const table = await find.byCssSelector('[data-test-subj="alertsList"] table'); + return table.isDisplayed(); + }, + async isAnEmptyAlertsListDisplayed() { + await retry.try(async () => { + const table = await find.byCssSelector('[data-test-subj="alertsList"] table'); + const $ = await table.parseDomContent(); + const rows = $.findTestSubjects('alert-row').toArray(); + expect(rows.length).not.to.eql(0); + const emptyRow = await find.byCssSelector( + '[data-test-subj="alertsList"] table .euiTableRow' + ); + expect(await emptyRow.getVisibleText()).not.to.eql('No items found'); + }); + return true; + }, async clickOnAlertInAlertsList(name: string) { await this.searchAlerts(name); await find.clickDisplayedByCssSelector(`[data-test-subj="alertsList"] [title="${name}"]`); From 6d1479fc08147b78454c6a5c1aee2b44d894dfd1 Mon Sep 17 00:00:00 2001 From: Wylie Conlon Date: Fri, 20 Mar 2020 14:59:51 -0400 Subject: [PATCH 04/31] [Lens] Fix bug when removing dimensions from non-XY chart (#60704) --- .../datatable_visualization/visualization.tsx | 1 + .../editor_frame/config_panel_wrapper.tsx | 2 +- x-pack/test/functional/apps/lens/smokescreen.ts | 13 ++++++++++++- x-pack/test/functional/page_objects/lens_page.ts | 13 +++++++++++-- 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/x-pack/legacy/plugins/lens/public/datatable_visualization/visualization.tsx b/x-pack/legacy/plugins/lens/public/datatable_visualization/visualization.tsx index 4248d722d5540..359c06a6a9ebc 100644 --- a/x-pack/legacy/plugins/lens/public/datatable_visualization/visualization.tsx +++ b/x-pack/legacy/plugins/lens/public/datatable_visualization/visualization.tsx @@ -150,6 +150,7 @@ export const datatableVisualization: Visualization< accessors: sortedColumns, supportsMoreColumns: true, filterOperations: () => true, + dataTestSubj: 'lnsDatatable_column', }, ], }; diff --git a/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/config_panel_wrapper.tsx b/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/config_panel_wrapper.tsx index c2cd0485de67e..da812e948b23f 100644 --- a/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/config_panel_wrapper.tsx +++ b/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/config_panel_wrapper.tsx @@ -129,7 +129,7 @@ function LayerPanels( }, }, visualization: { - activeId: activeVisualization.id, + ...prevState.visualization, state: newVisualizationState, }, stagedPreview: undefined, diff --git a/x-pack/test/functional/apps/lens/smokescreen.ts b/x-pack/test/functional/apps/lens/smokescreen.ts index 317bb0b27e972..5768e51ae5f9f 100644 --- a/x-pack/test/functional/apps/lens/smokescreen.ts +++ b/x-pack/test/functional/apps/lens/smokescreen.ts @@ -9,7 +9,7 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../ftr_provider_context'; // eslint-disable-next-line import/no-default-export -export default function({ getService, getPageObjects, ...rest }: FtrProviderContext) { +export default function({ getService, getPageObjects }: FtrProviderContext) { const PageObjects = getPageObjects([ 'header', 'common', @@ -89,6 +89,17 @@ export default function({ getService, getPageObjects, ...rest }: FtrProviderCont field: 'bytes', }); + await PageObjects.lens.configureDimension({ + dimension: + '[data-test-subj="lnsXY_splitDimensionPanel"] [data-test-subj="lns-empty-dimension"]', + operation: 'terms', + field: '@message.raw', + }); + + await PageObjects.lens.switchToVisualization('lnsChartSwitchPopover_lnsDatatable'); + await PageObjects.lens.removeDimension('lnsDatatable_column'); + await PageObjects.lens.switchToVisualization('lnsChartSwitchPopover_bar_stacked'); + await PageObjects.lens.configureDimension({ dimension: '[data-test-subj="lnsXY_splitDimensionPanel"] [data-test-subj="lns-empty-dimension"]', diff --git a/x-pack/test/functional/page_objects/lens_page.ts b/x-pack/test/functional/page_objects/lens_page.ts index 480814cb02781..1bf637c50b0ba 100644 --- a/x-pack/test/functional/page_objects/lens_page.ts +++ b/x-pack/test/functional/page_objects/lens_page.ts @@ -103,8 +103,8 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont /** * Changes the specified dimension to the specified operation and (optinally) field. * - * @param opts.from - the text of the dimension being changed - * @param opts.to - the desired operation for the dimension + * @param opts.dimension - the selector of the dimension being changed + * @param opts.operation - the desired operation ID for the dimension * @param opts.field - the desired field for the dimension */ async configureDimension(opts: { dimension: string; operation?: string; field?: string }) { @@ -123,6 +123,15 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont } }, + /** + * Removes the dimension matching a specific test subject + */ + async removeDimension(dimensionTestSubj: string) { + await find.clickByCssSelector( + `[data-test-subj="${dimensionTestSubj}"] [data-test-subj="indexPattern-dimensionPopover-remove"]` + ); + }, + /** * Save the current Lens visualization. */ From 67a01a71bdc2d8ef638514040885b8be3b1609c5 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Fri, 20 Mar 2020 12:14:32 -0700 Subject: [PATCH 05/31] Removed restriction on adding multiple connectors of the same action type to an alert (#60720) * Allows multiple action under the same connector for alert * Fixed due to comments * fixed ui issue --- .../action_connector_form/action_form.tsx | 63 ++++++------------- .../connector_add_modal.scss | 4 ++ .../sections/alert_form/alert_add.tsx | 29 ++++----- .../sections/alert_form/alert_edit.tsx | 29 ++++----- .../public/application/type_registry.ts | 2 +- 5 files changed, 47 insertions(+), 80 deletions(-) diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_form.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_form.tsx index 18bc6ad8810a0..4dcbfeaaf1d3a 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_form.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_form.tsx @@ -139,19 +139,6 @@ export const ActionForm = ({ }); } } - - const actionsErrors = actions.reduce( - (acc: Record, alertAction: AlertAction) => { - const actionType = actionTypeRegistry.get(alertAction.actionTypeId); - if (!actionType) { - return { ...acc }; - } - const actionValidationErrors = actionType.validateParams(alertAction.params); - return { ...acc, [alertAction.id]: actionValidationErrors }; - }, - {} - ) as Record; - const getSelectedOptions = (actionItemId: string) => { const val = connectors.find(connector => connector.id === actionItemId); if (!val) { @@ -169,17 +156,16 @@ export const ActionForm = ({ const getActionTypeForm = ( actionItem: AlertAction, actionConnector: ActionConnector, + actionParamsErrors: { + errors: IErrorObject; + }, index: number ) => { const optionsList = connectors .filter( connectorItem => connectorItem.actionTypeId === actionItem.actionTypeId && - (connectorItem.id === actionItem.id || - !actions.find( - (existingAction: AlertAction) => - existingAction.id === connectorItem.id && existingAction.group === actionItem.group - )) + connectorItem.id === actionItem.id ) .map(({ name, id }) => ({ label: name, @@ -189,8 +175,6 @@ export const ActionForm = ({ const actionTypeRegistered = actionTypeRegistry.get(actionConnector.actionTypeId); if (!actionTypeRegistered || actionItem.group !== defaultActionGroupId) return null; const ParamsFieldsComponent = actionTypeRegistered.actionParamsFields; - const actionParamsErrors: { errors: IErrorObject } = - Object.keys(actionsErrors).length > 0 ? actionsErrors[actionItem.id] : { errors: {} }; const checkEnabledResult = checkActionTypeEnabled( actionTypesIndex && actionTypesIndex[actionConnector.actionTypeId] ); @@ -317,9 +301,7 @@ export const ActionForm = ({ } )} onClick={() => { - const updatedActions = actions.filter( - (item: AlertAction) => item.id !== actionItem.id - ); + const updatedActions = actions.filter((_item: AlertAction, i: number) => i !== index); setAlertProperty(updatedActions); setIsAddActionPanelOpen( updatedActions.filter((item: AlertAction) => item.id !== actionItem.id).length === 0 @@ -381,9 +363,7 @@ export const ActionForm = ({ } )} onClick={() => { - const updatedActions = actions.filter( - (item: AlertAction) => item.id !== actionItem.id - ); + const updatedActions = actions.filter((_item: AlertAction, i: number) => i !== index); setAlertProperty(updatedActions); setIsAddActionPanelOpen( updatedActions.filter((item: AlertAction) => item.id !== actionItem.id).length === 0 @@ -441,24 +421,16 @@ export const ActionForm = ({ const actionTypeConnectors = connectors.filter( field => field.actionTypeId === actionTypeModel.id ); - let freeConnectors; if (actionTypeConnectors.length > 0) { - // Should we allow adding multiple actions to the same connector under the alert? - freeConnectors = actionTypeConnectors.filter( - (actionConnector: ActionConnector) => - !actions.find((actionItem: AlertAction) => actionItem.id === actionConnector.id) - ); - if (freeConnectors.length > 0) { - actions.push({ - id: '', - actionTypeId: actionTypeModel.id, - group: defaultActionGroupId, - params: {}, - }); - setActionIdByIndex(freeConnectors[0].id, actions.length - 1); - } + actions.push({ + id: '', + actionTypeId: actionTypeModel.id, + group: defaultActionGroupId, + params: {}, + }); + setActionIdByIndex(actionTypeConnectors[0].id, actions.length - 1); } - if (actionTypeConnectors.length === 0 || !freeConnectors || freeConnectors.length === 0) { + if (actionTypeConnectors.length === 0) { // if no connectors exists or all connectors is already assigned an action under current alert // set actionType as id to be able to create new connector within the alert form actions.push({ @@ -520,7 +492,12 @@ export const ActionForm = ({ if (!actionConnector) { return getAddConnectorsForm(actionItem, index); } - return getActionTypeForm(actionItem, actionConnector, index); + + const actionErrors: { errors: IErrorObject } = actionTypeRegistry + .get(actionItem.actionTypeId) + ?.validateParams(actionItem.params); + + return getActionTypeForm(actionItem, actionConnector, actionErrors, index); })} {isAddActionPanelOpen === false ? ( diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_add_modal.scss b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_add_modal.scss index f8fa882cd617d..7f56c220db4bb 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_add_modal.scss +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_add_modal.scss @@ -1,3 +1,7 @@ .actConnectorModal { z-index: 9000; } + +.euiComboBoxOptionsList { + z-index: 9001; +} diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_add.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_add.tsx index 2ab59a9d10ab9..4e6d63e97ec45 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_add.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_add.tsx @@ -82,25 +82,18 @@ export const AlertAdd = ({ } as IErrorObject; const hasErrors = !!Object.keys(errors).find(errorKey => errors[errorKey].length >= 1); - const actionsErrors = alert.actions.reduce( - (acc: Record, alertAction: AlertAction) => { - const actionType = actionTypeRegistry.get(alertAction.actionTypeId); - if (!actionType) { - return { ...acc }; - } - const actionValidationErrors = actionType.validateParams(alertAction.params); - return { ...acc, [alertAction.id]: actionValidationErrors }; - }, - {} - ) as Record; + const actionsErrors: Array<{ + errors: IErrorObject; + }> = alert.actions.map((alertAction: AlertAction) => + actionTypeRegistry.get(alertAction.actionTypeId)?.validateParams(alertAction.params) + ); - const hasActionErrors = !!Object.entries(actionsErrors) - .map(([, actionErrors]) => actionErrors) - .find((actionErrors: { errors: IErrorObject }) => { - return !!Object.keys(actionErrors.errors).find( - errorKey => actionErrors.errors[errorKey].length >= 1 - ); - }); + const hasActionErrors = + actionsErrors.find( + (errorObj: { errors: IErrorObject }) => + errorObj && + !!Object.keys(errorObj.errors).find(errorKey => errorObj.errors[errorKey].length >= 1) + ) !== undefined; async function onSaveAlert(): Promise { try { diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_edit.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_edit.tsx index cd368193e5fa4..3feceb42e6ddc 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_edit.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_edit.tsx @@ -66,25 +66,18 @@ export const AlertEdit = ({ } as IErrorObject; const hasErrors = !!Object.keys(errors).find(errorKey => errors[errorKey].length >= 1); - const actionsErrors = alert.actions.reduce( - (acc: Record, alertAction: AlertAction) => { - const actionType = actionTypeRegistry.get(alertAction.actionTypeId); - if (!actionType) { - return { ...acc }; - } - const actionValidationErrors = actionType.validateParams(alertAction.params); - return { ...acc, [alertAction.id]: actionValidationErrors }; - }, - {} - ) as Record; + const actionsErrors: Array<{ + errors: IErrorObject; + }> = alert.actions.map((alertAction: AlertAction) => + actionTypeRegistry.get(alertAction.actionTypeId)?.validateParams(alertAction.params) + ); - const hasActionErrors = !!Object.entries(actionsErrors) - .map(([, actionErrors]) => actionErrors) - .find((actionErrors: { errors: IErrorObject }) => { - return !!Object.keys(actionErrors.errors).find( - errorKey => actionErrors.errors[errorKey].length >= 1 - ); - }); + const hasActionErrors = + actionsErrors.find( + (errorObj: { errors: IErrorObject }) => + errorObj && + !!Object.keys(errorObj.errors).find(errorKey => errorObj.errors[errorKey].length >= 1) + ) !== undefined; async function onSaveAlert(): Promise { try { diff --git a/x-pack/plugins/triggers_actions_ui/public/application/type_registry.ts b/x-pack/plugins/triggers_actions_ui/public/application/type_registry.ts index 8eaa9638d0806..f5fe6f96ca8c0 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/type_registry.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/type_registry.ts @@ -41,7 +41,7 @@ export class TypeRegistry { } /** - * Returns an object type, null if not registered + * Returns an object type, throw error if not registered */ public get(id: string): T { if (!this.has(id)) { From b01832249dc45d47b45c4e291a7036cb3fd1c36b Mon Sep 17 00:00:00 2001 From: Jen Huang Date: Fri, 20 Mar 2020 12:18:07 -0700 Subject: [PATCH 06/31] [Ingest] Support input-level config fields (#60594) * Support input-level config fields * Adjust tests * Adjust server schema --- .../datasource_to_agent_datasource.test.ts | 20 +++++- .../datasource_to_agent_datasource.ts | 72 +++++++++++-------- .../common/services/package_to_config.test.ts | 23 +++--- .../common/services/package_to_config.ts | 45 +++++++----- .../common/types/models/datasource.ts | 16 +++-- .../components/datasource_input_config.tsx | 36 ++++------ .../create_datasource_page/step_review.tsx | 15 +++- .../ingest_manager/server/saved_objects.ts | 1 + .../server/types/models/datasource.ts | 23 ++++-- 9 files changed, 153 insertions(+), 98 deletions(-) diff --git a/x-pack/plugins/ingest_manager/common/services/datasource_to_agent_datasource.test.ts b/x-pack/plugins/ingest_manager/common/services/datasource_to_agent_datasource.test.ts index 7b4e4adc4e4fc..ab039be8e7c22 100644 --- a/x-pack/plugins/ingest_manager/common/services/datasource_to_agent_datasource.test.ts +++ b/x-pack/plugins/ingest_manager/common/services/datasource_to_agent_datasource.test.ts @@ -20,12 +20,24 @@ describe('Ingest Manager - storedDatasourceToAgentDatasource', () => { const mockInput: DatasourceInput = { type: 'test-logs', enabled: true, + config: { + inputVar: { value: 'input-value' }, + inputVar2: { value: undefined }, + inputVar3: { + type: 'yaml', + value: 'testField: test', + }, + inputVar4: { value: '' }, + }, streams: [ { id: 'test-logs-foo', enabled: true, dataset: 'foo', - config: { fooVar: { value: 'foo-value' }, fooVar2: { value: [1, 2] } }, + config: { + fooVar: { value: 'foo-value' }, + fooVar2: { value: [1, 2] }, + }, }, { id: 'test-logs-bar', @@ -83,7 +95,7 @@ describe('Ingest Manager - storedDatasourceToAgentDatasource', () => { }); }); - it('returns agent datasource config with flattened stream configs', () => { + it('returns agent datasource config with flattened input and stream configs', () => { expect(storedDatasourceToAgentDatasource({ ...mockDatasource, inputs: [mockInput] })).toEqual({ id: 'mock-datasource', namespace: 'default', @@ -93,6 +105,10 @@ describe('Ingest Manager - storedDatasourceToAgentDatasource', () => { { type: 'test-logs', enabled: true, + inputVar: 'input-value', + inputVar3: { + testField: 'test', + }, streams: [ { id: 'test-logs-foo', diff --git a/x-pack/plugins/ingest_manager/common/services/datasource_to_agent_datasource.ts b/x-pack/plugins/ingest_manager/common/services/datasource_to_agent_datasource.ts index ea048b84afef3..f58eaacb7be67 100644 --- a/x-pack/plugins/ingest_manager/common/services/datasource_to_agent_datasource.ts +++ b/x-pack/plugins/ingest_manager/common/services/datasource_to_agent_datasource.ts @@ -4,13 +4,42 @@ * you may not use this file except in compliance with the Elastic License. */ import { safeLoad } from 'js-yaml'; -import { Datasource, NewDatasource, FullAgentConfigDatasource } from '../types'; +import { + Datasource, + NewDatasource, + DatasourceConfigRecord, + DatasourceConfigRecordEntry, + FullAgentConfigDatasource, +} from '../types'; import { DEFAULT_OUTPUT } from '../constants'; +const configReducer = ( + configResult: DatasourceConfigRecord, + configEntry: [string, DatasourceConfigRecordEntry] +): DatasourceConfigRecord => { + const [configName, { type: configType, value: configValue }] = configEntry; + if (configValue !== undefined && configValue !== '') { + if (configType === 'yaml') { + try { + const yamlValue = safeLoad(configValue); + if (yamlValue) { + configResult[configName] = yamlValue; + } + } catch (e) { + // Silently swallow parsing error + } + } else { + configResult[configName] = configValue; + } + } + return configResult; +}; + export const storedDatasourceToAgentDatasource = ( datasource: Datasource | NewDatasource ): FullAgentConfigDatasource => { const { name, namespace, enabled, package: pkg, inputs } = datasource; + const fullDatasource: FullAgentConfigDatasource = { id: name, namespace, @@ -18,41 +47,22 @@ export const storedDatasourceToAgentDatasource = ( use_output: DEFAULT_OUTPUT.name, // TODO: hardcoded to default output for now inputs: inputs .filter(input => input.enabled) - .map(input => ({ - ...input, - streams: input.streams.map(stream => { - if (stream.config) { + .map(input => { + const fullInput = { + ...input, + ...Object.entries(input.config || {}).reduce(configReducer, {}), + streams: input.streams.map(stream => { const fullStream = { ...stream, - ...Object.entries(stream.config).reduce( - (acc, [configName, { type: configType, value: configValue }]) => { - if (configValue !== undefined) { - if (configType === 'yaml') { - try { - const yamlValue = safeLoad(configValue); - if (yamlValue) { - acc[configName] = yamlValue; - } - } catch (e) { - // Silently swallow parsing error - } - } else { - acc[configName] = configValue; - } - } - return acc; - }, - {} as { [key: string]: any } - ), + ...Object.entries(stream.config || {}).reduce(configReducer, {}), }; delete fullStream.config; return fullStream; - } else { - const fullStream = { ...stream }; - return fullStream; - } - }), - })), + }), + }; + delete fullInput.config; + return fullInput; + }), }; if (pkg) { diff --git a/x-pack/plugins/ingest_manager/common/services/package_to_config.test.ts b/x-pack/plugins/ingest_manager/common/services/package_to_config.test.ts index e54e59dd24df3..5025c9b5288b9 100644 --- a/x-pack/plugins/ingest_manager/common/services/package_to_config.test.ts +++ b/x-pack/plugins/ingest_manager/common/services/package_to_config.test.ts @@ -79,14 +79,14 @@ describe('Ingest Manager - packageToConfig', () => { { type: 'foo', enabled: true, - streams: [{ id: 'foo-foo', enabled: true, dataset: 'foo', config: {} }], + streams: [{ id: 'foo-foo', enabled: true, dataset: 'foo' }], }, { type: 'bar', enabled: true, streams: [ - { id: 'bar-bar', enabled: true, dataset: 'bar', config: {} }, - { id: 'bar-bar2', enabled: true, dataset: 'bar2', config: {} }, + { id: 'bar-bar', enabled: true, dataset: 'bar' }, + { id: 'bar-bar2', enabled: true, dataset: 'bar2' }, ], }, ]); @@ -204,6 +204,11 @@ describe('Ingest Manager - packageToConfig', () => { { type: 'foo', enabled: true, + config: { + 'foo-input-var-name': { value: 'foo-input-var-value' }, + 'foo-input2-var-name': { value: 'foo-input2-var-value' }, + 'foo-input3-var-name': { value: undefined }, + }, streams: [ { id: 'foo-foo', @@ -211,9 +216,6 @@ describe('Ingest Manager - packageToConfig', () => { dataset: 'foo', config: { 'var-name': { value: 'foo-var-value' }, - 'foo-input-var-name': { value: 'foo-input-var-value' }, - 'foo-input2-var-name': { value: 'foo-input2-var-value' }, - 'foo-input3-var-name': { value: undefined }, }, }, ], @@ -221,6 +223,10 @@ describe('Ingest Manager - packageToConfig', () => { { type: 'bar', enabled: true, + config: { + 'bar-input-var-name': { value: ['value1', 'value2'] }, + 'bar-input2-var-name': { value: 123456 }, + }, streams: [ { id: 'bar-bar', @@ -228,8 +234,6 @@ describe('Ingest Manager - packageToConfig', () => { dataset: 'bar', config: { 'var-name': { value: 'bar-var-value' }, - 'bar-input-var-name': { value: ['value1', 'value2'] }, - 'bar-input2-var-name': { value: 123456 }, }, }, { @@ -238,8 +242,6 @@ describe('Ingest Manager - packageToConfig', () => { dataset: 'bar2', config: { 'var-name': { value: 'bar2-var-value' }, - 'bar-input-var-name': { value: ['value1', 'value2'] }, - 'bar-input2-var-name': { value: 123456 }, }, }, ], @@ -260,7 +262,6 @@ describe('Ingest Manager - packageToConfig', () => { id: 'with-disabled-streams-disabled2', enabled: false, dataset: 'disabled2', - config: {}, }, ], }, diff --git a/x-pack/plugins/ingest_manager/common/services/package_to_config.ts b/x-pack/plugins/ingest_manager/common/services/package_to_config.ts index 6de75a004303e..8848fa6a9cf48 100644 --- a/x-pack/plugins/ingest_manager/common/services/package_to_config.ts +++ b/x-pack/plugins/ingest_manager/common/services/package_to_config.ts @@ -8,6 +8,8 @@ import { RegistryDatasource, RegistryVarsEntry, Datasource, + DatasourceConfigRecord, + DatasourceConfigRecordEntry, DatasourceInput, DatasourceInputStream, NewDatasource, @@ -27,32 +29,33 @@ export const packageToConfigDatasourceInputs = (packageInfo: PackageInfo): Datas if (packageDatasource?.inputs?.length) { // Map each package datasource input to agent config datasource input packageDatasource.inputs.forEach(packageInput => { + // Reduces registry var def into config object entry + const varsReducer = ( + configObject: DatasourceConfigRecord, + registryVar: RegistryVarsEntry + ): DatasourceConfigRecord => { + const configEntry: DatasourceConfigRecordEntry = { + value: !registryVar.default && registryVar.multi ? [] : registryVar.default, + }; + if (registryVar.type) { + configEntry.type = registryVar.type; + } + configObject![registryVar.name] = configEntry; + return configObject; + }; + // Map each package input stream into datasource input stream const streams: DatasourceInputStream[] = packageInput.streams ? packageInput.streams.map(packageStream => { - // Copy input vars into each stream's vars - const streamVars: RegistryVarsEntry[] = [ - ...(packageInput.vars || []), - ...(packageStream.vars || []), - ]; - const streamConfig = {}; - const streamVarsReducer = ( - configObject: DatasourceInputStream['config'], - streamVar: RegistryVarsEntry - ): DatasourceInputStream['config'] => { - if (!streamVar.default && streamVar.multi) { - configObject![streamVar.name] = { type: streamVar.type, value: [] }; - } else { - configObject![streamVar.name] = { type: streamVar.type, value: streamVar.default }; - } - return configObject; - }; - return { + const stream: DatasourceInputStream = { id: `${packageInput.type}-${packageStream.dataset}`, enabled: packageStream.enabled === false ? false : true, dataset: packageStream.dataset, - config: streamVars.reduce(streamVarsReducer, streamConfig), }; + if (packageStream.vars && packageStream.vars.length) { + stream.config = packageStream.vars.reduce(varsReducer, {}); + } + return stream; }) : []; @@ -62,6 +65,10 @@ export const packageToConfigDatasourceInputs = (packageInfo: PackageInfo): Datas streams, }; + if (packageInput.vars && packageInput.vars.length) { + input.config = packageInput.vars.reduce(varsReducer, {}); + } + inputs.push(input); }); } diff --git a/x-pack/plugins/ingest_manager/common/types/models/datasource.ts b/x-pack/plugins/ingest_manager/common/types/models/datasource.ts index c6a2e0252492b..ee4d24ab11777 100644 --- a/x-pack/plugins/ingest_manager/common/types/models/datasource.ts +++ b/x-pack/plugins/ingest_manager/common/types/models/datasource.ts @@ -10,24 +10,26 @@ export interface DatasourcePackage { version: string; } +export interface DatasourceConfigRecordEntry { + type?: string; + value?: any; +} + +export type DatasourceConfigRecord = Record; + export interface DatasourceInputStream { id: string; enabled: boolean; dataset: string; processors?: string[]; - config?: Record< - string, - { - type?: string; - value?: any; - } - >; + config?: DatasourceConfigRecord; } export interface DatasourceInput { type: string; enabled: boolean; processors?: string[]; + config?: DatasourceConfigRecord; streams: DatasourceInputStream[]; } diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/components/datasource_input_config.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/components/datasource_input_config.tsx index 1128f25818d7c..356739af1ff9a 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/components/datasource_input_config.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/components/datasource_input_config.tsx @@ -55,7 +55,7 @@ export const DatasourceInputConfig: React.FunctionComponent<{

@@ -64,7 +64,7 @@ export const DatasourceInputConfig: React.FunctionComponent<{ {requiredVars.map(varDef => { const { name: varName, type: varType } = varDef; - const value = datasourceInput.streams[0].config![varName].value; + const value = datasourceInput.config![varName].value; return ( { updateDatasourceInput({ - streams: datasourceInput.streams.map(stream => ({ - ...stream, - config: { - ...stream.config, - [varName]: { - type: varType, - value: newValue, - }, + config: { + ...datasourceInput.config, + [varName]: { + type: varType, + value: newValue, }, - })), + }, }); }} /> @@ -109,7 +106,7 @@ export const DatasourceInputConfig: React.FunctionComponent<{ {isShowingAdvanced ? advancedVars.map(varDef => { const { name: varName, type: varType } = varDef; - const value = datasourceInput.streams[0].config![varName].value; + const value = datasourceInput.config![varName].value; return ( { updateDatasourceInput({ - streams: datasourceInput.streams.map(stream => ({ - ...stream, - config: { - ...stream.config, - [varName]: { - type: varType, - value: newValue, - }, + config: { + ...datasourceInput.config, + [varName]: { + type: varType, + value: newValue, }, - })), + }, }); }} /> diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/step_review.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/step_review.tsx index 355bf2febdf5f..20af5954c1436 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/step_review.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_config/create_datasource_page/step_review.tsx @@ -24,6 +24,8 @@ import { NewDatasource, AgentConfig } from '../../../types'; import { useConfig, sendGetAgentStatus } from '../../../hooks'; import { storedDatasourceToAgentDatasource } from '../../../services'; +const KEYS_TO_SINK = ['inputs', 'streams']; + export const StepReviewDatasource: React.FunctionComponent<{ agentConfig: AgentConfig; datasource: NewDatasource; @@ -119,7 +121,18 @@ export const StepReviewDatasource: React.FunctionComponent<{ - {dump(fullAgentDatasource)} + {dump(fullAgentDatasource, { + sortKeys: (a: string, b: string) => { + // Make YAML output prettier by sinking certain fields + if (KEYS_TO_SINK.indexOf(a) > -1) { + return 1; + } + if (KEYS_TO_SINK.indexOf(b) > -1) { + return -1; + } + return 0; + }, + })} ), diff --git a/x-pack/plugins/ingest_manager/server/saved_objects.ts b/x-pack/plugins/ingest_manager/server/saved_objects.ts index b1a9d14ed6e86..9f3035e1aac17 100644 --- a/x-pack/plugins/ingest_manager/server/saved_objects.ts +++ b/x-pack/plugins/ingest_manager/server/saved_objects.ts @@ -128,6 +128,7 @@ export const savedObjectMappings = { type: { type: 'keyword' }, enabled: { type: 'boolean' }, processors: { type: 'keyword' }, + config: { type: 'flattened' }, streams: { type: 'nested', properties: { diff --git a/x-pack/plugins/ingest_manager/server/types/models/datasource.ts b/x-pack/plugins/ingest_manager/server/types/models/datasource.ts index 933453e0a5b36..c0cfee8f231c9 100644 --- a/x-pack/plugins/ingest_manager/server/types/models/datasource.ts +++ b/x-pack/plugins/ingest_manager/server/types/models/datasource.ts @@ -25,18 +25,29 @@ const DatasourceBaseSchema = { type: schema.string(), enabled: schema.boolean(), processors: schema.maybe(schema.arrayOf(schema.string())), + config: schema.maybe( + schema.recordOf( + schema.string(), + schema.object({ + type: schema.maybe(schema.string()), + value: schema.maybe(schema.any()), + }) + ) + ), streams: schema.arrayOf( schema.object({ id: schema.string(), enabled: schema.boolean(), dataset: schema.string(), processors: schema.maybe(schema.arrayOf(schema.string())), - config: schema.recordOf( - schema.string(), - schema.object({ - type: schema.maybe(schema.string()), - value: schema.maybe(schema.any()), - }) + config: schema.maybe( + schema.recordOf( + schema.string(), + schema.object({ + type: schema.maybe(schema.string()), + value: schema.maybe(schema.any()), + }) + ) ), }) ), From d896292b6fe91a11a31931b990a10bf0c99cc94f Mon Sep 17 00:00:00 2001 From: Tim Sullivan Date: Fri, 20 Mar 2020 12:37:22 -0700 Subject: [PATCH 07/31] [Reporting] revert skip telemetry step (#60450) Co-authored-by: Elastic Machine --- .../common/lib/screenshots/observable.ts | 2 -- .../common/lib/screenshots/skip_telemetry.ts | 34 ------------------- 2 files changed, 36 deletions(-) delete mode 100644 x-pack/legacy/plugins/reporting/export_types/common/lib/screenshots/skip_telemetry.ts diff --git a/x-pack/legacy/plugins/reporting/export_types/common/lib/screenshots/observable.ts b/x-pack/legacy/plugins/reporting/export_types/common/lib/screenshots/observable.ts index 878a9d3b87393..44c04c763f840 100644 --- a/x-pack/legacy/plugins/reporting/export_types/common/lib/screenshots/observable.ts +++ b/x-pack/legacy/plugins/reporting/export_types/common/lib/screenshots/observable.ts @@ -12,7 +12,6 @@ import { getNumberOfItems } from './get_number_of_items'; import { getScreenshots } from './get_screenshots'; import { getTimeRange } from './get_time_range'; import { openUrl } from './open_url'; -import { skipTelemetry } from './skip_telemetry'; import { ScreenSetupData, ScreenshotObservableOpts, ScreenshotResults } from './types'; import { waitForRenderComplete } from './wait_for_render'; import { waitForVisualizations } from './wait_for_visualizations'; @@ -43,7 +42,6 @@ export function screenshotsObservableFactory( const setup$: Rx.Observable = Rx.of(1).pipe( takeUntil(exit$), mergeMap(() => openUrl(server, driver, url, conditionalHeaders, logger)), - mergeMap(() => skipTelemetry(driver, logger)), mergeMap(() => getNumberOfItems(server, driver, layout, logger)), mergeMap(async itemsCount => { const viewport = layout.getViewport(itemsCount); diff --git a/x-pack/legacy/plugins/reporting/export_types/common/lib/screenshots/skip_telemetry.ts b/x-pack/legacy/plugins/reporting/export_types/common/lib/screenshots/skip_telemetry.ts deleted file mode 100644 index 1762a78f22720..0000000000000 --- a/x-pack/legacy/plugins/reporting/export_types/common/lib/screenshots/skip_telemetry.ts +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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. - */ - -import { HeadlessChromiumDriver as HeadlessBrowser } from '../../../../server/browsers/chromium/driver'; -import { LevelLogger } from '../../../../server/lib'; -import { CONTEXT_SKIPTELEMETRY } from './constants'; - -const LAST_REPORT_STORAGE_KEY = 'xpack.data'; - -export async function skipTelemetry(browser: HeadlessBrowser, logger: LevelLogger) { - const storageData = await browser.evaluate( - { - fn: storageKey => { - // set something - const optOutJSON = JSON.stringify({ lastReport: Date.now() }); - localStorage.setItem(storageKey, optOutJSON); - - // get it - const session = localStorage.getItem(storageKey); - - // return it - return session; - }, - args: [LAST_REPORT_STORAGE_KEY], - }, - { context: CONTEXT_SKIPTELEMETRY }, - logger - ); - - logger.debug(`added data to localStorage to skip telmetry: ${storageData}`); -} From 0bf62cbf3e792854bb3e1b9c350a065161a916b7 Mon Sep 17 00:00:00 2001 From: Chandler Prall Date: Fri, 20 Mar 2020 14:07:04 -0600 Subject: [PATCH 08/31] Upgrade EUI to 21.0.1 (#60282) * update to eui 21.0.1 * most changes needed for search bar ts changes * Passing types * snapshots * jest tests * Removed IQuery placeholder types * Updated functional test to only look at table headers with content * Moved 'filters' definition around in api docs * Update types * update snapshot * typo * Move DATA_FRAME_TASK_STATE enum to its own file to fix x-pack functional test config imports * merge public api 'changes' Co-authored-by: patrykkopycinski Co-authored-by: Patryk Kopycinski --- ...na-plugin-plugins-data-public.filterbar.md | 2 +- ...na-plugin-plugins-data-public.searchbar.md | 4 +- package.json | 2 +- packages/kbn-ui-shared-deps/package.json | 2 +- .../__snapshots__/agg.test.tsx.snap | 1 + .../value_axes_panel.test.tsx.snap | 2 + .../value_axis_options.test.tsx.snap | 1 + .../management_app/advanced_settings.tsx | 15 +- .../components/search/search.tsx | 19 +- .../public/management_app/types.ts | 6 - src/plugins/data/public/public.api.md | 6 +- .../_index_pattern_create_delete.js | 1 - .../plugins/kbn_tp_run_pipeline/package.json | 2 +- .../kbn_tp_custom_visualizations/package.json | 2 +- .../kbn_tp_embeddable_explorer/package.json | 2 +- .../kbn_tp_sample_panel_action/package.json | 2 +- typings/@elastic/eui/index.d.ts | 4 - .../__test__/__snapshots__/List.test.tsx.snap | 8 +- .../__snapshots__/Stackframe.test.tsx.snap | 1 + .../canvas/.storybook/storyshots.test.js | 6 + .../custom_element_modal.examples.storyshot | 8 + .../file_upload.stories.storyshot | 2 + .../__snapshots__/view.test.js.snap | 1 + .../__snapshots__/ccr_shard.test.js.snap | 1 + .../note_card_body.test.tsx.snap | 47 +- .../timelines_table/common_columns.test.tsx | 6 +- .../timelines_table/extended_columns.test.tsx | 2 +- .../timelines_table/index.test.tsx | 4 +- .../__snapshots__/index.test.tsx.snap | 4 + .../__snapshots__/index.test.tsx.snap | 3 + .../__snapshots__/index.test.tsx.snap | 47 +- .../modal_all_errors.test.tsx.snap | 1 + .../__snapshots__/monitor_list.test.tsx.snap | 4 +- x-pack/package.json | 2 +- .../endpoint/view/alerts/index.test.tsx | 11 + .../template_table/template_table.tsx | 33 +- .../request_trial_extension.test.js.snap | 8 +- .../upload_license.test.tsx.snap | 18 +- .../analytics_list/analytics_list.tsx | 10 +- .../components/analytics_list/common.ts | 31 +- .../analytics_list/data_frame_task_state.ts | 17 + .../components/fields_panel/fields_panel.tsx | 2 +- .../remote_cluster_form.test.js.snap | 1730 ++++++++--------- .../report_listing.test.tsx.snap | 3 +- .../public/components/report_listing.tsx | 2 +- .../components/transform_list/common.ts | 20 +- .../transform_list/transform_list.tsx | 16 +- .../watch_list/components/watch_list.tsx | 45 +- .../machine_learning/data_frame_analytics.ts | 2 +- x-pack/typings/@elastic/eui/index.d.ts | 4 - yarn.lock | 23 +- 51 files changed, 1113 insertions(+), 1082 deletions(-) create mode 100644 x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/data_frame_task_state.ts diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.filterbar.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.filterbar.md index 016adffd0d7f4..6d8862323792a 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.filterbar.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.filterbar.md @@ -7,7 +7,7 @@ Signature: ```typescript -FilterBar: React.ComponentClass, any> & { +FilterBar: React.ComponentClass, any> & { WrappedComponent: React.ComponentType; } ``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchbar.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchbar.md index 89c5ca800a4d4..a0b879673e553 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchbar.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchbar.md @@ -7,7 +7,7 @@ Signature: ```typescript -SearchBar: React.ComponentClass, "query" | "isLoading" | "indexPatterns" | "filters" | "refreshInterval" | "screenTitle" | "dataTestSubj" | "customSubmitButton" | "showQueryBar" | "showQueryInput" | "showFilterBar" | "showDatePicker" | "showAutoRefreshOnly" | "isRefreshPaused" | "dateRangeFrom" | "dateRangeTo" | "showSaveQuery" | "savedQuery" | "onQueryChange" | "onQuerySubmit" | "onSaved" | "onSavedQueryUpdated" | "onClearSavedQuery" | "onRefresh" | "timeHistory" | "onFiltersUpdated" | "onRefreshChange">, any> & { - WrappedComponent: React.ComponentType & ReactIntl.InjectedIntlProps>; +SearchBar: React.ComponentClass, "query" | "isLoading" | "filters" | "indexPatterns" | "refreshInterval" | "screenTitle" | "dataTestSubj" | "customSubmitButton" | "showQueryBar" | "showQueryInput" | "showFilterBar" | "showDatePicker" | "showAutoRefreshOnly" | "isRefreshPaused" | "dateRangeFrom" | "dateRangeTo" | "showSaveQuery" | "savedQuery" | "onQueryChange" | "onQuerySubmit" | "onSaved" | "onSavedQueryUpdated" | "onClearSavedQuery" | "onRefresh" | "timeHistory" | "onFiltersUpdated" | "onRefreshChange">, any> & { + WrappedComponent: React.ComponentType & ReactIntl.InjectedIntlProps>; } ``` diff --git a/package.json b/package.json index ba0bb5c56ef18..3421bf938cd80 100644 --- a/package.json +++ b/package.json @@ -121,7 +121,7 @@ "@elastic/charts": "^18.1.0", "@elastic/datemath": "5.0.2", "@elastic/ems-client": "7.7.0", - "@elastic/eui": "20.0.2", + "@elastic/eui": "21.0.1", "@elastic/filesaver": "1.1.2", "@elastic/good": "8.1.1-kibana2", "@elastic/numeral": "2.4.0", diff --git a/packages/kbn-ui-shared-deps/package.json b/packages/kbn-ui-shared-deps/package.json index c4c93f1658dd3..1e9ceb42433f0 100644 --- a/packages/kbn-ui-shared-deps/package.json +++ b/packages/kbn-ui-shared-deps/package.json @@ -11,7 +11,7 @@ "devDependencies": { "@elastic/charts": "^18.1.0", "abortcontroller-polyfill": "^1.4.0", - "@elastic/eui": "20.0.2", + "@elastic/eui": "21.0.1", "@kbn/babel-preset": "1.0.0", "@kbn/dev-utils": "1.0.0", "@kbn/i18n": "1.0.0", diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/__snapshots__/agg.test.tsx.snap b/src/legacy/core_plugins/vis_default_editor/public/components/__snapshots__/agg.test.tsx.snap index ba5f2ae975cbe..5200fee45d6b3 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/__snapshots__/agg.test.tsx.snap +++ b/src/legacy/core_plugins/vis_default_editor/public/components/__snapshots__/agg.test.tsx.snap @@ -3,6 +3,7 @@ exports[`DefaultEditorAgg component should init with the default set of props 1`] = ` diff --git a/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/__snapshots__/value_axes_panel.test.tsx.snap b/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/__snapshots__/value_axes_panel.test.tsx.snap index 0b673a819f666..ab3e273f99c05 100644 --- a/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/__snapshots__/value_axes_panel.test.tsx.snap +++ b/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/__snapshots__/value_axes_panel.test.tsx.snap @@ -46,6 +46,7 @@ exports[`ValueAxesPanel component should init with the default set of props 1`] /> @@ -226,6 +227,7 @@ exports[`ValueAxesPanel component should init with the default set of props 1`] diff --git a/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/__snapshots__/value_axis_options.test.tsx.snap b/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/__snapshots__/value_axis_options.test.tsx.snap index 00e1b1cce5ea8..b89d193c7c751 100644 --- a/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/__snapshots__/value_axis_options.test.tsx.snap +++ b/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/__snapshots__/value_axis_options.test.tsx.snap @@ -118,6 +118,7 @@ exports[`ValueAxisOptions component should init with the default set of props 1` /> ; } @@ -156,7 +149,7 @@ export class AdvancedSettingsComponent extends Component< }, {}); } - onQueryChange = ({ query }: { query: IQuery }) => { + onQueryChange = ({ query }: { query: Query }) => { this.setState({ query, filteredSettings: this.mapSettings(Query.execute(query, this.settings)), diff --git a/src/plugins/advanced_settings/public/management_app/components/search/search.tsx b/src/plugins/advanced_settings/public/management_app/components/search/search.tsx index 51402296a44a2..74e4894a27a6d 100644 --- a/src/plugins/advanced_settings/public/management_app/components/search/search.tsx +++ b/src/plugins/advanced_settings/public/management_app/components/search/search.tsx @@ -19,19 +19,14 @@ import React, { Fragment, PureComponent } from 'react'; import { i18n } from '@kbn/i18n'; -import { - // @ts-ignore - EuiSearchBar, - EuiFormErrorText, -} from '@elastic/eui'; -import { IQuery } from '../../types'; +import { EuiSearchBar, EuiFormErrorText, Query } from '@elastic/eui'; import { getCategoryName } from '../../lib'; interface SearchProps { categories: string[]; - query: IQuery; - onQueryChange: ({ query }: { query: IQuery }) => void; + query: Query; + onQueryChange: ({ query }: { query: Query }) => void; } export class Search extends PureComponent { @@ -53,7 +48,7 @@ export class Search extends PureComponent { parseErrorMessage: null, }; - onChange = ({ query, error }: { query: IQuery; error: { message: string } }) => { + onChange = ({ query, error }: { query: Query | null; error: { message: string } | null }) => { if (error) { this.setState({ isSearchTextValid: false, @@ -66,7 +61,7 @@ export class Search extends PureComponent { isSearchTextValid: true, parseErrorMessage: null, }); - this.props.onQueryChange({ query }); + this.props.onQueryChange({ query: query! }); }; render() { @@ -82,12 +77,12 @@ export class Search extends PureComponent { const filters = [ { - type: 'field_value_selection', + type: 'field_value_selection' as const, field: 'category', name: i18n.translate('advancedSettings.categorySearchLabel', { defaultMessage: 'Category', }), - multiSelect: 'or', + multiSelect: 'or' as const, options: this.categories, }, ]; diff --git a/src/plugins/advanced_settings/public/management_app/types.ts b/src/plugins/advanced_settings/public/management_app/types.ts index ee9b9b0535b79..6e243926f7d7d 100644 --- a/src/plugins/advanced_settings/public/management_app/types.ts +++ b/src/plugins/advanced_settings/public/management_app/types.ts @@ -54,9 +54,3 @@ export interface FieldState { isInvalid?: boolean; error?: string | null; } - -export interface IQuery { - ast: any; // incomplete - text: string; - syntax: any; // incomplete -} diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md index 45ac5a3e12531..dad3a8e639bc5 100644 --- a/src/plugins/data/public/public.api.md +++ b/src/plugins/data/public/public.api.md @@ -513,7 +513,7 @@ export interface Filter { // Warning: (ae-missing-release-tag) "FilterBar" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export const FilterBar: React.ComponentClass, any> & { +export const FilterBar: React.ComponentClass, any> & { WrappedComponent: React.ComponentType; }; @@ -1531,8 +1531,8 @@ export const search: { // Warning: (ae-missing-release-tag) "SearchBar" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export const SearchBar: React.ComponentClass, "query" | "isLoading" | "indexPatterns" | "filters" | "refreshInterval" | "screenTitle" | "dataTestSubj" | "customSubmitButton" | "showQueryBar" | "showQueryInput" | "showFilterBar" | "showDatePicker" | "showAutoRefreshOnly" | "isRefreshPaused" | "dateRangeFrom" | "dateRangeTo" | "showSaveQuery" | "savedQuery" | "onQueryChange" | "onQuerySubmit" | "onSaved" | "onSavedQueryUpdated" | "onClearSavedQuery" | "onRefresh" | "timeHistory" | "onFiltersUpdated" | "onRefreshChange">, any> & { - WrappedComponent: React.ComponentType & ReactIntl.InjectedIntlProps>; +export const SearchBar: React.ComponentClass, "query" | "isLoading" | "filters" | "indexPatterns" | "refreshInterval" | "screenTitle" | "dataTestSubj" | "customSubmitButton" | "showQueryBar" | "showQueryInput" | "showFilterBar" | "showDatePicker" | "showAutoRefreshOnly" | "isRefreshPaused" | "dateRangeFrom" | "dateRangeTo" | "showSaveQuery" | "savedQuery" | "onQueryChange" | "onQuerySubmit" | "onSaved" | "onSavedQueryUpdated" | "onClearSavedQuery" | "onRefresh" | "timeHistory" | "onFiltersUpdated" | "onRefreshChange">, any> & { + WrappedComponent: React.ComponentType & ReactIntl.InjectedIntlProps>; }; // Warning: (ae-forgotten-export) The symbol "SearchBarOwnProps" needs to be exported by the entry point index.d.ts diff --git a/test/functional/apps/management/_index_pattern_create_delete.js b/test/functional/apps/management/_index_pattern_create_delete.js index 61228744adcdc..4661c9b4d53b8 100644 --- a/test/functional/apps/management/_index_pattern_create_delete.js +++ b/test/functional/apps/management/_index_pattern_create_delete.js @@ -94,7 +94,6 @@ export default function({ getService, getPageObjects }) { 'Searchable', 'Aggregatable', 'Excluded', - '', ]; expect(headers.length).to.be(expectedHeaders.length); diff --git a/test/interpreter_functional/plugins/kbn_tp_run_pipeline/package.json b/test/interpreter_functional/plugins/kbn_tp_run_pipeline/package.json index 594823ad047a7..611e16e5a942d 100644 --- a/test/interpreter_functional/plugins/kbn_tp_run_pipeline/package.json +++ b/test/interpreter_functional/plugins/kbn_tp_run_pipeline/package.json @@ -7,7 +7,7 @@ }, "license": "Apache-2.0", "dependencies": { - "@elastic/eui": "20.0.2", + "@elastic/eui": "21.0.1", "react": "^16.12.0", "react-dom": "^16.12.0" } diff --git a/test/plugin_functional/plugins/kbn_tp_custom_visualizations/package.json b/test/plugin_functional/plugins/kbn_tp_custom_visualizations/package.json index 56f5719b5dbef..344aae30b5bbc 100644 --- a/test/plugin_functional/plugins/kbn_tp_custom_visualizations/package.json +++ b/test/plugin_functional/plugins/kbn_tp_custom_visualizations/package.json @@ -7,7 +7,7 @@ }, "license": "Apache-2.0", "dependencies": { - "@elastic/eui": "20.0.2", + "@elastic/eui": "21.0.1", "react": "^16.12.0" } } diff --git a/test/plugin_functional/plugins/kbn_tp_embeddable_explorer/package.json b/test/plugin_functional/plugins/kbn_tp_embeddable_explorer/package.json index d12c15d0688b2..3b3d69c06ff3e 100644 --- a/test/plugin_functional/plugins/kbn_tp_embeddable_explorer/package.json +++ b/test/plugin_functional/plugins/kbn_tp_embeddable_explorer/package.json @@ -8,7 +8,7 @@ }, "license": "Apache-2.0", "dependencies": { - "@elastic/eui": "20.0.2", + "@elastic/eui": "21.0.1", "react": "^16.12.0" }, "scripts": { diff --git a/test/plugin_functional/plugins/kbn_tp_sample_panel_action/package.json b/test/plugin_functional/plugins/kbn_tp_sample_panel_action/package.json index eb24035f9acbe..8bc9afbc803a5 100644 --- a/test/plugin_functional/plugins/kbn_tp_sample_panel_action/package.json +++ b/test/plugin_functional/plugins/kbn_tp_sample_panel_action/package.json @@ -8,7 +8,7 @@ }, "license": "Apache-2.0", "dependencies": { - "@elastic/eui": "20.0.2", + "@elastic/eui": "21.0.1", "react": "^16.12.0" }, "scripts": { diff --git a/typings/@elastic/eui/index.d.ts b/typings/@elastic/eui/index.d.ts index db07861d63cfe..30c96ba91d405 100644 --- a/typings/@elastic/eui/index.d.ts +++ b/typings/@elastic/eui/index.d.ts @@ -19,7 +19,3 @@ import { Direction } from '@elastic/eui/src/services/sort/sort_direction'; // TODO: Remove once typescript definitions are in EUI - -declare module '@elastic/eui' { - export const Query: any; -} diff --git a/x-pack/legacy/plugins/apm/public/components/app/ErrorGroupOverview/List/__test__/__snapshots__/List.test.tsx.snap b/x-pack/legacy/plugins/apm/public/components/app/ErrorGroupOverview/List/__test__/__snapshots__/List.test.tsx.snap index b3abc8c436b6a..205a303bcf47b 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ErrorGroupOverview/List/__test__/__snapshots__/List.test.tsx.snap +++ b/x-pack/legacy/plugins/apm/public/components/app/ErrorGroupOverview/List/__test__/__snapshots__/List.test.tsx.snap @@ -161,7 +161,7 @@ exports[`ErrorGroupOverview -> List should render empty state 1`] = ` - List should render empty state 1`] = ` className="euiTableCellContent__text" /> - + List should render with data 1`] = ` - List should render with data 1`] = ` className="euiTableCellContent__text" /> - + { }; }); +jest.mock('@elastic/eui/lib/services/accessibility/html_id_generator', () => { + return { + htmlIdGenerator: () => () => `generated-id`, + }; +}); + jest.mock('plugins/interpreter/registries', () => ({})); // Disabling this test due to https://github.com/elastic/eui/issues/2242 diff --git a/x-pack/legacy/plugins/canvas/public/components/custom_element_modal/__examples__/__snapshots__/custom_element_modal.examples.storyshot b/x-pack/legacy/plugins/canvas/public/components/custom_element_modal/__examples__/__snapshots__/custom_element_modal.examples.storyshot index 61ffc33cd9dde..eb82d1b63fdc2 100644 --- a/x-pack/legacy/plugins/canvas/public/components/custom_element_modal/__examples__/__snapshots__/custom_element_modal.examples.storyshot +++ b/x-pack/legacy/plugins/canvas/public/components/custom_element_modal/__examples__/__snapshots__/custom_element_modal.examples.storyshot @@ -193,6 +193,7 @@ Array [ >
+ +
+
+ @@ -1384,26 +1345,21 @@ Array [
-
-
- - - +

+ Name +

@@ -1462,27 +1418,22 @@ Array [
-
-
+
-
- - - +

+ Connection mode +

@@ -1665,27 +1616,22 @@ Array [
-
-
+
-
- - - +

+ Make remote cluster optional +

@@ -1762,7 +1708,7 @@ Array [
-
+
,
{ private renderDeleteButton = () => { const { selectedJobs } = this.state; - if (selectedJobs.length === 0) return null; + if (selectedJobs.length === 0) return undefined; const performDelete = async () => { for (const record of selectedJobs) { diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/common.ts b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/common.ts index a6d69dd655c0c..f42c9afb7ed00 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/common.ts +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/common.ts @@ -4,18 +4,14 @@ * you may not use this file except in compliance with the Elastic License. */ -export interface Clause { - type: string; - value: string; - match: string; -} +import { Query, Ast } from '@elastic/eui'; -export interface Query { - ast: { - clauses: Clause[]; - }; - text: string; - syntax: any; -} +export { Query }; +export type Clause = Parameters[0]; + +type ExtractClauseType = T extends (x: any) => x is infer Type ? Type : never; +export type TermClause = ExtractClauseType; +export type FieldClause = ExtractClauseType; +export type Value = Parameters[0]; export type ItemIdToExpandedRowMap = Record; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.tsx index 3393aada8b69d..6736a79d62a3f 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.tsx @@ -18,6 +18,7 @@ import { EuiFlexGroup, EuiFlexItem, EuiInMemoryTable, + EuiSearchBarProps, EuiPopover, EuiTitle, } from '@elastic/eui'; @@ -39,7 +40,7 @@ import { DeleteAction } from './action_delete'; import { StartAction } from './action_start'; import { StopAction } from './action_stop'; -import { ItemIdToExpandedRowMap, Query, Clause } from './common'; +import { ItemIdToExpandedRowMap, Clause, TermClause, FieldClause, Value } from './common'; import { getColumns } from './columns'; import { ExpandedRow } from './expanded_row'; @@ -56,7 +57,7 @@ function getItemIdToExpandedRowMap( }, {} as ItemIdToExpandedRowMap); } -function stringMatch(str: string | undefined, substr: string) { +function stringMatch(str: string | undefined, substr: any) { return ( typeof str === 'string' && typeof substr === 'string' && @@ -104,7 +105,10 @@ export const TransformList: FC = ({ !capabilities.canPreviewTransform || !capabilities.canStartStopTransform; - const onQueryChange = ({ query, error }: { query: Query; error: any }) => { + const onQueryChange = ({ + query, + error, + }: Parameters>[0]) => { if (error) { setSearchError(error.message); } else { @@ -114,7 +118,7 @@ export const TransformList: FC = ({ } if (clauses.length > 0) { setFilterActive(true); - filterTransforms(clauses); + filterTransforms(clauses as Array); } else { setFilterActive(false); } @@ -122,7 +126,7 @@ export const TransformList: FC = ({ } }; - const filterTransforms = (clauses: Clause[]) => { + const filterTransforms = (clauses: Array) => { setIsLoading(true); // keep count of the number of matches we make as we're looping over the clauses // we only want to return transforms which match all clauses, i.e. each search term is ANDed @@ -161,7 +165,7 @@ export const TransformList: FC = ({ // filter other clauses, i.e. the mode and status filters if (Array.isArray(c.value)) { // the status value is an array of string(s) e.g. ['failed', 'stopped'] - ts = transforms.filter(transform => c.value.includes(transform.stats.state)); + ts = transforms.filter(transform => (c.value as Value[]).includes(transform.stats.state)); } else { ts = transforms.filter(transform => transform.mode === c.value); } diff --git a/x-pack/plugins/watcher/public/application/sections/watch_list/components/watch_list.tsx b/x-pack/plugins/watcher/public/application/sections/watch_list/components/watch_list.tsx index 54f4209a137b9..5be17ab2d7ed2 100644 --- a/x-pack/plugins/watcher/public/application/sections/watch_list/components/watch_list.tsx +++ b/x-pack/plugins/watcher/public/application/sections/watch_list/components/watch_list.tsx @@ -380,27 +380,30 @@ export const WatchList = () => { box: { incremental: true, }, - toolsLeft: selection.length && ( - { - setWatchesToDelete(selection.map((selected: any) => selected.id)); - }} - color="danger" - > - {selection.length > 1 ? ( - - ) : ( - - )} - - ), + toolsLeft: + selection.length > 0 ? ( + { + setWatchesToDelete(selection.map((selected: any) => selected.id)); + }} + color="danger" + > + {selection.length > 1 ? ( + + ) : ( + + )} + + ) : ( + undefined + ), toolsRight: createWatchContextMenu, }; diff --git a/x-pack/test/functional/services/machine_learning/data_frame_analytics.ts b/x-pack/test/functional/services/machine_learning/data_frame_analytics.ts index eed7db48af460..bada1d42b564a 100644 --- a/x-pack/test/functional/services/machine_learning/data_frame_analytics.ts +++ b/x-pack/test/functional/services/machine_learning/data_frame_analytics.ts @@ -7,7 +7,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; import { MlApi } from './api'; -import { DATA_FRAME_TASK_STATE } from '../../../../plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/common'; +import { DATA_FRAME_TASK_STATE } from '../../../../plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/data_frame_task_state'; export function MachineLearningDataFrameAnalyticsProvider( { getService }: FtrProviderContext, diff --git a/x-pack/typings/@elastic/eui/index.d.ts b/x-pack/typings/@elastic/eui/index.d.ts index ea7a81fa986ce..7306f1f1af138 100644 --- a/x-pack/typings/@elastic/eui/index.d.ts +++ b/x-pack/typings/@elastic/eui/index.d.ts @@ -6,10 +6,6 @@ // TODO: Remove once typescript definitions are in EUI -declare module '@elastic/eui' { - export const Query: any; -} - declare module '@elastic/eui/lib/services' { export const RIGHT_ALIGNMENT: any; } diff --git a/yarn.lock b/yarn.lock index 30fadce11c26f..e2b8082877cd2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1951,10 +1951,10 @@ tabbable "^1.1.0" uuid "^3.1.0" -"@elastic/eui@20.0.2": - version "20.0.2" - resolved "https://registry.yarnpkg.com/@elastic/eui/-/eui-20.0.2.tgz#c64b16fef15da6aa9e627d45cdd372f1fc676359" - integrity sha512-8TtazI7RO1zJH4Qkl6TZKvAxaFG9F8BEdwyGmbGhyvXOJbkvttRzoaEg9jSQpKr+z7w2vsjGNbza/fEAE41HOA== +"@elastic/eui@21.0.1": + version "21.0.1" + resolved "https://registry.yarnpkg.com/@elastic/eui/-/eui-21.0.1.tgz#7cf6846ed88032aebd72f75255298df2fbe26554" + integrity sha512-Hf8ZGRI265qpOKwnnqhZkaMQvali+Xg6FAaNZSskkpXvdLhwGtUGC4YU7HW2vb7svq6IpNUuz+5XWrMLLzVY9w== dependencies: "@types/chroma-js" "^1.4.3" "@types/enzyme" "^3.1.13" @@ -5036,14 +5036,7 @@ dependencies: "@types/react" "*" -"@types/react-dom@*": - version "16.9.4" - resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.9.4.tgz#0b58df09a60961dcb77f62d4f1832427513420df" - integrity sha512-fya9xteU/n90tda0s+FtN5Ym4tbgxpq/hb/Af24dvs6uYnYn+fspaxw5USlw0R8apDNwxsqumdRoCoKitckQqw== - dependencies: - "@types/react" "*" - -"@types/react-dom@^16.9.5": +"@types/react-dom@*", "@types/react-dom@^16.9.5": version "16.9.5" resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.9.5.tgz#5de610b04a35d07ffd8f44edad93a71032d9aaa7" integrity sha512-BX6RQ8s9D+2/gDhxrj8OW+YD4R+8hj7FEM/OJHGNR0KipE1h1mSsf39YeyC81qafkq+N3rU3h3RFbLSwE5VqUg== @@ -5158,9 +5151,9 @@ "@types/react" "*" "@types/react@*", "@types/react@^16.8.23", "@types/react@^16.9.19": - version "16.9.19" - resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.19.tgz#c842aa83ea490007d29938146ff2e4d9e4360c40" - integrity sha512-LJV97//H+zqKWMms0kvxaKYJDG05U2TtQB3chRLF8MPNs+MQh/H1aGlyDUxjaHvu08EAGerdX2z4LTBc7ns77A== + version "16.9.23" + resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.23.tgz#1a66c6d468ba11a8943ad958a8cb3e737568271c" + integrity sha512-SsGVT4E7L2wLN3tPYLiF20hmZTPGuzaayVunfgXzUn1x4uHVsKH6QDJQ/TdpHqwsTLd4CwrmQ2vOgxN7gE24gw== dependencies: "@types/prop-types" "*" csstype "^2.2.0" From ca55db53c1dbbcd91b8cdf7cf8a970a27e727e19 Mon Sep 17 00:00:00 2001 From: Catherine Liu Date: Fri, 20 Mar 2020 13:32:01 -0700 Subject: [PATCH 09/31] =?UTF-8?q?[Canvas]=20Switch=20to=20using=20EUI=20Su?= =?UTF-8?q?perDatePicker=20in=20time=20filter=20el=E2=80=A6=20(#59249)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Replaced custom custom time filter component with EuiSuperDatePicker * Added advanced settings dateFormat and timepicker:quickRanges to time filter * Round up end date in time filter * Updated snapshots * Fixed timefilter function * Fixed import * reduce margin between datepicker and selection border (#59498) * Added time_filter renderer stories * Updated storyshots * Updated timefilter element thumbnail * Updated snapshots * Used Filter type instead of any * Renamed timefilter components folder * Removed unused time range i18n strings * Updated translations * BROKEN * Updated snapshots * Revert "BROKEN" This reverts commit e3b8bd7865c98d366f98a691a78bde2572f81720. * Fix time-filter element preview image * Upated time filter preview image * Fix time-filter renderer * fixed storybook tests * Fixed time filter renderer --- .../elements/time_filter/header.png | Bin 33515 -> 18970 bytes .../functions/common/timefilter.ts | 10 +- .../functions/common/timefilterControl.ts | 1 + .../time_filter.examples.storyshot | 134 +++++ .../time_filter.stories.storyshot | 521 ++++++++++++++++++ .../__examples__/time_filter.stories.tsx | 66 +++ .../datetime_calendar.stories.storyshot | 335 ----------- .../datetime_calendar.stories.tsx | 55 -- .../datetime_calendar/datetime_calendar.scss | 6 - .../datetime_calendar/datetime_calendar.tsx | 65 --- .../components/datetime_calendar/index.ts | 7 - .../datetime_input.stories.storyshot | 67 --- .../__examples__/datetime_input.stories.tsx | 20 - .../datetime_input/datetime_input.tsx | 60 -- .../components/datetime_input/index.ts | 40 -- .../datetime_quick_list.stories.storyshot | 249 --------- .../datetime_quick_list.stories.tsx | 21 - .../datetime_quick_list.tsx | 60 -- .../components/datetime_quick_list/index.ts | 7 - .../datetime_range_absolute.stories.storyshot | 122 ---- .../datetime_range_absolute.stories.tsx | 18 - .../datetime_range_absolute.scss | 7 - .../datetime_range_absolute.tsx | 74 --- .../datetime_range_absolute/index.ts | 7 - .../time_filter/components/index.tsx | 25 + .../pretty_duration.stories.storyshot | 13 - .../__examples__/pretty_duration.stories.tsx | 13 - .../components/pretty_duration/index.ts | 10 - .../pretty_duration/lib/format_duration.ts | 59 -- .../pretty_duration/lib/quick_ranges.ts | 53 -- .../pretty_duration/pretty_duration.tsx | 25 - .../time_filter/components/time_filter.tsx | 87 +++ .../time_filter.examples.storyshot | 283 ---------- .../__examples__/time_filter.examples.tsx | 25 - .../components/time_filter/index.ts | 7 - .../components/time_filter/time_filter.tsx | 58 -- .../time_picker.stories.storyshot | 256 --------- .../__examples__/time_picker.stories.tsx | 18 - .../components/time_picker/index.ts | 7 - .../components/time_picker/time_picker.scss | 7 - .../components/time_picker/time_picker.tsx | 99 ---- .../time_picker_popover.examples.storyshot | 28 - .../time_picker_popover.examples.tsx | 18 - .../components/time_picker_popover/index.ts | 7 - .../time_picker_popover.scss | 19 - .../time_picker_popover.tsx | 63 --- .../renderers/time_filter/index.js | 2 +- .../renderers/time_filter/time_filter.scss | 11 + x-pack/legacy/plugins/canvas/i18n/units.ts | 92 +--- .../plugins/canvas/public/style/index.scss | 5 +- .../translations/translations/ja-JP.json | 21 - .../translations/translations/zh-CN.json | 21 - 52 files changed, 856 insertions(+), 2428 deletions(-) create mode 100644 x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/__examples__/__snapshots__/time_filter.examples.storyshot create mode 100644 x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/__examples__/__snapshots__/time_filter.stories.storyshot create mode 100644 x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/__examples__/time_filter.stories.tsx delete mode 100644 x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_calendar/__examples__/__snapshots__/datetime_calendar.stories.storyshot delete mode 100644 x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_calendar/__examples__/datetime_calendar.stories.tsx delete mode 100644 x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_calendar/datetime_calendar.scss delete mode 100644 x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_calendar/datetime_calendar.tsx delete mode 100644 x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_calendar/index.ts delete mode 100644 x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_input/__examples__/__snapshots__/datetime_input.stories.storyshot delete mode 100644 x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_input/__examples__/datetime_input.stories.tsx delete mode 100644 x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_input/datetime_input.tsx delete mode 100644 x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_input/index.ts delete mode 100644 x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_quick_list/__examples__/__snapshots__/datetime_quick_list.stories.storyshot delete mode 100644 x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_quick_list/__examples__/datetime_quick_list.stories.tsx delete mode 100644 x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_quick_list/datetime_quick_list.tsx delete mode 100644 x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_quick_list/index.ts delete mode 100644 x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_range_absolute/__examples__/__snapshots__/datetime_range_absolute.stories.storyshot delete mode 100644 x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_range_absolute/__examples__/datetime_range_absolute.stories.tsx delete mode 100644 x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_range_absolute/datetime_range_absolute.scss delete mode 100644 x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_range_absolute/datetime_range_absolute.tsx delete mode 100644 x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_range_absolute/index.ts create mode 100644 x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/index.tsx delete mode 100644 x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/pretty_duration/__examples__/__snapshots__/pretty_duration.stories.storyshot delete mode 100644 x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/pretty_duration/__examples__/pretty_duration.stories.tsx delete mode 100644 x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/pretty_duration/index.ts delete mode 100644 x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/pretty_duration/lib/format_duration.ts delete mode 100644 x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/pretty_duration/lib/quick_ranges.ts delete mode 100644 x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/pretty_duration/pretty_duration.tsx create mode 100644 x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_filter.tsx delete mode 100644 x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_filter/__examples__/__snapshots__/time_filter.examples.storyshot delete mode 100644 x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_filter/__examples__/time_filter.examples.tsx delete mode 100644 x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_filter/index.ts delete mode 100644 x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_filter/time_filter.tsx delete mode 100644 x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_picker/__examples__/__snapshots__/time_picker.stories.storyshot delete mode 100644 x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_picker/__examples__/time_picker.stories.tsx delete mode 100644 x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_picker/index.ts delete mode 100644 x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_picker/time_picker.scss delete mode 100644 x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_picker/time_picker.tsx delete mode 100644 x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_picker_popover/__examples__/__snapshots__/time_picker_popover.examples.storyshot delete mode 100644 x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_picker_popover/__examples__/time_picker_popover.examples.tsx delete mode 100644 x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_picker_popover/index.ts delete mode 100644 x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_picker_popover/time_picker_popover.scss delete mode 100644 x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_picker_popover/time_picker_popover.tsx create mode 100644 x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/time_filter.scss diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/elements/time_filter/header.png b/x-pack/legacy/plugins/canvas/canvas_plugin_src/elements/time_filter/header.png index 2fbfabd61a41bb9749cd940632c4e4efa2c40648..d36b4cc97e5b13c542cfb59e53013e179532e741 100644 GIT binary patch literal 18970 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 JPDHLkV1icSlym?9 diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/functions/common/timefilter.ts b/x-pack/legacy/plugins/canvas/canvas_plugin_src/functions/common/timefilter.ts index 8afa6eb04ad69..249faf6141b46 100644 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/functions/common/timefilter.ts +++ b/x-pack/legacy/plugins/canvas/canvas_plugin_src/functions/common/timefilter.ts @@ -58,14 +58,14 @@ export function timefilter(): ExpressionFunctionDefinition< } const { from, to, column } = args; - const filter = { + const filter: Filter = { type: 'time', column, and: [], }; - function parseAndValidate(str: string): string { - const moment = dateMath.parse(str); + function parseAndValidate(str: string, { roundUp }: { roundUp: boolean }): string { + const moment = dateMath.parse(str, { roundUp }); if (!moment || !moment.isValid()) { throw errors.invalidString(str); @@ -75,11 +75,11 @@ export function timefilter(): ExpressionFunctionDefinition< } if (!!to) { - (filter as any).to = parseAndValidate(to); + filter.to = parseAndValidate(to, { roundUp: true }); } if (!!from) { - (filter as any).from = parseAndValidate(from); + filter.from = parseAndValidate(from, { roundUp: false }); } return { ...input, and: [...input.and, filter] }; diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/functions/common/timefilterControl.ts b/x-pack/legacy/plugins/canvas/canvas_plugin_src/functions/common/timefilterControl.ts index 5b6c0cb97b0fd..2f7f5c26ad0b7 100644 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/functions/common/timefilterControl.ts +++ b/x-pack/legacy/plugins/canvas/canvas_plugin_src/functions/common/timefilterControl.ts @@ -34,6 +34,7 @@ export function timefilterControl(): ExpressionFunctionDefinition< help: argHelp.column, default: '@timestamp', }, + // TODO: remove this deprecated arg compact: { types: ['boolean'], help: argHelp.compact, diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/__examples__/__snapshots__/time_filter.examples.storyshot b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/__examples__/__snapshots__/time_filter.examples.storyshot new file mode 100644 index 0000000000000..d555fbbe0ce92 --- /dev/null +++ b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/__examples__/__snapshots__/time_filter.examples.storyshot @@ -0,0 +1,134 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Storyshots renderers/TimeFilter default 1`] = ` +
+
+
+
+
+
+ +
+
+
+
+
+
+ +
+
+
+
+ → +
+
+
+
+ +
+
+
+
+
+
+
+
+`; diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/__examples__/__snapshots__/time_filter.stories.storyshot b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/__examples__/__snapshots__/time_filter.stories.storyshot new file mode 100644 index 0000000000000..2973103d421a9 --- /dev/null +++ b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/__examples__/__snapshots__/time_filter.stories.storyshot @@ -0,0 +1,521 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Storyshots renderers/TimeFilter default 1`] = ` +
+
+
+
+
+
+
+ +
+
+
+
+ +
+
+
+
+
+
+
+`; + +exports[`Storyshots renderers/TimeFilter with absolute time bounds 1`] = ` +
+
+
+
+
+
+
+ +
+
+
+
+
+
+ +
+
+
+
+ → +
+
+
+
+ +
+
+
+
+
+
+
+
+
+`; + +exports[`Storyshots renderers/TimeFilter with commonlyUsedRanges 1`] = ` +
+
+
+
+
+
+
+ +
+
+
+
+ +
+
+
+
+
+
+
+`; + +exports[`Storyshots renderers/TimeFilter with dateFormat 1`] = ` +
+
+
+
+
+
+
+ +
+
+
+
+ +
+
+
+
+
+
+
+`; + +exports[`Storyshots renderers/TimeFilter with relative time bounds 1`] = ` +
+
+
+
+
+
+
+ +
+
+
+
+
+
+ +
+
+
+
+ → +
+
+
+
+ +
+
+
+
+
+
+
+
+
+`; diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/__examples__/time_filter.stories.tsx b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/__examples__/time_filter.stories.tsx new file mode 100644 index 0000000000000..c854ea8267bf5 --- /dev/null +++ b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/__examples__/time_filter.stories.tsx @@ -0,0 +1,66 @@ +/* + * 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. + */ + +import { action } from '@storybook/addon-actions'; +import { storiesOf } from '@storybook/react'; +import React from 'react'; +import { TimeFilter } from '../time_filter'; + +const timeRanges = [ + { start: 'now/d', end: 'now/d', label: 'Today' }, + { start: 'now/w', end: 'now/w', label: 'This week' }, + { start: 'now-15m', end: 'now', label: 'Last 15 minutes' }, + { start: 'now-30m', end: 'now', label: 'Last 30 minutes' }, + { start: 'now-1h', end: 'now', label: 'Last 1 hour' }, + { start: 'now-24h', end: 'now', label: 'Last 24 hours' }, + { start: 'now-7d', end: 'now', label: 'Last 7 days' }, + { start: 'now-30d', end: 'now', label: 'Last 30 days' }, + { start: 'now-90d', end: 'now', label: 'Last 90 days' }, + { start: 'now-1y', end: 'now', label: 'Last 1 year' }, +]; + +storiesOf('renderers/TimeFilter', module) + .addDecorator(story => ( +
+ {story()} +
+ )) + .add('default', () => ( + + )) + .add('with relative time bounds', () => ( + + )) + .add('with absolute time bounds', () => ( + + )) + .add('with dateFormat', () => ( + + )) + .add('with commonlyUsedRanges', () => ( + + )); diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_calendar/__examples__/__snapshots__/datetime_calendar.stories.storyshot b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_calendar/__examples__/__snapshots__/datetime_calendar.stories.storyshot deleted file mode 100644 index f6b14e98b5fad..0000000000000 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_calendar/__examples__/__snapshots__/datetime_calendar.stories.storyshot +++ /dev/null @@ -1,335 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Storyshots renderers/TimeFilter/components/DatetimeCalendar default 1`] = ` -
-
-
- -
-
- - -
-
- -
-
-
-
-
-`; - -exports[`Storyshots renderers/TimeFilter/components/DatetimeCalendar invalid date 1`] = ` -
-
-
- -
-
- - -
-
- -
-
-
-
-
-`; - -exports[`Storyshots renderers/TimeFilter/components/DatetimeCalendar with max date 1`] = ` -
-
-
- -
-
- - -
-
- -
-
-
-
-
-`; - -exports[`Storyshots renderers/TimeFilter/components/DatetimeCalendar with min date 1`] = ` -
-
-
- -
-
- - -
-
- -
-
-
-
-
-`; - -exports[`Storyshots renderers/TimeFilter/components/DatetimeCalendar with start and end date 1`] = ` -
-
-
- -
-
- - -
-
- -
-
-
-
-
-`; - -exports[`Storyshots renderers/TimeFilter/components/DatetimeCalendar with value 1`] = ` -
-
-
- -
-
- - -
-
- -
-
-
-
-
-`; diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_calendar/__examples__/datetime_calendar.stories.tsx b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_calendar/__examples__/datetime_calendar.stories.tsx deleted file mode 100644 index 19004e6fdcc5a..0000000000000 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_calendar/__examples__/datetime_calendar.stories.tsx +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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. - */ - -import { action } from '@storybook/addon-actions'; -import { storiesOf } from '@storybook/react'; -import moment from 'moment'; -import React from 'react'; -import { DatetimeCalendar } from '..'; - -const startDate = moment.utc('2019-06-27'); -const endDate = moment.utc('2019-07-04'); - -storiesOf('renderers/TimeFilter/components/DatetimeCalendar', module) - .add('default', () => ( - - )) - .add('with value', () => ( - - )) - .add('with start and end date', () => ( - - )) - .add('with min date', () => ( - - )) - .add('with max date', () => ( - - )) - .add('invalid date', () => ( - - )); diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_calendar/datetime_calendar.scss b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_calendar/datetime_calendar.scss deleted file mode 100644 index 6133b9184d1c5..0000000000000 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_calendar/datetime_calendar.scss +++ /dev/null @@ -1,6 +0,0 @@ -.canvasDateTimeCal { - display: inline-grid; - height: 100%; - border: $euiBorderThin; - grid-template-rows: $euiSizeXL 1fr; -} diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_calendar/datetime_calendar.tsx b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_calendar/datetime_calendar.tsx deleted file mode 100644 index 8c189682c959c..0000000000000 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_calendar/datetime_calendar.tsx +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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. - */ - -import React, { FunctionComponent } from 'react'; -import PropTypes from 'prop-types'; -import { Moment } from 'moment'; -import { momentObj } from 'react-moment-proptypes'; -import { EuiDatePicker } from '@elastic/eui'; -import { DatetimeInput } from '../datetime_input'; - -export interface Props { - /** Selected date (Moment date object) */ - value?: Moment; - /** Function invoked when a date is selected from the datepicker */ - onSelect: (date: Moment | null) => void; - /** Function invoked when the date text input changes */ - onValueChange: (moment: Moment) => void; // Called with a moment - /** Start date of selected date range (Moment date object) */ - startDate?: Moment; - /** End date of selected date range (Moment date object) */ - endDate?: Moment; - /** Earliest selectable date (Moment date object) */ - minDate?: Moment; - /** Latest selectable date (Moment date object) */ - maxDate?: Moment; -} - -export const DatetimeCalendar: FunctionComponent = ({ - value, - onValueChange, - onSelect, - startDate, - endDate, - minDate, - maxDate, -}) => ( -
- - -
-); - -DatetimeCalendar.propTypes = { - value: PropTypes.oneOfType([momentObj, PropTypes.object]), // Handle both valid and invalid moment objects - onSelect: PropTypes.func.isRequired, - onValueChange: PropTypes.func.isRequired, // Called with a moment - startDate: momentObj, - endDate: momentObj, - minDate: momentObj, - maxDate: momentObj, -}; diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_calendar/index.ts b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_calendar/index.ts deleted file mode 100644 index 7f64e2b89df03..0000000000000 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_calendar/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -/* - * 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. - */ - -export { DatetimeCalendar } from './datetime_calendar'; diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_input/__examples__/__snapshots__/datetime_input.stories.storyshot b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_input/__examples__/__snapshots__/datetime_input.stories.storyshot deleted file mode 100644 index 1bda4b5246991..0000000000000 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_input/__examples__/__snapshots__/datetime_input.stories.storyshot +++ /dev/null @@ -1,67 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Storyshots renderers/TimeFilter/components/DatetimeInput default 1`] = ` -
-
- -
-
-`; - -exports[`Storyshots renderers/TimeFilter/components/DatetimeInput invalid date 1`] = ` -
-
- -
-
-`; - -exports[`Storyshots renderers/TimeFilter/components/DatetimeInput with date 1`] = ` -
-
- -
-
-`; diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_input/__examples__/datetime_input.stories.tsx b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_input/__examples__/datetime_input.stories.tsx deleted file mode 100644 index 060f04da88f99..0000000000000 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_input/__examples__/datetime_input.stories.tsx +++ /dev/null @@ -1,20 +0,0 @@ -/* - * 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. - */ - -import { action } from '@storybook/addon-actions'; -import { storiesOf } from '@storybook/react'; -import moment from 'moment'; -import React from 'react'; -import { DatetimeInput } from '..'; - -storiesOf('renderers/TimeFilter/components/DatetimeInput', module) - .add('default', () => ) - .add('with date', () => ( - - )) - .add('invalid date', () => ( - - )); diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_input/datetime_input.tsx b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_input/datetime_input.tsx deleted file mode 100644 index 32bdcde5ddda0..0000000000000 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_input/datetime_input.tsx +++ /dev/null @@ -1,60 +0,0 @@ -/* - * 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. - */ - -import React, { FunctionComponent, ChangeEvent } from 'react'; -import PropTypes from 'prop-types'; -import { EuiFieldText } from '@elastic/eui'; -import moment, { Moment } from 'moment'; - -export interface Props { - /** Selected string value of input */ - strValue: string; - /** Function invoked with string when input is changed */ - setStrValue: (value: string) => void; - /** Function invoked with moment when input is changed with valid datetime */ - setMoment: (value: Moment) => void; - /** Boolean denotes whether current input value is valid date */ - valid: boolean; - /** Function invoked with value validity when input is changed */ - setValid: (valid: boolean) => void; -} - -export const DatetimeInput: FunctionComponent = ({ - strValue, - setStrValue, - setMoment, - valid, - setValid, -}) => { - function check(e: ChangeEvent) { - const parsed = moment(e.target.value, 'YYYY-MM-DD HH:mm:ss', true); - if (parsed.isValid()) { - setMoment(parsed); - setValid(true); - } else { - setValid(false); - } - setStrValue(e.target.value); - } - - return ( - - ); -}; - -DatetimeInput.propTypes = { - setMoment: PropTypes.func, - strValue: PropTypes.string, - setStrValue: PropTypes.func, - valid: PropTypes.bool, - setValid: PropTypes.func, -}; diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_input/index.ts b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_input/index.ts deleted file mode 100644 index ff0e52580b421..0000000000000 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_input/index.ts +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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. - */ - -import { Moment } from 'moment'; -import { compose, withState, lifecycle } from 'recompose'; -import { DatetimeInput as Component, Props as ComponentProps } from './datetime_input'; - -export interface Props { - /** Input value (Moment date object) */ - moment?: Moment; - /** Function to invoke when the input changes */ - setMoment: (m: Moment) => void; -} - -export const DatetimeInput = compose( - withState('valid', 'setValid', () => true), - withState('strValue', 'setStrValue', ({ moment }) => - moment ? moment.format('YYYY-MM-DD HH:mm:ss') : '' - ), - lifecycle({ - componentDidUpdate(prevProps) { - const prevMoment = prevProps.moment; - - // If we don't have a current moment, do nothing - if (!this.props.moment) return; - - // If we previously had a moment and it's the same as the current moment, do nothing - if (prevMoment && prevMoment.isSame(this.props.moment)) { - return; - } - - // Set the string value of the current moment and mark as valid - this.props.setStrValue(this.props.moment.format('YYYY-MM-DD HH:mm:ss')); - this.props.setValid(true); - }, - }) -)(Component); diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_quick_list/__examples__/__snapshots__/datetime_quick_list.stories.storyshot b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_quick_list/__examples__/__snapshots__/datetime_quick_list.stories.storyshot deleted file mode 100644 index b3ec64fa55a07..0000000000000 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_quick_list/__examples__/__snapshots__/datetime_quick_list.stories.storyshot +++ /dev/null @@ -1,249 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Storyshots renderers/TimeFilter/components/DatetimeQuickList with children 1`] = ` -
- - - - - - - - -
-`; - -exports[`Storyshots renderers/TimeFilter/components/DatetimeQuickList with start and end dates 1`] = ` -
- - - - - - - -
-`; diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_quick_list/__examples__/datetime_quick_list.stories.tsx b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_quick_list/__examples__/datetime_quick_list.stories.tsx deleted file mode 100644 index 68ef3cf1300bc..0000000000000 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_quick_list/__examples__/datetime_quick_list.stories.tsx +++ /dev/null @@ -1,21 +0,0 @@ -/* - * 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. - */ - -import { EuiButtonEmpty } from '@elastic/eui'; -import { action } from '@storybook/addon-actions'; -import { storiesOf } from '@storybook/react'; -import React from 'react'; -import { DatetimeQuickList } from '..'; - -storiesOf('renderers/TimeFilter/components/DatetimeQuickList', module) - .add('with start and end dates', () => ( - - )) - .add('with children', () => ( - - Apply - - )); diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_quick_list/datetime_quick_list.tsx b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_quick_list/datetime_quick_list.tsx deleted file mode 100644 index 9d5a3893dbcb8..0000000000000 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_quick_list/datetime_quick_list.tsx +++ /dev/null @@ -1,60 +0,0 @@ -/* - * 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. - */ - -import React, { ReactNode, FunctionComponent } from 'react'; -import PropTypes from 'prop-types'; -import { EuiButton, EuiButtonEmpty } from '@elastic/eui'; -import 'react-datetime/css/react-datetime.css'; -import { UnitStrings } from '../../../../../i18n/units'; - -const { quickRanges: strings } = UnitStrings; - -interface Props { - /** Initial start date string */ - from: string; - /** Initial end date string */ - to: string; - - /** Function invoked when a date range is clicked */ - onSelect: (from: string, to: string) => void; - - /** Nodes to display under the date range buttons */ - children?: ReactNode; -} - -const quickRanges = [ - { from: 'now/d', to: 'now', display: strings.getTodayLabel() }, - { from: 'now-24h', to: 'now', display: strings.getLast24HoursLabel() }, - { from: 'now-7d', to: 'now', display: strings.getLast7DaysLabel() }, - { from: 'now-14d', to: 'now', display: strings.getLast2WeeksLabel() }, - { from: 'now-30d', to: 'now', display: strings.getLast30DaysLabel() }, - { from: 'now-90d', to: 'now', display: strings.getLast90DaysLabel() }, - { from: 'now-1y', to: 'now', display: strings.getLast1YearLabel() }, -]; - -export const DatetimeQuickList: FunctionComponent = ({ from, to, onSelect, children }) => ( -
- {quickRanges.map((range, i) => - from === range.from && to === range.to ? ( - onSelect(range.from, range.to)}> - {range.display} - - ) : ( - onSelect(range.from, range.to)}> - {range.display} - - ) - )} - {children} -
-); - -DatetimeQuickList.propTypes = { - from: PropTypes.string.isRequired, - to: PropTypes.string.isRequired, - onSelect: PropTypes.func.isRequired, - children: PropTypes.node, -}; diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_quick_list/index.ts b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_quick_list/index.ts deleted file mode 100644 index 5780f0f89c00a..0000000000000 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_quick_list/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -/* - * 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. - */ - -export { DatetimeQuickList } from './datetime_quick_list'; diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_range_absolute/__examples__/__snapshots__/datetime_range_absolute.stories.storyshot b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_range_absolute/__examples__/__snapshots__/datetime_range_absolute.stories.storyshot deleted file mode 100644 index 7bf08c3d6f24e..0000000000000 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_range_absolute/__examples__/__snapshots__/datetime_range_absolute.stories.storyshot +++ /dev/null @@ -1,122 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Storyshots renderers/TimeFilter/components/DatetimeRangeAbsolute default 1`] = ` -
-
-
-
-
- -
-
- - -
-
- -
-
-
-
-
-
-
-
-
-
- -
-
- - -
-
- -
-
-
-
-
-
-
-`; diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_range_absolute/__examples__/datetime_range_absolute.stories.tsx b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_range_absolute/__examples__/datetime_range_absolute.stories.tsx deleted file mode 100644 index 01d2fe49e29e8..0000000000000 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_range_absolute/__examples__/datetime_range_absolute.stories.tsx +++ /dev/null @@ -1,18 +0,0 @@ -/* - * 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. - */ - -import { action } from '@storybook/addon-actions'; -import { storiesOf } from '@storybook/react'; -import moment from 'moment'; -import React from 'react'; -import { DatetimeRangeAbsolute } from '..'; - -const startDate = moment.utc('2019-06-21'); -const endDate = moment.utc('2019-07-05'); - -storiesOf('renderers/TimeFilter/components/DatetimeRangeAbsolute', module).add('default', () => ( - -)); diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_range_absolute/datetime_range_absolute.scss b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_range_absolute/datetime_range_absolute.scss deleted file mode 100644 index 706bd90ad1edf..0000000000000 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_range_absolute/datetime_range_absolute.scss +++ /dev/null @@ -1,7 +0,0 @@ -.canvasDateTimeRangeAbsolute { - display: flex; - - > div:not(:last-child) { - margin-right: $euiSizeS; - } -} diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_range_absolute/datetime_range_absolute.tsx b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_range_absolute/datetime_range_absolute.tsx deleted file mode 100644 index ddd755b4a12f4..0000000000000 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_range_absolute/datetime_range_absolute.tsx +++ /dev/null @@ -1,74 +0,0 @@ -/* - * 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. - */ - -import React, { FunctionComponent } from 'react'; -import PropTypes from 'prop-types'; -import { Moment } from 'moment'; -import { momentObj } from 'react-moment-proptypes'; -import { DatetimeCalendar } from '../datetime_calendar'; - -interface Props { - /** Optional initial start date moment */ - from?: Moment; - /** Optional initial end date moment */ - to?: Moment; - - /** Function invoked when a date is selected from the datetime calendar */ - onSelect: (from?: Moment, to?: Moment) => void; -} - -export const DatetimeRangeAbsolute: FunctionComponent = ({ from, to, onSelect }) => ( -
-
- onSelect(val, to)} - onSelect={val => { - if (!val || !from) { - return; - } - - // sets the time to start of day if only the date was selected - if (from.format('hh:mm:ss a') === val.format('hh:mm:ss a')) { - onSelect(val.startOf('day'), to); - } else { - onSelect(val, to); - } - }} - /> -
-
- onSelect(from, val)} - onSelect={val => { - if (!val || !to) { - return; - } - - // set the time to end of day if only the date was selected - if (to.format('hh:mm:ss a') === val.format('hh:mm:ss a')) { - onSelect(from, val.endOf('day')); - } else { - onSelect(from, val); - } - }} - /> -
-
-); - -DatetimeRangeAbsolute.propTypes = { - from: momentObj, - to: momentObj, - onSelect: PropTypes.func.isRequired, -}; diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_range_absolute/index.ts b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_range_absolute/index.ts deleted file mode 100644 index c6e5a77ca8af8..0000000000000 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/datetime_range_absolute/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -/* - * 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. - */ - -export { DatetimeRangeAbsolute } from './datetime_range_absolute'; diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/index.tsx b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/index.tsx new file mode 100644 index 0000000000000..e2e9358bf99c6 --- /dev/null +++ b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/index.tsx @@ -0,0 +1,25 @@ +/* + * 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. + */ + +import React from 'react'; +import { AdvancedSettings } from '../../../../public/lib/kibana_advanced_settings'; +import { TimeFilter as Component, Props } from './time_filter'; + +export const TimeFilter = (props: Props) => { + const customQuickRanges = (AdvancedSettings.get('timepicker:quickRanges') || []).map( + ({ from, to, display }: { from: string; to: string; display: string }) => ({ + start: from, + end: to, + label: display, + }) + ); + + const customDateFormat = AdvancedSettings.get('dateFormat'); + + return ( + + ); +}; diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/pretty_duration/__examples__/__snapshots__/pretty_duration.stories.storyshot b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/pretty_duration/__examples__/__snapshots__/pretty_duration.stories.storyshot deleted file mode 100644 index 3730cfb5f4e5c..0000000000000 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/pretty_duration/__examples__/__snapshots__/pretty_duration.stories.storyshot +++ /dev/null @@ -1,13 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Storyshots renderers/TimeFilter/components/PrettyDuration with absolute dates 1`] = ` - - ~ 5 months ago to ~ 4 months ago - -`; - -exports[`Storyshots renderers/TimeFilter/components/PrettyDuration with relative dates 1`] = ` - - Last 7 days - -`; diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/pretty_duration/__examples__/pretty_duration.stories.tsx b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/pretty_duration/__examples__/pretty_duration.stories.tsx deleted file mode 100644 index 951776f8a9558..0000000000000 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/pretty_duration/__examples__/pretty_duration.stories.tsx +++ /dev/null @@ -1,13 +0,0 @@ -/* - * 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. - */ - -import { storiesOf } from '@storybook/react'; -import React from 'react'; -import { PrettyDuration } from '..'; - -storiesOf('renderers/TimeFilter/components/PrettyDuration', module) - .add('with relative dates', () => ) - .add('with absolute dates', () => ); diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/pretty_duration/index.ts b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/pretty_duration/index.ts deleted file mode 100644 index a35a4aba66487..0000000000000 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/pretty_duration/index.ts +++ /dev/null @@ -1,10 +0,0 @@ -/* - * 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. - */ - -import { pure } from 'recompose'; -import { PrettyDuration as Component } from './pretty_duration'; - -export const PrettyDuration = pure(Component); diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/pretty_duration/lib/format_duration.ts b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/pretty_duration/lib/format_duration.ts deleted file mode 100644 index b713eb4d7cd5e..0000000000000 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/pretty_duration/lib/format_duration.ts +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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. - */ - -import dateMath from '@elastic/datemath'; -import moment, { Moment } from 'moment'; -import { quickRanges, QuickRange } from './quick_ranges'; -import { timeUnits, TimeUnit } from '../../../../../../common/lib/time_units'; - -const lookupByRange: { [key: string]: QuickRange } = {}; -quickRanges.forEach(frame => { - lookupByRange[`${frame.from} to ${frame.to}`] = frame; -}); - -function formatTime(time: string | Moment, roundUp = false) { - if (moment.isMoment(time)) { - return time.format('lll'); - } else { - if (time === 'now') { - return 'now'; - } else { - const tryParse = dateMath.parse(time, { roundUp }); - return moment.isMoment(tryParse) ? '~ ' + tryParse.fromNow() : time; - } - } -} - -function cantLookup(from: string, to: string) { - return `${formatTime(from)} to ${formatTime(to)}`; -} - -export function formatDuration(from: string, to: string) { - // If both parts are date math, try to look up a reasonable string - if (from && to && !moment.isMoment(from) && !moment.isMoment(to)) { - const tryLookup = lookupByRange[`${from.toString()} to ${to.toString()}`]; - if (tryLookup) { - return tryLookup.display; - } else { - const fromParts = from.toString().split('-'); - if (to.toString() === 'now' && fromParts[0] === 'now' && fromParts[1]) { - const rounded = fromParts[1].split('/'); - let text = `Last ${rounded[0]}`; - if (rounded[1]) { - const unit = rounded[1] as TimeUnit; - text = `${text} rounded to the ${timeUnits[unit]}`; - } - - return text; - } else { - return cantLookup(from, to); - } - } - // If at least one part is a moment, try to make pretty strings by parsing date math - } else { - return cantLookup(from, to); - } -} diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/pretty_duration/lib/quick_ranges.ts b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/pretty_duration/lib/quick_ranges.ts deleted file mode 100644 index 1c436d3630b53..0000000000000 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/pretty_duration/lib/quick_ranges.ts +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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. - */ - -import { UnitStrings } from '../../../../../../i18n/units'; - -export interface QuickRange { - /** Start date string of range */ - from: string; - /** Start date string of range */ - to: string; - /** Display name describing date range */ - display: string; -} - -const { quickRanges: strings } = UnitStrings; - -export const quickRanges: QuickRange[] = [ - { from: 'now/d', to: 'now/d', display: strings.getTodayLabel() }, - { from: 'now/w', to: 'now/w', display: strings.getThisWeekLabel() }, - { from: 'now/M', to: 'now/M', display: strings.getThisMonthLabel() }, - { from: 'now/y', to: 'now/y', display: strings.getThisYearLabel() }, - { from: 'now/d', to: 'now', display: strings.getTheDaySoFarLabel() }, - { from: 'now/w', to: 'now', display: strings.getWeekToDateLabel() }, - { from: 'now/M', to: 'now', display: strings.getMonthToDateLabel() }, - { from: 'now/y', to: 'now', display: strings.getYearToDateLabel() }, - - { from: 'now-1d/d', to: 'now-1d/d', display: strings.getYesterdayLabel() }, - { from: 'now-2d/d', to: 'now-2d/d', display: strings.getDayBeforeYesterdayLabel() }, - { from: 'now-7d/d', to: 'now-7d/d', display: strings.getThisDayLastWeek() }, - { from: 'now-1w/w', to: 'now-1w/w', display: strings.getPreviousWeekLabel() }, - { from: 'now-1M/M', to: 'now-1M/M', display: strings.getPreviousMonthLabel() }, - { from: 'now-1y/y', to: 'now-1y/y', display: strings.getPreviousYearLabel() }, - - { from: 'now-15m', to: 'now', display: strings.getLast15MinutesLabel() }, - { from: 'now-30m', to: 'now', display: strings.getLast30MinutesLabel() }, - { from: 'now-1h', to: 'now', display: strings.getLast1HourLabel() }, - { from: 'now-4h', to: 'now', display: strings.getLast4HoursLabel() }, - { from: 'now-12h', to: 'now', display: strings.getLast12HoursLabel() }, - { from: 'now-24h', to: 'now', display: strings.getLast24HoursLabel() }, - { from: 'now-7d', to: 'now', display: strings.getLast7DaysLabel() }, - { from: 'now-14d', to: 'now', display: strings.getLast2WeeksLabel() }, - - { from: 'now-30d', to: 'now', display: strings.getLast30DaysLabel() }, - { from: 'now-60d', to: 'now', display: strings.getLast60DaysLabel() }, - { from: 'now-90d', to: 'now', display: strings.getLast90DaysLabel() }, - { from: 'now-6M', to: 'now', display: strings.getLast6MonthsLabel() }, - { from: 'now-1y', to: 'now', display: strings.getLast1YearLabel() }, - { from: 'now-2y', to: 'now', display: strings.getLast2YearsLabel() }, - { from: 'now-5y', to: 'now', display: strings.getLast5YearsLabel() }, -]; diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/pretty_duration/pretty_duration.tsx b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/pretty_duration/pretty_duration.tsx deleted file mode 100644 index f1b65c586ff0c..0000000000000 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/pretty_duration/pretty_duration.tsx +++ /dev/null @@ -1,25 +0,0 @@ -/* - * 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. - */ - -import React, { FunctionComponent } from 'react'; -import PropTypes from 'prop-types'; -import { formatDuration } from './lib/format_duration'; - -interface Props { - /** Initial start date string */ - from: string; - /** Initial end date string */ - to: string; -} - -export const PrettyDuration: FunctionComponent = ({ from, to }) => ( - {formatDuration(from, to)} -); - -PrettyDuration.propTypes = { - from: PropTypes.string.isRequired, - to: PropTypes.string.isRequired, -}; diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_filter.tsx b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_filter.tsx new file mode 100644 index 0000000000000..8d28287b32066 --- /dev/null +++ b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_filter.tsx @@ -0,0 +1,87 @@ +/* + * 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. + */ +import { EuiSuperDatePicker, OnTimeChangeProps, EuiSuperDatePickerCommonRange } from '@elastic/eui'; +import React from 'react'; +import PropTypes from 'prop-types'; +import { get } from 'lodash'; +import { fromExpression } from '@kbn/interpreter/common'; +import { UnitStrings } from '../../../../i18n/units'; + +const { quickRanges: strings } = UnitStrings; + +const defaultQuickRanges: EuiSuperDatePickerCommonRange[] = [ + { start: 'now-1d/d', end: 'now-1d/d', label: strings.getYesterdayLabel() }, + { start: 'now/d', end: 'now', label: strings.getTodayLabel() }, + { start: 'now-24h', end: 'now', label: strings.getLast24HoursLabel() }, + { start: 'now-7d', end: 'now', label: strings.getLast7DaysLabel() }, + { start: 'now-14d', end: 'now', label: strings.getLast2WeeksLabel() }, + { start: 'now-30d', end: 'now', label: strings.getLast30DaysLabel() }, + { start: 'now-90d', end: 'now', label: strings.getLast90DaysLabel() }, + { start: 'now-1y', end: 'now', label: strings.getLast1YearLabel() }, +]; + +export interface FilterMeta { + /** Name of datetime column to be filtered */ + column: string; + /** Start date string of filtered date range */ + start: string; + /** End date string of filtered date range */ + end: string; +} + +function getFilterMeta(filter: string): FilterMeta { + const ast = fromExpression(filter); + const column = get(ast, 'chain[0].arguments.column[0]'); + const start = get(ast, 'chain[0].arguments.from[0]'); + const end = get(ast, 'chain[0].arguments.to[0]'); + return { column, start, end }; +} + +export interface Props { + /** Initial value of the filter */ + filter: string; + /** Function invoked when the filter changes */ + commit: (filter: string) => void; + /** Elastic datemath format string */ + dateFormat?: string; + /** Array of time ranges */ + commonlyUsedRanges?: EuiSuperDatePickerCommonRange[]; +} + +export const TimeFilter = ({ filter, commit, dateFormat, commonlyUsedRanges = [] }: Props) => { + const setFilter = (column: string) => ({ start, end }: OnTimeChangeProps) => { + commit(`timefilter from="${start}" to=${end} column=${column}`); + }; + + const { column, start, end } = getFilterMeta(filter); + + return ( +
+ +
+ ); +}; + +TimeFilter.propTypes = { + filter: PropTypes.string.isRequired, + commit: PropTypes.func.isRequired, // Canvas filter + dateFormat: PropTypes.string, + commonlyUsedRanges: PropTypes.arrayOf( + PropTypes.shape({ + start: PropTypes.string.isRequired, + end: PropTypes.string.isRequired, + label: PropTypes.string.isRequired, + }) + ), +}; diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_filter/__examples__/__snapshots__/time_filter.examples.storyshot b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_filter/__examples__/__snapshots__/time_filter.examples.storyshot deleted file mode 100644 index 9c070dded5810..0000000000000 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_filter/__examples__/__snapshots__/time_filter.examples.storyshot +++ /dev/null @@ -1,283 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Storyshots renderers/TimeFilter compact mode 1`] = ` -
-
- -
-
-`; - -exports[`Storyshots renderers/TimeFilter default 1`] = ` -
-
-
-
-
-
- -
-
- - -
-
- -
-
-
-
-
-
-
-
-
-
- -
-
- - -
-
- -
-
-
-
-
-
-
-
- - - - - - - - -
-
-`; diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_filter/__examples__/time_filter.examples.tsx b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_filter/__examples__/time_filter.examples.tsx deleted file mode 100644 index b6b94bf3e4a05..0000000000000 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_filter/__examples__/time_filter.examples.tsx +++ /dev/null @@ -1,25 +0,0 @@ -/* - * 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. - */ - -import { action } from '@storybook/addon-actions'; -import { storiesOf } from '@storybook/react'; -import React from 'react'; -import { TimeFilter } from '..'; - -storiesOf('renderers/TimeFilter', module) - .add('default', () => ( - - )) - .add('compact mode', () => ( - - )); diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_filter/index.ts b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_filter/index.ts deleted file mode 100644 index cdea7d6591592..0000000000000 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_filter/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -/* - * 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. - */ - -export { TimeFilter } from './time_filter'; diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_filter/time_filter.tsx b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_filter/time_filter.tsx deleted file mode 100644 index cbe9793c806e1..0000000000000 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_filter/time_filter.tsx +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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. - */ - -import React from 'react'; -import PropTypes from 'prop-types'; -import { get } from 'lodash'; -import { fromExpression } from '@kbn/interpreter/common'; -import { TimePicker } from '../time_picker'; -import { TimePickerPopover } from '../time_picker_popover'; - -export interface FilterMeta { - /** Name of datetime column to be filtered */ - column: string; - /** Start date string of filtered date range */ - from: string; - /** End date string of filtered date range */ - to: string; -} - -function getFilterMeta(filter: string): FilterMeta { - const ast = fromExpression(filter); - const column = get(ast, 'chain[0].arguments.column[0]'); - const from = get(ast, 'chain[0].arguments.from[0]'); - const to = get(ast, 'chain[0].arguments.to[0]'); - return { column, from, to }; -} - -export interface Props { - /** Initial value of the filter */ - filter: string; - /** Function invoked when the filter changes */ - commit: (filter: string) => void; - /** Determines if compact or full-sized time picker is displayed */ - compact?: boolean; -} - -export const TimeFilter = ({ filter, commit, compact }: Props) => { - const setFilter = (column: string) => (from: string, to: string) => { - commit(`timefilter from="${from}" to=${to} column=${column}`); - }; - - const { column, from, to } = getFilterMeta(filter); - - if (compact) { - return ; - } else { - return ; - } -}; - -TimeFilter.propTypes = { - filter: PropTypes.string.isRequired, - commit: PropTypes.func.isRequired, // Canvas filter - compact: PropTypes.bool, -}; diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_picker/__examples__/__snapshots__/time_picker.stories.storyshot b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_picker/__examples__/__snapshots__/time_picker.stories.storyshot deleted file mode 100644 index 49ea8ccc5889e..0000000000000 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_picker/__examples__/__snapshots__/time_picker.stories.storyshot +++ /dev/null @@ -1,256 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Storyshots renderers/TimeFilter/components/TimePicker default 1`] = ` -
-
-
-
-
-
- -
-
- - -
-
- -
-
-
-
-
-
-
-
-
-
- -
-
- - -
-
- -
-
-
-
-
-
-
-
- - - - - - - - -
-
-`; diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_picker/__examples__/time_picker.stories.tsx b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_picker/__examples__/time_picker.stories.tsx deleted file mode 100644 index e34d2d5f58561..0000000000000 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_picker/__examples__/time_picker.stories.tsx +++ /dev/null @@ -1,18 +0,0 @@ -/* - * 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. - */ - -import { action } from '@storybook/addon-actions'; -import { storiesOf } from '@storybook/react'; -import moment from 'moment'; -import React from 'react'; -import { TimePicker } from '..'; - -const startDate = moment.utc('2018-04-04').toISOString(); -const endDate = moment.utc('2019-04-04').toISOString(); - -storiesOf('renderers/TimeFilter/components/TimePicker', module).add('default', () => ( - -)); diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_picker/index.ts b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_picker/index.ts deleted file mode 100644 index a220bd5eebc21..0000000000000 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_picker/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -/* - * 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. - */ - -export { TimePicker } from './time_picker'; diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_picker/time_picker.scss b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_picker/time_picker.scss deleted file mode 100644 index 889db1fc8165d..0000000000000 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_picker/time_picker.scss +++ /dev/null @@ -1,7 +0,0 @@ -.canvasTimePicker { - display: flex; - - > div:not(:last-child) { - margin-right: $euiSizeS; - } -} diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_picker/time_picker.tsx b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_picker/time_picker.tsx deleted file mode 100644 index 599b15524ddda..0000000000000 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_picker/time_picker.tsx +++ /dev/null @@ -1,99 +0,0 @@ -/* - * 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. - */ - -import React, { Component } from 'react'; -import PropTypes from 'prop-types'; -import dateMath from '@elastic/datemath'; -import { EuiButton } from '@elastic/eui'; -import moment from 'moment'; -import { DatetimeQuickList } from '../datetime_quick_list'; -import { DatetimeRangeAbsolute } from '../datetime_range_absolute'; -import { ComponentStrings } from '../../../../../i18n/components'; - -const { TimePicker: strings } = ComponentStrings; - -export interface Props { - /** Start date string */ - from: string; - /** End date string */ - to: string; - /** Function invoked when date range is changed */ - onSelect: (from: string, to: string) => void; -} - -export interface State { - range: { - /** Start date string of selected date range */ - from: string; - /** End date string of selected date range */ - to: string; - }; - /** Boolean denoting whether selected date range has been applied */ - isDirty: boolean; -} - -export class TimePicker extends Component { - static propTypes = { - from: PropTypes.string.isRequired, - to: PropTypes.string.isRequired, - onSelect: PropTypes.func.isRequired, - }; - - state = { - range: { from: this.props.from, to: this.props.to }, - isDirty: false, - }; - - componentDidUpdate(prevProps: Props) { - const { to, from } = this.props; - - if (prevProps.from !== from || prevProps.to !== to) { - this.setState({ - range: { from, to }, - isDirty: false, - }); - } - } - - _absoluteSelect = (from?: moment.Moment, to?: moment.Moment) => { - if (from && to) { - this.setState({ - range: { from: moment(from).toISOString(), to: moment(to).toISOString() }, - isDirty: true, - }); - } - }; - - render() { - const { onSelect } = this.props; - const { range, isDirty } = this.state; - const { from, to } = range; - - return ( -
- - - { - this.setState({ isDirty: false }); - onSelect(from, to); - }} - > - {strings.getApplyButtonLabel()} - - -
- ); - } -} diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_picker_popover/__examples__/__snapshots__/time_picker_popover.examples.storyshot b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_picker_popover/__examples__/__snapshots__/time_picker_popover.examples.storyshot deleted file mode 100644 index 7e2474dbfb79c..0000000000000 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_picker_popover/__examples__/__snapshots__/time_picker_popover.examples.storyshot +++ /dev/null @@ -1,28 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Storyshots renderers/TimeFilter/components/TimePickerPopover default 1`] = ` -
-
- -
-
-`; diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_picker_popover/__examples__/time_picker_popover.examples.tsx b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_picker_popover/__examples__/time_picker_popover.examples.tsx deleted file mode 100644 index 7555de1336b3e..0000000000000 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_picker_popover/__examples__/time_picker_popover.examples.tsx +++ /dev/null @@ -1,18 +0,0 @@ -/* - * 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. - */ - -import { action } from '@storybook/addon-actions'; -import { storiesOf } from '@storybook/react'; -import moment from 'moment'; -import React from 'react'; -import { TimePickerPopover } from '..'; - -const startDate = moment.utc('2019-05-04').toISOString(); -const endDate = moment.utc('2019-06-04').toISOString(); - -storiesOf('renderers/TimeFilter/components/TimePickerPopover', module).add('default', () => ( - -)); diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_picker_popover/index.ts b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_picker_popover/index.ts deleted file mode 100644 index 482580ea2e367..0000000000000 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_picker_popover/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -/* - * 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. - */ - -export { TimePickerPopover } from './time_picker_popover'; diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_picker_popover/time_picker_popover.scss b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_picker_popover/time_picker_popover.scss deleted file mode 100644 index 1703c2c721dc0..0000000000000 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_picker_popover/time_picker_popover.scss +++ /dev/null @@ -1,19 +0,0 @@ -.canvasTimePickerPopover { - width: 100%; - - .canvasTimePickerPopover__button { - width: 100%; - padding: $euiSizeXS; - border: $euiBorderThin; - border-radius: $euiBorderRadius; - background-color: $euiColorEmptyShade; - - &:hover { - background-color: $euiColorLightestShade; - } - } - - .canvasTimePickerPopover__anchor { - width: 100%; - } -} diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_picker_popover/time_picker_popover.tsx b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_picker_popover/time_picker_popover.tsx deleted file mode 100644 index 8f6061b688319..0000000000000 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/components/time_picker_popover/time_picker_popover.tsx +++ /dev/null @@ -1,63 +0,0 @@ -/* - * 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. - */ - -import React, { FunctionComponent, MouseEvent } from 'react'; -import PropTypes from 'prop-types'; -// @ts-ignore untyped local -import { Popover } from '../../../../../public/components/popover'; -import { PrettyDuration } from '../pretty_duration'; -import { formatDuration } from '../pretty_duration/lib/format_duration'; -import { TimePicker } from '../time_picker'; - -export interface Props { - /** Start date string */ - from: string; - /** End date string */ - to: string; - /** Function invoked when date range is changed */ - onSelect: (from: string, to: string) => void; -} - -export const TimePickerPopover: FunctionComponent = ({ from, to, onSelect }) => { - const button = (handleClick: (event: MouseEvent) => void) => ( - - ); - - return ( - - {({ closePopover }) => ( - { - onSelect(...args); - closePopover(); - }} - /> - )} - - ); -}; - -TimePickerPopover.propTypes = { - from: PropTypes.string.isRequired, - to: PropTypes.string.isRequired, - onSelect: PropTypes.func.isRequired, -}; diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/index.js b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/index.js index 7fd6e81752b3c..cbc514e218d74 100644 --- a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/index.js +++ b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/index.js @@ -9,7 +9,7 @@ import React from 'react'; import { toExpression } from '@kbn/interpreter/common'; import { syncFilterExpression } from '../../../public/lib/sync_filter_expression'; import { RendererStrings } from '../../../i18n'; -import { TimeFilter } from './components/time_filter'; +import { TimeFilter } from './components'; const { timeFilter: strings } = RendererStrings; diff --git a/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/time_filter.scss b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/time_filter.scss new file mode 100644 index 0000000000000..442332697f318 --- /dev/null +++ b/x-pack/legacy/plugins/canvas/canvas_plugin_src/renderers/time_filter/time_filter.scss @@ -0,0 +1,11 @@ +.canvasTimeFilter .euiSuperDatePicker__flexWrapper { + width: 100%; + + &.euiFlexGroup--gutterSmall { + margin: 0; + + > .euiFlexItem { + margin: 0; + } + } +} \ No newline at end of file diff --git a/x-pack/legacy/plugins/canvas/i18n/units.ts b/x-pack/legacy/plugins/canvas/i18n/units.ts index 04b1fec9b1f8a..a105031e7edf7 100644 --- a/x-pack/legacy/plugins/canvas/i18n/units.ts +++ b/x-pack/legacy/plugins/canvas/i18n/units.ts @@ -72,6 +72,10 @@ export const UnitStrings = { }), }, quickRanges: { + getYesterdayLabel: () => + i18n.translate('xpack.canvas.units.quickRange.yesterday', { + defaultMessage: 'Yesterday', + }), getTodayLabel: () => i18n.translate('xpack.canvas.units.quickRange.today', { defaultMessage: 'Today', @@ -100,93 +104,5 @@ export const UnitStrings = { i18n.translate('xpack.canvas.units.quickRange.last1Year', { defaultMessage: 'Last 1 year', }), - getThisWeekLabel: () => - i18n.translate('xpack.canvas.units.quickRange.thisWeek', { - defaultMessage: 'This week', - }), - getThisMonthLabel: () => - i18n.translate('xpack.canvas.units.quickRange.thisMonth', { - defaultMessage: 'This month', - }), - getThisYearLabel: () => - i18n.translate('xpack.canvas.units.quickRange.thisYear', { - defaultMessage: 'This year', - }), - getTheDaySoFarLabel: () => - i18n.translate('xpack.canvas.units.quickRange.theDaySoFar', { - defaultMessage: 'The day so far', - }), - getWeekToDateLabel: () => - i18n.translate('xpack.canvas.units.quickRange.weekToDate', { - defaultMessage: 'Week to date', - }), - getMonthToDateLabel: () => - i18n.translate('xpack.canvas.units.quickRange.monthToDate', { - defaultMessage: 'Month to date', - }), - getYearToDateLabel: () => - i18n.translate('xpack.canvas.units.quickRange.yearToDate', { - defaultMessage: 'Year to date', - }), - getYesterdayLabel: () => - i18n.translate('xpack.canvas.units.quickRange.yesterday', { - defaultMessage: 'Yesterday', - }), - getDayBeforeYesterdayLabel: () => - i18n.translate('xpack.canvas.units.quickRange.dayBeforeYesterday', { - defaultMessage: 'Day before yesterday', - }), - getThisDayLastWeek: () => - i18n.translate('xpack.canvas.units.quickRange.thisDayLastWeek', { - defaultMessage: 'This day last week', - }), - getPreviousWeekLabel: () => - i18n.translate('xpack.canvas.units.quickRange.previousWeek', { - defaultMessage: 'Previous week', - }), - getPreviousMonthLabel: () => - i18n.translate('xpack.canvas.units.quickRange.previousMonth', { - defaultMessage: 'Previous month', - }), - getPreviousYearLabel: () => - i18n.translate('xpack.canvas.units.quickRange.previousYear', { - defaultMessage: 'Previous year', - }), - getLast15MinutesLabel: () => - i18n.translate('xpack.canvas.units.quickRange.last15Minutes', { - defaultMessage: 'Last 15 minutes', - }), - getLast30MinutesLabel: () => - i18n.translate('xpack.canvas.units.quickRange.last30Minutes', { - defaultMessage: 'Last 30 minutes', - }), - getLast1HourLabel: () => - i18n.translate('xpack.canvas.units.quickRange.last1Hour', { - defaultMessage: 'Last 1 hour', - }), - getLast4HoursLabel: () => - i18n.translate('xpack.canvas.units.quickRange.last4Hours', { - defaultMessage: 'Last 4 hours', - }), - getLast12HoursLabel: () => - i18n.translate('xpack.canvas.units.quickRange.last12Hours', { - defaultMessage: 'Last 12 hours', - }), - getLast60DaysLabel: () => - i18n.translate('xpack.canvas.units.quickRange.last60Days', { - defaultMessage: 'Last 60 days', - }), - getLast6MonthsLabel: () => - i18n.translate('xpack.canvas.units.quickRange.last6Months', { - defaultMessage: 'Last 6 months', - }), - getLast2YearsLabel: () => - i18n.translate('xpack.canvas.units.quickRange.last2Years', { - defaultMessage: 'Last 2 years', - }), - getLast5YearsLabel: () => - i18n.translate('xpack.canvas.units.quickRange.last5Years', { - defaultMessage: 'Last 5 years', - }), }, }; diff --git a/x-pack/legacy/plugins/canvas/public/style/index.scss b/x-pack/legacy/plugins/canvas/public/style/index.scss index 39e5903ff1d96..56f9ed8d18cbe 100644 --- a/x-pack/legacy/plugins/canvas/public/style/index.scss +++ b/x-pack/legacy/plugins/canvas/public/style/index.scss @@ -64,8 +64,5 @@ @import '../../canvas_plugin_src/renderers/embeddable/embeddable.scss'; @import '../../canvas_plugin_src/renderers/plot/plot.scss'; @import '../../canvas_plugin_src/renderers/reveal_image/reveal_image.scss'; -@import '../../canvas_plugin_src/renderers/time_filter/components/datetime_calendar/datetime_calendar.scss'; -@import '../../canvas_plugin_src/renderers/time_filter/components/datetime_range_absolute/datetime_range_absolute.scss'; -@import '../../canvas_plugin_src/renderers/time_filter/components/time_picker/time_picker.scss'; -@import '../../canvas_plugin_src/renderers/time_filter/components/time_picker_popover/time_picker_popover.scss'; +@import '../../canvas_plugin_src/renderers/time_filter/time_filter.scss'; @import '../../canvas_plugin_src/uis/arguments/image_upload/image_upload.scss'; diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 8c7ea95d713d7..bec3ffd147964 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -5140,34 +5140,13 @@ "xpack.canvas.uis.views.timefilter.args.filterGroupLabel": "選択されたグループ名をエレメントのフィルター関数に適用してこのフィルターをターゲットにする", "xpack.canvas.uis.views.timefilter.args.filterGroupTitle": "フィルターグループ名", "xpack.canvas.uis.views.timefilterTitle": "時間フィルター", - "xpack.canvas.units.quickRange.dayBeforeYesterday": "一昨日", - "xpack.canvas.units.quickRange.last12Hours": "過去 12 時間", - "xpack.canvas.units.quickRange.last15Minutes": "過去 15 分間", - "xpack.canvas.units.quickRange.last1Hour": "過去 1 時間", "xpack.canvas.units.quickRange.last1Year": "過去 1 年間", "xpack.canvas.units.quickRange.last24Hours": "過去 24 時間", "xpack.canvas.units.quickRange.last2Weeks": "過去 2 週間", - "xpack.canvas.units.quickRange.last2Years": "過去 2 年間", "xpack.canvas.units.quickRange.last30Days": "過去 30 日間", - "xpack.canvas.units.quickRange.last30Minutes": "過去 30 分間", - "xpack.canvas.units.quickRange.last4Hours": "過去 4 時間", - "xpack.canvas.units.quickRange.last5Years": "過去 5 年間", - "xpack.canvas.units.quickRange.last60Days": "過去 60 日間", - "xpack.canvas.units.quickRange.last6Months": "過去 6 か月間", "xpack.canvas.units.quickRange.last7Days": "過去 7 日間", "xpack.canvas.units.quickRange.last90Days": "過去 90 日間", - "xpack.canvas.units.quickRange.monthToDate": "月初めから今日まで", - "xpack.canvas.units.quickRange.previousMonth": "先月", - "xpack.canvas.units.quickRange.previousWeek": "先週", - "xpack.canvas.units.quickRange.previousYear": "昨年", - "xpack.canvas.units.quickRange.theDaySoFar": "本日現在まで", - "xpack.canvas.units.quickRange.thisDayLastWeek": "先週のこの曜日", - "xpack.canvas.units.quickRange.thisMonth": "今月", - "xpack.canvas.units.quickRange.thisWeek": "今週", - "xpack.canvas.units.quickRange.thisYear": "今年", "xpack.canvas.units.quickRange.today": "今日", - "xpack.canvas.units.quickRange.weekToDate": "週初めから今日まで", - "xpack.canvas.units.quickRange.yearToDate": "年度の頭から今日まで", "xpack.canvas.units.quickRange.yesterday": "昨日", "xpack.canvas.units.time.days": "{days, plural, one {# 日} other {# 日}}", "xpack.canvas.units.time.hours": "{hours, plural, one {# 時間} other {# 時間}}", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 34fff4d885eda..f472247232cb8 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -5140,34 +5140,13 @@ "xpack.canvas.uis.views.timefilter.args.filterGroupLabel": "将选定组名称应用到元素的筛选函数,以定位该筛选", "xpack.canvas.uis.views.timefilter.args.filterGroupTitle": "筛选组名称", "xpack.canvas.uis.views.timefilterTitle": "时间筛选", - "xpack.canvas.units.quickRange.dayBeforeYesterday": "前天", - "xpack.canvas.units.quickRange.last12Hours": "过去 12 小时", - "xpack.canvas.units.quickRange.last15Minutes": "过去 15 分钟", - "xpack.canvas.units.quickRange.last1Hour": "过去 1 小时", "xpack.canvas.units.quickRange.last1Year": "过去 1 年", "xpack.canvas.units.quickRange.last24Hours": "过去 24 小时", "xpack.canvas.units.quickRange.last2Weeks": "过去 2 周", - "xpack.canvas.units.quickRange.last2Years": "过去 2 年", "xpack.canvas.units.quickRange.last30Days": "过去 30 天", - "xpack.canvas.units.quickRange.last30Minutes": "过去 30 分钟", - "xpack.canvas.units.quickRange.last4Hours": "过去 4 小时", - "xpack.canvas.units.quickRange.last5Years": "过去 5 年", - "xpack.canvas.units.quickRange.last60Days": "过去 60 天", - "xpack.canvas.units.quickRange.last6Months": "过去 6 个月", "xpack.canvas.units.quickRange.last7Days": "过去 7 天", "xpack.canvas.units.quickRange.last90Days": "过去 90 天", - "xpack.canvas.units.quickRange.monthToDate": "本月迄今为止", - "xpack.canvas.units.quickRange.previousMonth": "上一月", - "xpack.canvas.units.quickRange.previousWeek": "上一周", - "xpack.canvas.units.quickRange.previousYear": "上一年", - "xpack.canvas.units.quickRange.theDaySoFar": "今天迄今为止", - "xpack.canvas.units.quickRange.thisDayLastWeek": "上周本日", - "xpack.canvas.units.quickRange.thisMonth": "本月", - "xpack.canvas.units.quickRange.thisWeek": "本周", - "xpack.canvas.units.quickRange.thisYear": "本年", "xpack.canvas.units.quickRange.today": "今日", - "xpack.canvas.units.quickRange.weekToDate": "本周迄今为止", - "xpack.canvas.units.quickRange.yearToDate": "本年迄今为止", "xpack.canvas.units.quickRange.yesterday": "昨天", "xpack.canvas.units.time.days": "{days, plural, one {# 天} other {# 天}}", "xpack.canvas.units.time.hours": "{hours, plural, one {# 小时} other {# 小时}}", From 7983d1dff73beac45d9719fe264391928982f373 Mon Sep 17 00:00:00 2001 From: Paul Tavares <56442535+paul-tavares@users.noreply.github.com> Date: Fri, 20 Mar 2020 16:32:55 -0400 Subject: [PATCH 10/31] [Endpoint] Integrate the Policy list with ingest datasources api (#60548) * Use ingest API to get endpoint datasources * Add `application` service to `KibanaContextProvider` * Adjust Policy list to show data available from API * Added ingest service + refactored middleware * handle api failures/errors * Removed policy list fake_data generator * Fix typing * Rename method + added explicit return type * move dispatch outside of try block * Removed unnecessary action * Added FIXME comments with link to issue * Skip some functional tests * added tests for ingest service * Policy list tests - turn it all off Co-authored-by: Elastic Machine --- .../public/applications/endpoint/index.tsx | 9 +- .../endpoint/services/ingest.test.ts | 53 ++++++++ .../applications/endpoint/services/ingest.ts | 62 +++++++++ .../store/policy_details/middleware.ts | 6 +- .../endpoint/store/policy_details/reducer.ts | 12 +- .../endpoint/store/policy_list/action.ts | 12 +- .../endpoint/store/policy_list/fake_data.ts | 63 --------- .../endpoint/store/policy_list/middleware.ts | 25 +++- .../endpoint/store/policy_list/reducer.ts | 10 ++ .../endpoint/store/policy_list/selectors.ts | 2 + .../public/applications/endpoint/types.ts | 19 +-- .../endpoint/view/policy/policy_list.tsx | 125 +++++++----------- .../apps/endpoint/policy_details.ts | 3 +- .../functional/apps/endpoint/policy_list.ts | 4 +- 14 files changed, 230 insertions(+), 175 deletions(-) create mode 100644 x-pack/plugins/endpoint/public/applications/endpoint/services/ingest.test.ts create mode 100644 x-pack/plugins/endpoint/public/applications/endpoint/services/ingest.ts delete mode 100644 x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/fake_data.ts diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/index.tsx b/x-pack/plugins/endpoint/public/applications/endpoint/index.tsx index 997113754f95d..884646369b4b1 100644 --- a/x-pack/plugins/endpoint/public/applications/endpoint/index.tsx +++ b/x-pack/plugins/endpoint/public/applications/endpoint/index.tsx @@ -50,13 +50,18 @@ interface RouterProps { } const AppRoot: React.FunctionComponent = React.memo( - ({ basename, store, coreStart: { http, notifications, uiSettings }, depsStart: { data } }) => { + ({ + basename, + store, + coreStart: { http, notifications, uiSettings, application }, + depsStart: { data }, + }) => { const isDarkMode = useObservable(uiSettings.get$('theme:darkMode')); return ( - + diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/services/ingest.test.ts b/x-pack/plugins/endpoint/public/applications/endpoint/services/ingest.test.ts new file mode 100644 index 0000000000000..a2c1dfbe09a48 --- /dev/null +++ b/x-pack/plugins/endpoint/public/applications/endpoint/services/ingest.test.ts @@ -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. + */ + +import { httpServiceMock } from '../../../../../../../src/core/public/mocks'; +import { sendGetDatasource, sendGetEndpointSpecificDatasources } from './ingest'; + +describe('ingest service', () => { + let http: ReturnType; + + beforeEach(() => { + http = httpServiceMock.createStartContract(); + }); + + describe('sendGetEndpointSpecificDatasources()', () => { + it('auto adds kuery to api request', async () => { + await sendGetEndpointSpecificDatasources(http); + expect(http.get).toHaveBeenCalledWith('/api/ingest_manager/datasources', { + query: { + kuery: 'datasources.package.name: endpoint', + }, + }); + }); + it('supports additional KQL to be defined on input for query params', async () => { + await sendGetEndpointSpecificDatasources(http, { + query: { kuery: 'someValueHere', page: 1, perPage: 10 }, + }); + expect(http.get).toHaveBeenCalledWith('/api/ingest_manager/datasources', { + query: { + kuery: 'someValueHere and datasources.package.name: endpoint', + perPage: 10, + page: 1, + }, + }); + }); + }); + describe('sendGetDatasource()', () => { + it('builds correct API path', async () => { + await sendGetDatasource(http, '123'); + expect(http.get).toHaveBeenCalledWith('/api/ingest_manager/datasources/123', undefined); + }); + it('supports http options', async () => { + await sendGetDatasource(http, '123', { query: { page: 1 } }); + expect(http.get).toHaveBeenCalledWith('/api/ingest_manager/datasources/123', { + query: { + page: 1, + }, + }); + }); + }); +}); diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/services/ingest.ts b/x-pack/plugins/endpoint/public/applications/endpoint/services/ingest.ts new file mode 100644 index 0000000000000..fbb92f8bbe915 --- /dev/null +++ b/x-pack/plugins/endpoint/public/applications/endpoint/services/ingest.ts @@ -0,0 +1,62 @@ +/* + * 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. + */ + +import { HttpFetchOptions, HttpStart } from 'kibana/public'; +import { GetDatasourcesRequest } from '../../../../../ingest_manager/common/types/rest_spec'; +import { PolicyData } from '../types'; + +const INGEST_API_ROOT = `/api/ingest_manager`; +const INGEST_API_DATASOURCES = `${INGEST_API_ROOT}/datasources`; + +// FIXME: Import from ingest after - https://github.com/elastic/kibana/issues/60677 +export interface GetDatasourcesResponse { + items: PolicyData[]; + total: number; + page: number; + perPage: number; + success: boolean; +} + +// FIXME: Import from Ingest after - https://github.com/elastic/kibana/issues/60677 +export interface GetDatasourceResponse { + item: PolicyData; + success: boolean; +} + +/** + * Retrieves a list of endpoint specific datasources (those created with a `package.name` of + * `endpoint`) from Ingest + * @param http + * @param options + */ +export const sendGetEndpointSpecificDatasources = ( + http: HttpStart, + options: HttpFetchOptions & Partial = {} +): Promise => { + return http.get(INGEST_API_DATASOURCES, { + ...options, + query: { + ...options.query, + kuery: `${ + options?.query?.kuery ? options.query.kuery + ' and ' : '' + }datasources.package.name: endpoint`, + }, + }); +}; + +/** + * Retrieves a single datasource based on ID from ingest + * @param http + * @param datasourceId + * @param options + */ +export const sendGetDatasource = ( + http: HttpStart, + datasourceId: string, + options?: HttpFetchOptions +) => { + return http.get(`${INGEST_API_DATASOURCES}/${datasourceId}`, options); +}; diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_details/middleware.ts b/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_details/middleware.ts index 92a1c036c0211..39d7eb93569e2 100644 --- a/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_details/middleware.ts +++ b/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_details/middleware.ts @@ -6,8 +6,11 @@ import { MiddlewareFactory, PolicyDetailsState } from '../../types'; import { selectPolicyIdFromParams, isOnPolicyDetailsPage } from './selectors'; +import { sendGetDatasource } from '../../services/ingest'; export const policyDetailsMiddlewareFactory: MiddlewareFactory = coreStart => { + const http = coreStart.http; + return ({ getState, dispatch }) => next => async action => { next(action); const state = getState(); @@ -15,8 +18,7 @@ export const policyDetailsMiddlewareFactory: MiddlewareFactory { return { - policyItem: { - name: '', - total: 0, - pending: 0, - failed: 0, - id: '', - created_by: '', - created: '', - updated_by: '', - updated: '', - }, + policyItem: undefined, isLoading: false, }; }; diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/action.ts b/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/action.ts index 5ac2a4328b00a..3f4f3f39e9be0 100644 --- a/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/action.ts +++ b/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/action.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { PolicyData } from '../../types'; +import { PolicyData, ServerApiError } from '../../types'; interface ServerReturnedPolicyListData { type: 'serverReturnedPolicyListData'; @@ -16,6 +16,11 @@ interface ServerReturnedPolicyListData { }; } +interface ServerFailedToReturnPolicyListData { + type: 'serverFailedToReturnPolicyListData'; + payload: ServerApiError; +} + interface UserPaginatedPolicyListTable { type: 'userPaginatedPolicyListTable'; payload: { @@ -24,4 +29,7 @@ interface UserPaginatedPolicyListTable { }; } -export type PolicyListAction = ServerReturnedPolicyListData | UserPaginatedPolicyListTable; +export type PolicyListAction = + | ServerReturnedPolicyListData + | UserPaginatedPolicyListTable + | ServerFailedToReturnPolicyListData; diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/fake_data.ts b/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/fake_data.ts deleted file mode 100644 index 2312d3397f7be..0000000000000 --- a/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/fake_data.ts +++ /dev/null @@ -1,63 +0,0 @@ -/* - * 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. - */ - -// !!!! Should be deleted when https://github.com/elastic/endpoint-app-team/issues/150 -// is implemented - -const dateOffsets = [ - 0, - 1000, - 300000, // 5 minutes - 3.6e6, // 1 hour - 86340000, // 23h, 59m - 9e7, // 25h - 9e7 * 5, // 5d -]; - -const randomNumbers = [5, 50, 500, 5000, 50000]; - -const getRandomDateIsoString = () => { - const randomIndex = Math.floor(Math.random() * Math.floor(dateOffsets.length)); - return new Date(Date.now() - dateOffsets[randomIndex]).toISOString(); -}; - -const getRandomNumber = () => { - const randomIndex = Math.floor(Math.random() * Math.floor(randomNumbers.length)); - return randomNumbers[randomIndex]; -}; - -const policyItem = (id: string) => { - return { - name: `policy with some protections ${id}`, - total: getRandomNumber(), - pending: getRandomNumber(), - failed: getRandomNumber(), - id: `${id}`, - created_by: `admin ABC`, - created: getRandomDateIsoString(), - updated_by: 'admin 123', - updated: getRandomDateIsoString(), - }; -}; - -export const getFakeDatasourceApiResponse = async (page: number, pageSize: number) => { - await new Promise(resolve => setTimeout(resolve, 500)); - - // Emulates the API response - see PR: - // https://github.com/elastic/kibana/pull/56567/files#diff-431549a8739efe0c56763f164c32caeeR25 - return { - items: Array.from({ length: pageSize }, (x, i) => policyItem(`${i + 1}`)), - success: true, - total: pageSize * 10, - page, - perPage: pageSize, - }; -}; - -export const getFakeDatasourceDetailsApiResponse = async (id: string) => { - await new Promise(resolve => setTimeout(resolve, 500)); - return policyItem(id); -}; diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/middleware.ts b/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/middleware.ts index f8e2b7d07c389..ebfee5dbe6a7e 100644 --- a/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/middleware.ts +++ b/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/middleware.ts @@ -5,8 +5,11 @@ */ import { MiddlewareFactory, PolicyListState } from '../../types'; +import { GetDatasourcesResponse, sendGetEndpointSpecificDatasources } from '../../services/ingest'; export const policyListMiddlewareFactory: MiddlewareFactory = coreStart => { + const http = coreStart.http; + return ({ getState, dispatch }) => next => async action => { next(action); @@ -26,10 +29,24 @@ export const policyListMiddlewareFactory: MiddlewareFactory = c pageIndex = state.pageIndex; } - // Need load data from API and remove fake data below - // Refactor tracked via: https://github.com/elastic/endpoint-app-team/issues/150 - const { getFakeDatasourceApiResponse } = await import('./fake_data'); - const { items: policyItems, total } = await getFakeDatasourceApiResponse(pageIndex, pageSize); + let response: GetDatasourcesResponse; + + try { + response = await sendGetEndpointSpecificDatasources(http, { + query: { + perPage: pageSize, + page: pageIndex + 1, + }, + }); + } catch (err) { + dispatch({ + type: 'serverFailedToReturnPolicyListData', + payload: err.body ?? err, + }); + return; + } + + const { items: policyItems, total } = response; dispatch({ type: 'serverReturnedPolicyListData', diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/reducer.ts b/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/reducer.ts index 77f536d413ae3..b964f4f023866 100644 --- a/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/reducer.ts +++ b/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/reducer.ts @@ -12,6 +12,7 @@ const initialPolicyListState = (): PolicyListState => { return { policyItems: [], isLoading: false, + apiError: undefined, pageIndex: 0, pageSize: 10, total: 0, @@ -30,12 +31,21 @@ export const policyListReducer: Reducer = ( }; } + if (action.type === 'serverFailedToReturnPolicyListData') { + return { + ...state, + apiError: action.payload, + isLoading: false, + }; + } + if ( action.type === 'userPaginatedPolicyListTable' || (action.type === 'userNavigatedToPage' && action.payload === 'policyListPage') ) { return { ...state, + apiError: undefined, isLoading: true, }; } diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/selectors.ts b/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/selectors.ts index b9c2edbf5d55b..7ca25e81ce75a 100644 --- a/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/selectors.ts +++ b/x-pack/plugins/endpoint/public/applications/endpoint/store/policy_list/selectors.ts @@ -15,3 +15,5 @@ export const selectPageSize = (state: PolicyListState) => state.pageSize; export const selectTotal = (state: PolicyListState) => state.total; export const selectIsLoading = (state: PolicyListState) => state.isLoading; + +export const selectApiError = (state: PolicyListState) => state.apiError; diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/types.ts b/x-pack/plugins/endpoint/public/applications/endpoint/types.ts index 3045f42a93fe2..dae2c93c9dd04 100644 --- a/x-pack/plugins/endpoint/public/applications/endpoint/types.ts +++ b/x-pack/plugins/endpoint/public/applications/endpoint/types.ts @@ -16,6 +16,7 @@ import { import { EndpointPluginStartDependencies } from '../../plugin'; import { AppAction } from './store/action'; import { CoreStart } from '../../../../../../src/core/public'; +import { Datasource } from '../../../../ingest_manager/common/types/models'; export { AppAction }; export type MiddlewareFactory = ( @@ -50,18 +51,10 @@ export interface ServerApiError { message: string; } -// REFACTOR to use Types from Ingest Manager - see: https://github.com/elastic/endpoint-app-team/issues/150 -export interface PolicyData { - name: string; - total: number; - pending: number; - failed: number; - id: string; - created_by: string; - created: string; - updated_by: string; - updated: string; -} +/** + * An Endpoint Policy. + */ +export type PolicyData = Datasource; /** * Policy list store state @@ -69,6 +62,8 @@ export interface PolicyData { export interface PolicyListState { /** Array of policy items */ policyItems: PolicyData[]; + /** API error if loading data failed */ + apiError?: ServerApiError; /** total number of policies */ total: number; /** Number of policies per page */ diff --git a/x-pack/plugins/endpoint/public/applications/endpoint/view/policy/policy_list.tsx b/x-pack/plugins/endpoint/public/applications/endpoint/view/policy/policy_list.tsx index e7ce53679bbe7..f949efa46a2bd 100644 --- a/x-pack/plugins/endpoint/public/applications/endpoint/view/policy/policy_list.tsx +++ b/x-pack/plugins/endpoint/public/applications/endpoint/view/policy/policy_list.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { useCallback, useMemo } from 'react'; +import React, { SyntheticEvent, useCallback, useEffect, useMemo } from 'react'; import { EuiPage, EuiPageBody, @@ -16,17 +16,15 @@ import { EuiBasicTable, EuiText, EuiTableFieldDataColumnType, - EuiToolTip, EuiLink, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { FormattedMessage, FormattedNumber } from '@kbn/i18n/react'; +import { FormattedMessage } from '@kbn/i18n/react'; import { useDispatch } from 'react-redux'; -import styled from 'styled-components'; import { useHistory } from 'react-router-dom'; import { usePageId } from '../use_page_id'; -import { FormattedDateAndTime } from '../formatted_date_time'; import { + selectApiError, selectIsLoading, selectPageIndex, selectPageSize, @@ -36,21 +34,12 @@ import { import { usePolicyListSelector } from './policy_hooks'; import { PolicyListAction } from '../../store/policy_list'; import { PolicyData } from '../../types'; -import { TruncateText } from '../../components/truncate_text'; +import { useKibana } from '../../../../../../../../src/plugins/kibana_react/public'; interface TableChangeCallbackArguments { page: { index: number; size: number }; } -const TruncateTooltipText = styled(TruncateText)` - .euiToolTipAnchor { - display: block; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - } -`; - const PolicyLink: React.FC<{ name: string; route: string }> = ({ name, route }) => { const history = useHistory(); @@ -70,29 +59,28 @@ const renderPolicyNameLink = (value: string, _item: PolicyData) => { return ; }; -const renderDate = (date: string, _item: PolicyData) => ( - - - - - -); - -const renderFormattedNumber = (value: number, _item: PolicyData) => ( - - - -); - export const PolicyList = React.memo(() => { usePageId('policyListPage'); + const { services, notifications } = useKibana(); + const dispatch = useDispatch<(action: PolicyListAction) => void>(); const policyItems = usePolicyListSelector(selectPolicyItems); const pageIndex = usePolicyListSelector(selectPageIndex); const pageSize = usePolicyListSelector(selectPageSize); const totalItemCount = usePolicyListSelector(selectTotal); const loading = usePolicyListSelector(selectIsLoading); + const apiError = usePolicyListSelector(selectApiError); + + useEffect(() => { + if (apiError) { + notifications.toasts.danger({ + title: apiError.error, + body: apiError.message, + toastLifeTimeMs: 10000, + }); + } + }, [apiError, dispatch, notifications.toasts]); const paginationSetup = useMemo(() => { return { @@ -128,67 +116,52 @@ export const PolicyList = React.memo(() => { truncateText: true, }, { - field: 'total', - name: i18n.translate('xpack.endpoint.policyList.totalField', { - defaultMessage: 'Total', + field: 'revision', + name: i18n.translate('xpack.endpoint.policyList.revisionField', { + defaultMessage: 'Revision', }), - render: renderFormattedNumber, dataType: 'number', - truncateText: true, - width: '15ch', }, { - field: 'pending', - name: i18n.translate('xpack.endpoint.policyList.pendingField', { - defaultMessage: 'Pending', + field: 'package', + name: i18n.translate('xpack.endpoint.policyList.versionField', { + defaultMessage: 'Version', }), - render: renderFormattedNumber, - dataType: 'number', - truncateText: true, - width: '15ch', - }, - { - field: 'failed', - name: i18n.translate('xpack.endpoint.policyList.failedField', { - defaultMessage: 'Failed', - }), - render: renderFormattedNumber, - dataType: 'number', - truncateText: true, - width: '15ch', - }, - { - field: 'created_by', - name: i18n.translate('xpack.endpoint.policyList.createdByField', { - defaultMessage: 'Created By', - }), - truncateText: true, - }, - { - field: 'created', - name: i18n.translate('xpack.endpoint.policyList.createdField', { - defaultMessage: 'Created', - }), - render: renderDate, - truncateText: true, + render(pkg) { + return `${pkg.title} v${pkg.version}`; + }, }, { - field: 'updated_by', - name: i18n.translate('xpack.endpoint.policyList.updatedByField', { - defaultMessage: 'Last Updated By', + field: 'description', + name: i18n.translate('xpack.endpoint.policyList.descriptionField', { + defaultMessage: 'Description', }), truncateText: true, }, { - field: 'updated', - name: i18n.translate('xpack.endpoint.policyList.updatedField', { - defaultMessage: 'Last Updated', + field: 'config_id', + name: i18n.translate('xpack.endpoint.policyList.agentConfigField', { + defaultMessage: 'Agent Configuration', }), - render: renderDate, - truncateText: true, + render(version: string) { + return ( + // eslint-disable-next-line @elastic/eui/href-or-on-click + { + ev.preventDefault(); + services.application.navigateToApp('ingestManager', { + path: `#/configs/${version}`, + }); + }} + > + {version} + + ); + }, }, ], - [] + [services.application] ); return ( diff --git a/x-pack/test/functional/apps/endpoint/policy_details.ts b/x-pack/test/functional/apps/endpoint/policy_details.ts index 39b6e7a9f4fb7..f251dcd93014e 100644 --- a/x-pack/test/functional/apps/endpoint/policy_details.ts +++ b/x-pack/test/functional/apps/endpoint/policy_details.ts @@ -10,7 +10,8 @@ export default function({ getPageObjects, getService }: FtrProviderContext) { const pageObjects = getPageObjects(['common', 'endpoint']); const testSubjects = getService('testSubjects'); - describe('Endpoint Policy Details', function() { + // Skipped until we can figure out how to load data for Ingest + describe.skip('Endpoint Policy Details', function() { this.tags(['ciGroup7']); it('loads the Policy Details Page', async () => { diff --git a/x-pack/test/functional/apps/endpoint/policy_list.ts b/x-pack/test/functional/apps/endpoint/policy_list.ts index 382963bc2b0c7..c54eafdd8b787 100644 --- a/x-pack/test/functional/apps/endpoint/policy_list.ts +++ b/x-pack/test/functional/apps/endpoint/policy_list.ts @@ -10,8 +10,8 @@ export default function({ getPageObjects, getService }: FtrProviderContext) { const pageObjects = getPageObjects(['common', 'endpoint']); const testSubjects = getService('testSubjects'); - // FLAKY: https://github.com/elastic/kibana/issues/57946 - describe('Endpoint Policy List', function() { + // FIXME: Skipped until we can figure out how to load data for Ingest + describe.skip('Endpoint Policy List', function() { this.tags(['ciGroup7']); before(async () => { await pageObjects.common.navigateToUrlWithBrowserHistory('endpoint', '/policy'); From 5efd59b43ffcc747d43222a08c772cb658650d5e Mon Sep 17 00:00:00 2001 From: Patrick Mueller Date: Fri, 20 Mar 2020 16:36:01 -0400 Subject: [PATCH 11/31] [Alerting]: harden APIs of built-in alert index-threshold (#60702) resolves https://github.com/elastic/kibana/issues/59889 The index threshold APIs - used by both the index threshold UI and the alert executor - were returning errors (500's from http endpoints) when getting errors from ES. These have been changed so that the error is logged as a warning, and the relevant API returns an "empty" result. Another 500 response was found while experimenting with this. Apparently the date_range agg requires a date format to be passed in if the date format in ES is not an ISO date. The repro on this was to select the `.security` alias (or it's index) within the index threshold alert UI, and then select one of it's date fields. --- .../index_threshold/lib/time_series_query.ts | 5 ++-- .../index_threshold/routes/fields.ts | 7 +++-- .../index_threshold/routes/indices.ts | 11 +++++--- .../routes/time_series_query.ts | 22 ++++++---------- .../common/lib/es_test_index_tool.ts | 4 +++ .../index_threshold/alert.ts | 9 ++++--- .../index_threshold/create_test_data.ts | 1 + .../index_threshold/fields_endpoint.ts | 6 +++++ .../index_threshold/indices_endpoint.ts | 6 +++++ .../time_series_query_endpoint.ts | 26 +++++++++++++++++++ 10 files changed, 72 insertions(+), 25 deletions(-) diff --git a/x-pack/plugins/alerting_builtins/server/alert_types/index_threshold/lib/time_series_query.ts b/x-pack/plugins/alerting_builtins/server/alert_types/index_threshold/lib/time_series_query.ts index 0382792dafb35..1d9cc1c98bc01 100644 --- a/x-pack/plugins/alerting_builtins/server/alert_types/index_threshold/lib/time_series_query.ts +++ b/x-pack/plugins/alerting_builtins/server/alert_types/index_threshold/lib/time_series_query.ts @@ -94,6 +94,7 @@ export async function timeSeriesQuery( dateAgg: { date_range: { field: timeField, + format: 'strict_date_time', ranges: dateRangeInfo.dateRanges, }, }, @@ -134,8 +135,8 @@ export async function timeSeriesQuery( esResult = await callCluster('search', esQuery); } catch (err) { // console.log('time_series_query.ts error\n', JSON.stringify(err, null, 4)); - logger.warn(`${logPrefix} error: ${JSON.stringify(err.message)}`); - throw new Error('error running search'); + logger.warn(`${logPrefix} error: ${err.message}`); + return { results: [] }; } // console.log('time_series_query.ts response\n', JSON.stringify(esResult, null, 4)); diff --git a/x-pack/plugins/alerting_builtins/server/alert_types/index_threshold/routes/fields.ts b/x-pack/plugins/alerting_builtins/server/alert_types/index_threshold/routes/fields.ts index c862d96828eb4..32d6409d9c9fb 100644 --- a/x-pack/plugins/alerting_builtins/server/alert_types/index_threshold/routes/fields.ts +++ b/x-pack/plugins/alerting_builtins/server/alert_types/index_threshold/routes/fields.ts @@ -53,8 +53,11 @@ export function createFieldsRoute(service: Service, router: IRouter, baseRoute: try { rawFields = await getRawFields(ctx.core.elasticsearch.dataClient, req.body.indexPatterns); } catch (err) { - service.logger.debug(`route ${path} error: ${err.message}`); - return res.internalError({ body: 'error getting field data' }); + const indexPatterns = req.body.indexPatterns.join(','); + service.logger.warn( + `route ${path} error getting fields from pattern "${indexPatterns}": ${err.message}` + ); + return res.ok({ body: { fields: [] } }); } const result = { fields: getFieldsFromRawFields(rawFields) }; diff --git a/x-pack/plugins/alerting_builtins/server/alert_types/index_threshold/routes/indices.ts b/x-pack/plugins/alerting_builtins/server/alert_types/index_threshold/routes/indices.ts index 760ed21078de2..c08450448b44c 100644 --- a/x-pack/plugins/alerting_builtins/server/alert_types/index_threshold/routes/indices.ts +++ b/x-pack/plugins/alerting_builtins/server/alert_types/index_threshold/routes/indices.ts @@ -54,15 +54,18 @@ export function createIndicesRoute(service: Service, router: IRouter, baseRoute: try { aliases = await getAliasesFromPattern(ctx.core.elasticsearch.dataClient, pattern); } catch (err) { - service.logger.debug(`route ${path} error: ${err.message}`); - return res.internalError({ body: 'error getting alias data' }); + service.logger.warn( + `route ${path} error getting aliases from pattern "${pattern}": ${err.message}` + ); } + let indices: string[] = []; try { indices = await getIndicesFromPattern(ctx.core.elasticsearch.dataClient, pattern); } catch (err) { - service.logger.debug(`route ${path} error: ${err.message}`); - return res.internalError({ body: 'error getting index data' }); + service.logger.warn( + `route ${path} error getting indices from pattern "${pattern}": ${err.message}` + ); } const result = { indices: uniqueCombined(aliases, indices, MAX_INDICES) }; diff --git a/x-pack/plugins/alerting_builtins/server/alert_types/index_threshold/routes/time_series_query.ts b/x-pack/plugins/alerting_builtins/server/alert_types/index_threshold/routes/time_series_query.ts index 16864d250a747..c8129c2428ee4 100644 --- a/x-pack/plugins/alerting_builtins/server/alert_types/index_threshold/routes/time_series_query.ts +++ b/x-pack/plugins/alerting_builtins/server/alert_types/index_threshold/routes/time_series_query.ts @@ -13,7 +13,7 @@ import { } from 'kibana/server'; import { Service } from '../../../types'; -import { TimeSeriesQuery, TimeSeriesQuerySchema, TimeSeriesResult } from '../lib/time_series_types'; +import { TimeSeriesQuery, TimeSeriesQuerySchema } from '../lib/time_series_types'; export { TimeSeriesQuery, TimeSeriesResult } from '../lib/time_series_types'; export function createTimeSeriesQueryRoute(service: Service, router: IRouter, baseRoute: string) { @@ -33,21 +33,15 @@ export function createTimeSeriesQueryRoute(service: Service, router: IRouter, ba req: KibanaRequest, res: KibanaResponseFactory ): Promise { - service.logger.debug(`route query_data request: ${JSON.stringify(req.body)}`); + service.logger.debug(`route ${path} request: ${JSON.stringify(req.body)}`); - let result: TimeSeriesResult; - try { - result = await service.indexThreshold.timeSeriesQuery({ - logger: service.logger, - callCluster: ctx.core.elasticsearch.dataClient.callAsCurrentUser, - query: req.body, - }); - } catch (err) { - service.logger.debug(`route query_data error: ${err.message}`); - return res.internalError({ body: 'error running time series query' }); - } + const result = await service.indexThreshold.timeSeriesQuery({ + logger: service.logger, + callCluster: ctx.core.elasticsearch.dataClient.callAsCurrentUser, + query: req.body, + }); - service.logger.debug(`route query_data response: ${JSON.stringify(result)}`); + service.logger.debug(`route ${path} response: ${JSON.stringify(result)}`); return res.ok({ body: result }); } } diff --git a/x-pack/test/alerting_api_integration/common/lib/es_test_index_tool.ts b/x-pack/test/alerting_api_integration/common/lib/es_test_index_tool.ts index 999a8686e0ee7..14a91325d1cc1 100644 --- a/x-pack/test/alerting_api_integration/common/lib/es_test_index_tool.ts +++ b/x-pack/test/alerting_api_integration/common/lib/es_test_index_tool.ts @@ -41,6 +41,10 @@ export class ESTestIndexTool { type: 'date', format: 'strict_date_time', }, + date_epoch_millis: { + type: 'date', + format: 'epoch_millis', + }, testedValue: { type: 'long', }, diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/index_threshold/alert.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/index_threshold/alert.ts index 13f3a4971183c..87acbcf99d383 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/index_threshold/alert.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/index_threshold/alert.ts @@ -172,12 +172,14 @@ export default function alertTests({ getService }: FtrProviderContext) { // create some more documents in the first group createEsDocumentsInGroups(1); + // this never fires because of bad fields error await createAlert({ name: 'never fire', + timeField: 'source', // bad field for time aggType: 'avg', - aggField: 'testedValue', + aggField: 'source', // bad field for agg groupBy: 'all', - thresholdComparator: '<', + thresholdComparator: '>', threshold: [0], }); @@ -303,6 +305,7 @@ export default function alertTests({ getService }: FtrProviderContext) { name: string; aggType: string; aggField?: string; + timeField?: string; groupBy: 'all' | 'top'; termField?: string; termSize?: number; @@ -347,7 +350,7 @@ export default function alertTests({ getService }: FtrProviderContext) { actions: [action], params: { index: ES_TEST_INDEX_NAME, - timeField: 'date', + timeField: params.timeField || 'date', aggType: params.aggType, aggField: params.aggField, groupBy: params.groupBy, diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/index_threshold/create_test_data.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/index_threshold/create_test_data.ts index 21f73ac9b9833..1a83f34f0fdfb 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/index_threshold/create_test_data.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/index_threshold/create_test_data.ts @@ -53,6 +53,7 @@ async function createEsDocument(es: any, epochMillis: number, testedValue: numbe source: DOCUMENT_SOURCE, reference: DOCUMENT_REFERENCE, date: new Date(epochMillis).toISOString(), + date_epoch_millis: epochMillis, testedValue, group, }; diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/index_threshold/fields_endpoint.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/index_threshold/fields_endpoint.ts index fa7aed2c035b9..c6f8f6d1b80b1 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/index_threshold/fields_endpoint.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/index_threshold/fields_endpoint.ts @@ -139,6 +139,12 @@ export default function fieldsEndpointTests({ getService }: FtrProviderContext) expect(field.name).to.eql('updated_at'); expect(field.type).to.eql('date'); }); + + // TODO: the pattern '*a:b,c:d*' throws an exception in dev, but not ci! + it('should handle no_such_remote_cluster', async () => { + const result = await runQueryExpect({ indexPatterns: ['*a:b,c:d*'] }, 200); + expect(result.fields.length).to.be(0); + }); }); function getFieldNamed(fields: any[], fieldName: string): any | undefined { diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/index_threshold/indices_endpoint.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/index_threshold/indices_endpoint.ts index 6908398deb57b..72484fa70f9cc 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/index_threshold/indices_endpoint.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/index_threshold/indices_endpoint.ts @@ -105,6 +105,12 @@ export default function indicesEndpointTests({ getService }: FtrProviderContext) expect(result.indices).to.be.an('array'); expect(result.indices.includes('.kibana')).to.be(true); }); + + // TODO: the pattern '*a:b,c:d*' throws an exception in dev, but not ci! + it('should handle no_such_remote_cluster', async () => { + const result = await runQueryExpect({ pattern: '*a:b,c:d*' }, 200); + expect(result.indices.length).to.be(0); + }); }); async function runQueryExpect(requestBody: any, status: number): Promise { diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/index_threshold/time_series_query_endpoint.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/index_threshold/time_series_query_endpoint.ts index c9b488da5dec5..932ffe3a7ce14 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/index_threshold/time_series_query_endpoint.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/index_threshold/time_series_query_endpoint.ts @@ -273,6 +273,32 @@ export default function timeSeriesQueryEndpointTests({ getService }: FtrProvider }; expect(await runQueryExpect(query, 400)).eql(expected); }); + + it('should handle epoch_millis time field', async () => { + const query = getQueryBody({ + dateStart: START_DATE, + dateEnd: START_DATE, + timeField: 'date_epoch_millis', + }); + const expected = { + results: [{ group: 'all documents', metrics: [[START_DATE, 6]] }], + }; + expect(await runQueryExpect(query, 200)).eql(expected); + }); + + it('should handle ES errors', async () => { + const query = getQueryBody({ + dateStart: START_DATE, + dateEnd: START_DATE, + timeField: 'source', // bad field for time + aggType: 'avg', + aggField: 'source', // bad field for agg + }); + const expected = { + results: [], + }; + expect(await runQueryExpect(query, 200)).eql(expected); + }); }); async function runQueryExpect(requestBody: TimeSeriesQuery, status: number): Promise { From 5d93a0890c436d11969c9757dfeb2ceb1cf41ec8 Mon Sep 17 00:00:00 2001 From: MadameSheema Date: Fri, 20 Mar 2020 21:52:26 +0100 Subject: [PATCH 12/31] increases loading timeout (#60788) --- x-pack/legacy/plugins/siem/cypress/tasks/login.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/legacy/plugins/siem/cypress/tasks/login.ts b/x-pack/legacy/plugins/siem/cypress/tasks/login.ts index 883bdb2a4820a..3abf5a6930486 100644 --- a/x-pack/legacy/plugins/siem/cypress/tasks/login.ts +++ b/x-pack/legacy/plugins/siem/cypress/tasks/login.ts @@ -131,5 +131,5 @@ export const loginAndWaitForPageWithoutDateRange = (url: string) => { login(); cy.viewport('macbook-15'); cy.visit(url); - cy.contains('a', 'SIEM'); + cy.contains('a', 'SIEM', { timeout: 60000 }); }; From fc24febec9f25f31b8921ff7ad905fb7b520bb25 Mon Sep 17 00:00:00 2001 From: Wylie Conlon Date: Fri, 20 Mar 2020 17:03:59 -0400 Subject: [PATCH 13/31] [Lens] Resetting a layer generates new suggestions (#60674) * [Lens] Resetting a layer generates new suggestions * Include preview in tests --- .../editor_frame/layer_actions.test.ts | 32 +++++++++++++------ .../editor_frame/layer_actions.ts | 2 ++ 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/layer_actions.test.ts b/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/layer_actions.test.ts index 0fd38a8fdba65..3363e34a01568 100644 --- a/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/layer_actions.test.ts +++ b/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/layer_actions.test.ts @@ -28,19 +28,21 @@ function createTestArgs(initialLayerIds: string[]) { appendLayer: (layerIds: unknown, layerId: string) => [...(layerIds as string[]), layerId], }; + const datasourceStates = { + ds1: { + isLoading: false, + state: initialLayerIds.slice(0, 1), + }, + ds2: { + isLoading: false, + state: initialLayerIds.slice(1), + }, + }; + return { state: { activeDatasourceId: 'ds1', - datasourceStates: { - ds1: { - isLoading: false, - state: initialLayerIds.slice(0, 1), - }, - ds2: { - isLoading: false, - state: initialLayerIds.slice(1), - }, - }, + datasourceStates, title: 'foo', visualization: { activeId: 'vis1', @@ -53,6 +55,13 @@ function createTestArgs(initialLayerIds: string[]) { ds2: testDatasource('ds2'), }, trackUiEvent, + stagedPreview: { + visualization: { + activeId: 'vis1', + state: initialLayerIds, + }, + datasourceStates, + }, }; } @@ -70,6 +79,7 @@ describe('removeLayer', () => { expect(newState.visualization.state).toEqual(['vis_clear_layer1']); expect(newState.datasourceStates.ds1.state).toEqual(['ds1_clear_layer1']); expect(newState.datasourceStates.ds2.state).toEqual([]); + expect(newState.stagedPreview).not.toBeDefined(); expect(trackUiEvent).toHaveBeenCalledWith('layer_cleared'); }); @@ -89,6 +99,7 @@ describe('removeLayer', () => { expect(newState.visualization.state).toEqual(['layer2']); expect(newState.datasourceStates.ds1.state).toEqual([]); expect(newState.datasourceStates.ds2.state).toEqual(['layer2']); + expect(newState.stagedPreview).not.toBeDefined(); expect(trackUiEvent).toHaveBeenCalledWith('layer_removed'); }); }); @@ -110,6 +121,7 @@ describe('appendLayer', () => { expect(newState.visualization.state).toEqual(['layer1', 'layer2', 'foo']); expect(newState.datasourceStates.ds1.state).toEqual(['layer1', 'foo']); expect(newState.datasourceStates.ds2.state).toEqual(['layer2']); + expect(newState.stagedPreview).not.toBeDefined(); expect(trackUiEvent).toHaveBeenCalledWith('layer_added'); }); }); diff --git a/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/layer_actions.ts b/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/layer_actions.ts index e0562e8ca8e11..cc2cbb172d23e 100644 --- a/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/layer_actions.ts +++ b/x-pack/legacy/plugins/lens/public/editor_frame_service/editor_frame/layer_actions.ts @@ -50,6 +50,7 @@ export function removeLayer(opts: RemoveLayerOptions): EditorFrameState { ? activeVisualization.clearLayer(state.visualization.state, layerId) : activeVisualization.removeLayer(state.visualization.state, layerId), }, + stagedPreview: undefined, }; } @@ -84,5 +85,6 @@ export function appendLayer({ ...state.visualization, state: activeVisualization.appendLayer(state.visualization.state, layerId), }, + stagedPreview: undefined, }; } From cf9b64eada5b0809dab7e69bfd356ba30e57755f Mon Sep 17 00:00:00 2001 From: Steph Milovic Date: Fri, 20 Mar 2020 15:14:09 -0600 Subject: [PATCH 14/31] [SIEM] [Cases] Create case from timeline (#60711) --- .../insert_timeline_popover/index.test.tsx | 60 +++++++++++++++++++ .../insert_timeline_popover/index.tsx | 33 +++++++++- .../timeline/properties/helpers.tsx | 37 ++++++++++++ .../components/timeline/properties/index.tsx | 1 + .../timeline/properties/properties_right.tsx | 12 +++- .../timeline/properties/translations.ts | 11 +++- .../components/timeline/timeline.test.tsx | 2 +- .../case/components/case_view/index.test.tsx | 11 ++++ .../pages/case/components/user_list/index.tsx | 2 +- 9 files changed, 162 insertions(+), 7 deletions(-) create mode 100644 x-pack/legacy/plugins/siem/public/components/timeline/insert_timeline_popover/index.test.tsx diff --git a/x-pack/legacy/plugins/siem/public/components/timeline/insert_timeline_popover/index.test.tsx b/x-pack/legacy/plugins/siem/public/components/timeline/insert_timeline_popover/index.test.tsx new file mode 100644 index 0000000000000..adac26a8ac92b --- /dev/null +++ b/x-pack/legacy/plugins/siem/public/components/timeline/insert_timeline_popover/index.test.tsx @@ -0,0 +1,60 @@ +/* + * 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. + */ + +import React from 'react'; +import { mount } from 'enzyme'; +/* eslint-disable @kbn/eslint/module_migration */ +import routeData from 'react-router'; +/* eslint-enable @kbn/eslint/module_migration */ +import { InsertTimelinePopoverComponent } from './'; + +const mockDispatch = jest.fn(); +jest.mock('react-redux', () => ({ + useDispatch: () => mockDispatch, +})); +const mockLocation = { + pathname: '/apath', + hash: '', + search: '', + state: '', +}; +const mockLocationWithState = { + ...mockLocation, + state: { + insertTimeline: { + timelineId: 'timeline-id', + timelineTitle: 'Timeline title', + }, + }, +}; + +const onTimelineChange = jest.fn(); +const defaultProps = { + isDisabled: false, + onTimelineChange, +}; + +describe('Insert timeline popover ', () => { + beforeEach(() => { + jest.resetAllMocks(); + }); + + it('should insert a timeline when passed in the router state', () => { + jest.spyOn(routeData, 'useLocation').mockReturnValue(mockLocationWithState); + mount(); + expect(mockDispatch).toBeCalledWith({ + payload: { id: 'timeline-id', show: false }, + type: 'x-pack/siem/local/timeline/SHOW_TIMELINE', + }); + expect(onTimelineChange).toBeCalledWith('Timeline title', 'timeline-id'); + }); + it('should do nothing when router state', () => { + jest.spyOn(routeData, 'useLocation').mockReturnValue(mockLocation); + mount(); + expect(mockDispatch).toHaveBeenCalledTimes(0); + expect(onTimelineChange).toHaveBeenCalledTimes(0); + }); +}); diff --git a/x-pack/legacy/plugins/siem/public/components/timeline/insert_timeline_popover/index.tsx b/x-pack/legacy/plugins/siem/public/components/timeline/insert_timeline_popover/index.tsx index 84bd8c1f302c3..fa474c4d601ad 100644 --- a/x-pack/legacy/plugins/siem/public/components/timeline/insert_timeline_popover/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/timeline/insert_timeline_popover/index.tsx @@ -5,11 +5,14 @@ */ import { EuiButtonIcon, EuiPopover, EuiSelectableOption } from '@elastic/eui'; -import React, { memo, useCallback, useMemo, useState } from 'react'; +import React, { memo, useCallback, useEffect, useMemo, useState } from 'react'; +import { useLocation } from 'react-router-dom'; +import { useDispatch } from 'react-redux'; import { OpenTimelineResult } from '../../open_timeline/types'; import { SelectableTimeline } from '../selectable_timeline'; import * as i18n from '../translations'; +import { timelineActions } from '../../../store/timeline'; interface InsertTimelinePopoverProps { isDisabled: boolean; @@ -17,12 +20,37 @@ interface InsertTimelinePopoverProps { onTimelineChange: (timelineTitle: string, timelineId: string | null) => void; } -const InsertTimelinePopoverComponent: React.FC = ({ +interface RouterState { + insertTimeline: { + timelineId: string; + timelineTitle: string; + }; +} + +type Props = InsertTimelinePopoverProps; + +export const InsertTimelinePopoverComponent: React.FC = ({ isDisabled, hideUntitled = false, onTimelineChange, }) => { + const dispatch = useDispatch(); const [isPopoverOpen, setIsPopoverOpen] = useState(false); + const { state } = useLocation(); + const [routerState, setRouterState] = useState(state ?? null); + + useEffect(() => { + if (routerState && routerState.insertTimeline) { + dispatch( + timelineActions.showTimeline({ id: routerState.insertTimeline.timelineId, show: false }) + ); + onTimelineChange( + routerState.insertTimeline.timelineTitle, + routerState.insertTimeline.timelineId + ); + setRouterState(null); + } + }, [routerState]); const handleClosePopover = useCallback(() => { setIsPopoverOpen(false); @@ -65,6 +93,7 @@ const InsertTimelinePopoverComponent: React.FC = ({ return ( (({ timelineId, title, updateTitle }) = )); Name.displayName = 'Name'; +interface NewCaseProps { + onClosePopover: () => void; + timelineId: string; + timelineTitle: string; +} + +export const NewCase = React.memo(({ onClosePopover, timelineId, timelineTitle }) => { + const history = useHistory(); + const handleClick = useCallback(() => { + onClosePopover(); + history.push({ + pathname: `/${SiemPageName.case}/create`, + state: { + insertTimeline: { + timelineId, + timelineTitle: timelineTitle.length > 0 ? timelineTitle : i18n.UNTITLED_TIMELINE, + }, + }, + }); + }, [onClosePopover, history, timelineId, timelineTitle]); + + return ( + + {i18n.ATTACH_TIMELINE_TO_NEW_CASE} + + ); +}); +NewCase.displayName = 'NewCase'; + interface NewTimelineProps { createTimeline: CreateTimeline; onClosePopover: () => void; diff --git a/x-pack/legacy/plugins/siem/public/components/timeline/properties/index.tsx b/x-pack/legacy/plugins/siem/public/components/timeline/properties/index.tsx index 8549784b8ecd6..0080fcb1e6924 100644 --- a/x-pack/legacy/plugins/siem/public/components/timeline/properties/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/timeline/properties/index.tsx @@ -141,6 +141,7 @@ export const Properties = React.memo( showTimelineModal={showTimelineModal} showUsersView={title.length > 0} timelineId={timelineId} + title={title} updateDescription={updateDescription} updateNote={updateNote} usersViewing={usersViewing} diff --git a/x-pack/legacy/plugins/siem/public/components/timeline/properties/properties_right.tsx b/x-pack/legacy/plugins/siem/public/components/timeline/properties/properties_right.tsx index b21ab5063441e..59d268487cca7 100644 --- a/x-pack/legacy/plugins/siem/public/components/timeline/properties/properties_right.tsx +++ b/x-pack/legacy/plugins/siem/public/components/timeline/properties/properties_right.tsx @@ -14,7 +14,7 @@ import { EuiToolTip, EuiAvatar, } from '@elastic/eui'; -import { NewTimeline, Description, NotesButton } from './helpers'; +import { NewTimeline, Description, NotesButton, NewCase } from './helpers'; import { OpenTimelineModalButton } from '../../open_timeline/open_timeline_modal/open_timeline_modal_button'; import { OpenTimelineModal } from '../../open_timeline/open_timeline_modal'; import { InspectButton, InspectButtonContainer } from '../../inspect'; @@ -79,6 +79,7 @@ interface Props { onCloseTimelineModal: () => void; onOpenTimelineModal: () => void; showTimelineModal: boolean; + title: string; updateNote: UpdateNote; } @@ -104,6 +105,7 @@ const PropertiesRightComponent: React.FC = ({ showTimelineModal, onCloseTimelineModal, onOpenTimelineModal, + title, }) => ( @@ -135,6 +137,14 @@ const PropertiesRightComponent: React.FC = ({ + + + + { .find('[data-test-subj="timeline-title"]') .first() .props().placeholder - ).toContain('Untitled Timeline'); + ).toContain('Untitled timeline'); }); test('it renders the timeline table', () => { diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/case_view/index.test.tsx b/x-pack/legacy/plugins/siem/public/pages/case/components/case_view/index.test.tsx index 41100ec6d50f1..3f4a83d1bff33 100644 --- a/x-pack/legacy/plugins/siem/public/pages/case/components/case_view/index.test.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/case/components/case_view/index.test.tsx @@ -7,6 +7,9 @@ import React from 'react'; import { Router } from 'react-router-dom'; import { mount } from 'enzyme'; +/* eslint-disable @kbn/eslint/module_migration */ +import routeData from 'react-router'; +/* eslint-enable @kbn/eslint/module_migration */ import { CaseComponent } from './'; import { caseProps, caseClosedProps, data, dataClosed } from './__mock__'; import { TestProviders } from '../../../../mock'; @@ -35,6 +38,13 @@ const mockHistory = { listen: jest.fn(), }; +const mockLocation = { + pathname: '/welcome', + hash: '', + search: '', + state: '', +}; + describe('CaseView ', () => { const updateCaseProperty = jest.fn(); /* eslint-disable no-console */ @@ -59,6 +69,7 @@ describe('CaseView ', () => { beforeEach(() => { jest.resetAllMocks(); useUpdateCaseMock.mockImplementation(() => defaultUpdateCaseState); + jest.spyOn(routeData, 'useLocation').mockReturnValue(mockLocation); }); it('should render CaseComponent', () => { diff --git a/x-pack/legacy/plugins/siem/public/pages/case/components/user_list/index.tsx b/x-pack/legacy/plugins/siem/public/pages/case/components/user_list/index.tsx index 74a1b98c29eef..9ace36eea1e9e 100644 --- a/x-pack/legacy/plugins/siem/public/pages/case/components/user_list/index.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/case/components/user_list/index.tsx @@ -58,7 +58,7 @@ const renderUsers = ( From fda31966113068ee57faf2e85a47d1e22aeb4470 Mon Sep 17 00:00:00 2001 From: Kaarina Tungseth Date: Fri, 20 Mar 2020 16:33:20 -0500 Subject: [PATCH 15/31] [DOCS] Updates API requests and examples (#60695) * [DOCS] Updates API requests and examples * Review comments --- docs/api/dashboard/export-dashboard.asciidoc | 12 +- docs/api/dashboard/import-dashboard.asciidoc | 6 +- docs/api/features.asciidoc | 4 +- ...logstash-configuration-management.asciidoc | 6 +- .../create-logstash.asciidoc | 6 +- .../delete-pipeline.asciidoc | 7 +- .../list-pipeline.asciidoc | 6 +- .../retrieve-pipeline.asciidoc | 8 +- docs/api/role-management.asciidoc | 4 +- docs/api/role-management/delete.asciidoc | 13 +- docs/api/role-management/get-all.asciidoc | 16 +- docs/api/role-management/get.asciidoc | 14 +- docs/api/role-management/put.asciidoc | 44 ++-- docs/api/saved-objects/bulk_create.asciidoc | 10 +- docs/api/saved-objects/bulk_get.asciidoc | 10 +- docs/api/saved-objects/create.asciidoc | 12 +- docs/api/saved-objects/delete.asciidoc | 12 +- docs/api/saved-objects/export.asciidoc | 22 +- docs/api/saved-objects/find.asciidoc | 14 +- docs/api/saved-objects/get.asciidoc | 18 +- docs/api/saved-objects/import.asciidoc | 25 +- .../resolve_import_errors.asciidoc | 25 +- docs/api/saved-objects/update.asciidoc | 10 +- .../copy_saved_objects.asciidoc | 220 +++--------------- docs/api/spaces-management/delete.asciidoc | 12 +- docs/api/spaces-management/get.asciidoc | 10 +- docs/api/spaces-management/get_all.asciidoc | 8 +- docs/api/spaces-management/post.asciidoc | 16 +- docs/api/spaces-management/put.asciidoc | 26 +-- ...olve_copy_saved_objects_conflicts.asciidoc | 213 +++-------------- docs/api/upgrade-assistant.asciidoc | 4 +- .../upgrade-assistant/cancel_reindex.asciidoc | 6 +- .../check_reindex_status.asciidoc | 63 +++-- .../api/upgrade-assistant/reindexing.asciidoc | 18 +- docs/api/upgrade-assistant/status.asciidoc | 6 +- docs/api/url-shortening.asciidoc | 16 +- docs/api/using-api.asciidoc | 5 +- 37 files changed, 308 insertions(+), 619 deletions(-) diff --git a/docs/api/dashboard/export-dashboard.asciidoc b/docs/api/dashboard/export-dashboard.asciidoc index 7858b69d44c79..36c551dee84fc 100644 --- a/docs/api/dashboard/export-dashboard.asciidoc +++ b/docs/api/dashboard/export-dashboard.asciidoc @@ -9,7 +9,7 @@ experimental[] Export dashboards and corresponding saved objects. [[dashboard-api-export-request]] ==== Request -`GET /api/kibana/dashboards/export` +`GET :/api/kibana/dashboards/export` [[dashboard-api-export-params]] ==== Query parameters @@ -20,9 +20,9 @@ experimental[] Export dashboards and corresponding saved objects. [[dashboard-api-export-response-body]] ==== Response body -`objects`:: +`objects`:: (array) A top level property that includes the saved objects. The order of the objects is not guaranteed. Use the exact response body as the request body for the corresponding <>. - + [[dashboard-api-export-codes]] ==== Response code @@ -33,10 +33,10 @@ experimental[] Export dashboards and corresponding saved objects. [[dashboard-api-export-example]] ==== Example -[source,js] +[source,sh] -------------------------------------------------- -GET api/kibana/dashboards/export?dashboard=942dcef0-b2cd-11e8-ad8e-85441f0c2e5c <1> +$ curl -X GET "localhost:5601/api/kibana/dashboards/export?dashboard=942dcef0-b2cd-11e8-ad8e-85441f0c2e5c" <1> -------------------------------------------------- // KIBANA -<1> The dashboard ID is `942dcef0-b2cd-11e8-ad8e-85441f0c2e5c`. \ No newline at end of file +<1> The dashboard ID is `942dcef0-b2cd-11e8-ad8e-85441f0c2e5c`. diff --git a/docs/api/dashboard/import-dashboard.asciidoc b/docs/api/dashboard/import-dashboard.asciidoc index 14817719ec7ee..320859f78c617 100644 --- a/docs/api/dashboard/import-dashboard.asciidoc +++ b/docs/api/dashboard/import-dashboard.asciidoc @@ -9,7 +9,7 @@ experimental[] Import dashboards and corresponding saved objects. [[dashboard-api-import-request]] ==== Request -`POST /api/kibana/dashboards/import` +`POST :/api/kibana/dashboards/import` [[dashboard-api-import-params]] ==== Query parameters @@ -40,9 +40,9 @@ Use the complete response body from the <:/api/features` [float] [[features-api-get-codes]] @@ -23,7 +23,7 @@ experimental[] Retrieves all {kib} features. Features are used by spaces and sec The API returns the following: -[source,js] +[source,sh] -------------------------------------------------- { "id": "discover", diff --git a/docs/api/logstash-configuration-management.asciidoc b/docs/api/logstash-configuration-management.asciidoc index fbb45095c214b..621b6c61dad8a 100644 --- a/docs/api/logstash-configuration-management.asciidoc +++ b/docs/api/logstash-configuration-management.asciidoc @@ -2,9 +2,9 @@ [[logstash-configuration-management-api]] == Logstash configuration management APIs -Programmatically integrate with the Logstash configuration management feature. +Programmatically integrate with Logstash configuration management. -WARNING: Do not directly access the `.logstash` index. The structure of the `.logstash` index is subject to change, which could cause your integration to break. Instead, use the Logstash configuration management APIs. +WARNING: Do not directly access the `.logstash` index. The structure of the `.logstash` index is subject to change, which could cause your integration to break. Instead, use the Logstash configuration management APIs. The following Logstash configuration management APIs are available: @@ -20,5 +20,3 @@ include::logstash-configuration-management/delete-pipeline.asciidoc[] include::logstash-configuration-management/list-pipeline.asciidoc[] include::logstash-configuration-management/create-logstash.asciidoc[] include::logstash-configuration-management/retrieve-pipeline.asciidoc[] - - diff --git a/docs/api/logstash-configuration-management/create-logstash.asciidoc b/docs/api/logstash-configuration-management/create-logstash.asciidoc index 38e0ee12a0ebf..d6ad27fe44603 100644 --- a/docs/api/logstash-configuration-management/create-logstash.asciidoc +++ b/docs/api/logstash-configuration-management/create-logstash.asciidoc @@ -9,7 +9,7 @@ experimental[] Create a centrally-managed Logstash pipeline, or update an existi [[logstash-configuration-management-api-create-request]] ==== Request -`PUT /api/logstash/pipeline/` +`PUT :/api/logstash/pipeline/` [[logstash-configuration-management-api-create-params]] ==== Path parameters @@ -39,9 +39,9 @@ experimental[] Create a centrally-managed Logstash pipeline, or update an existi [[logstash-configuration-management-api-create-example]] ==== Example -[source,js] +[source,sh] -------------------------------------------------- -PUT api/logstash/pipeline/hello-world +$ curl -X PUT "localhost:5601/api/logstash/pipeline/hello-world" { "pipeline": "input { stdin {} } output { stdout {} }", "settings": { diff --git a/docs/api/logstash-configuration-management/delete-pipeline.asciidoc b/docs/api/logstash-configuration-management/delete-pipeline.asciidoc index 15d44034b46fe..e982619ee17f4 100644 --- a/docs/api/logstash-configuration-management/delete-pipeline.asciidoc +++ b/docs/api/logstash-configuration-management/delete-pipeline.asciidoc @@ -9,7 +9,7 @@ experimental[] Delete a centrally-managed Logstash pipeline. [[logstash-configuration-management-api-delete-request]] ==== Request -`DELETE /api/logstash/pipeline/` +`DELETE :/api/logstash/pipeline/` [[logstash-configuration-management-api-delete-params]] ==== Path parameters @@ -26,9 +26,8 @@ experimental[] Delete a centrally-managed Logstash pipeline. [[logstash-configuration-management-api-delete-example]] ==== Example -[source,js] +[source,sh] -------------------------------------------------- -DELETE api/logstash/pipeline/hello-world +$ curl -X DELETE "localhost:5601/api/logstash/pipeline/hello-world" -------------------------------------------------- // KIBANA - diff --git a/docs/api/logstash-configuration-management/list-pipeline.asciidoc b/docs/api/logstash-configuration-management/list-pipeline.asciidoc index 7140c35d89853..d875ea3d95b78 100644 --- a/docs/api/logstash-configuration-management/list-pipeline.asciidoc +++ b/docs/api/logstash-configuration-management/list-pipeline.asciidoc @@ -9,14 +9,14 @@ experimental[] List all centrally-managed Logstash pipelines. [[logstash-configuration-management-api-list-request]] ==== Request -`GET /api/logstash/pipelines` +`GET :/api/logstash/pipelines` [[logstash-configuration-management-api-list-example]] ==== Example The API returns the following: -[source,js] +[source,sh] -------------------------------------------------- { "pipelines": [ @@ -35,4 +35,4 @@ The API returns the following: } -------------------------------------------------- -<1> The `username` property appears when security is enabled, and depends on when the pipeline was created or last updated. \ No newline at end of file +<1> The `username` property appears when security is enabled, and depends on when the pipeline was created or last updated. diff --git a/docs/api/logstash-configuration-management/retrieve-pipeline.asciidoc b/docs/api/logstash-configuration-management/retrieve-pipeline.asciidoc index 93a1ec3aa1da5..1eb380b71c62a 100644 --- a/docs/api/logstash-configuration-management/retrieve-pipeline.asciidoc +++ b/docs/api/logstash-configuration-management/retrieve-pipeline.asciidoc @@ -9,20 +9,20 @@ experimental[] Retrieve a centrally-managed Logstash pipeline. [[logstash-configuration-management-api-retrieve-request]] ==== Request -`GET /api/logstash/pipeline/` +`GET :/api/logstash/pipeline/` [[logstash-configuration-management-api-retrieve-path-params]] ==== Path parameters `id`:: (Required, string) The pipeline ID. - + [[logstash-configuration-management-api-retrieve-example]] ==== Example The API returns the following: -[source,js] +[source,sh] -------------------------------------------------- { "id": "hello-world", @@ -33,4 +33,4 @@ The API returns the following: "queue.type": "persistent" } } --------------------------------------------------- \ No newline at end of file +-------------------------------------------------- diff --git a/docs/api/role-management.asciidoc b/docs/api/role-management.asciidoc index 482d1a9b3cdd3..4c4620a23943a 100644 --- a/docs/api/role-management.asciidoc +++ b/docs/api/role-management.asciidoc @@ -2,9 +2,9 @@ [[role-management-api]] == {kib} role management APIs -Manage the roles that grant <>. +Manage the roles that grant <>. -WARNING: Do not use the {ref}/security-api.html#security-role-apis[{es} role management APIs] to manage {kib} roles. +WARNING: Do not use the {ref}/security-api.html#security-role-apis[{es} role management APIs] to manage {kib} roles. The following {kib} role management APIs are available: diff --git a/docs/api/role-management/delete.asciidoc b/docs/api/role-management/delete.asciidoc index acf2e4a3e3f1f..530e1e252ef8f 100644 --- a/docs/api/role-management/delete.asciidoc +++ b/docs/api/role-management/delete.asciidoc @@ -4,26 +4,23 @@ Delete role ++++ -Delete a {kib} role. - -experimental["The underlying mechanism of enforcing role-based access control is stable, but the APIs for managing the roles are experimental."] +experimental[] Delete a {kib} role. [[role-management-api-delete-prereqs]] -==== Prerequisite +==== Prerequisite To use the delete role API, you must have the `manage_security` cluster privilege. [[role-management-api-delete-request-body]] ==== Request -`DELETE /api/security/role/my_admin_role` +`DELETE :/api/security/role/my_admin_role` [[role-management-api-delete-response-codes]] ==== Response codes `204`:: Indicates a successful call. - + `404`:: - Indicates an unsuccessful call. - \ No newline at end of file + Indicates an unsuccessful call. diff --git a/docs/api/role-management/get-all.asciidoc b/docs/api/role-management/get-all.asciidoc index 4a3dbd7734d3a..888bf0c8a137c 100644 --- a/docs/api/role-management/get-all.asciidoc +++ b/docs/api/role-management/get-all.asciidoc @@ -4,32 +4,30 @@ Get all roles ++++ -Retrieve all {kib} roles. - -experimental["The underlying mechanism of enforcing role-based access control is stable, but the APIs for managing the roles are experimental."] +experimental[] Retrieve all {kib} roles. [[role-management-api-get-prereqs]] -==== Prerequisite +==== Prerequisite To use the get role API, you must have the `manage_security` cluster privilege. [[role-management-api-retrieve-all-request-body]] ==== Request -`GET /api/security/role` +`GET :/api/security/role` [[role-management-api-retrieve-all-response-codes]] ==== Response code -`200`:: +`200`:: Indicates a successful call. - + [[role-management-api-retrieve-all-example]] ==== Example The API returns the following: -[source,js] +[source,sh] -------------------------------------------------- [ { @@ -77,4 +75,4 @@ The API returns the following: "kibana": [ ] } ] --------------------------------------------------- \ No newline at end of file +-------------------------------------------------- diff --git a/docs/api/role-management/get.asciidoc b/docs/api/role-management/get.asciidoc index 44423b01abe5b..d1e9d1e6afa83 100644 --- a/docs/api/role-management/get.asciidoc +++ b/docs/api/role-management/get.asciidoc @@ -4,32 +4,30 @@ Get specific role ++++ -Retrieve a specific role. - -experimental["The underlying mechanism of enforcing role-based access control is stable, but the APIs for managing the roles are experimental."] +experimental[] Retrieve a specific role. [[role-management-specific-api-get-prereqs]] -==== Prerequisite +==== Prerequisite To use the get specific role API, you must have the `manage_security` cluster privilege. [[role-management-specific-api-retrieve-all-request-body]] ===== Request -`GET /api/security/role/my_restricted_kibana_role` +`GET :/api/security/role/my_restricted_kibana_role` [[role-management-specific-api-retrieve-all-response-codes]] ==== Response code -`200`:: +`200`:: Indicates a successful call. - + [[role-management-specific-api-retrieve-all-example]] ===== Example The API returns the following: -[source,js] +[source,sh] -------------------------------------------------- { "name": "my_restricted_kibana_role", diff --git a/docs/api/role-management/put.asciidoc b/docs/api/role-management/put.asciidoc index a00fedf7e7ac4..59e6bc8d37eec 100644 --- a/docs/api/role-management/put.asciidoc +++ b/docs/api/role-management/put.asciidoc @@ -4,15 +4,13 @@ Create or update role ++++ -Create a new {kib} role, or update the attributes of an existing role. {kib} roles are stored in the +experimental[] Create a new {kib} role, or update the attributes of an existing role. {kib} roles are stored in the {es} native realm. -experimental["The underlying mechanism of enforcing role-based access control is stable, but the APIs for managing the roles are experimental."] - [[role-management-api-put-request]] ==== Request -`PUT /api/security/role/my_kibana_role` +`PUT :/api/security/role/my_kibana_role` [[role-management-api-put-prereqs]] ==== Prerequisite @@ -22,45 +20,45 @@ To use the create or update role API, you must have the `manage_security` cluste [[role-management-api-response-body]] ==== Request body -`metadata`:: +`metadata`:: (Optional, object) In the `metadata` object, keys that begin with `_` are reserved for system usage. -`elasticsearch`:: - (Optional, object) {es} cluster and index privileges. Valid keys include +`elasticsearch`:: + (Optional, object) {es} cluster and index privileges. Valid keys include `cluster`, `indices`, and `run_as`. For more information, see {ref}/defining-roles.html[Defining roles]. -`kibana`:: +`kibana`:: (list) Objects that specify the <> for the role: -`base` ::: +`base` ::: (Optional, list) A base privilege. When specified, the base must be `["all"]` or `["read"]`. When the `base` privilege is specified, you are unable to use the `feature` section. "all" grants read/write access to all {kib} features for the specified spaces. "read" grants read-only access to all {kib} features for the specified spaces. -`feature` ::: +`feature` ::: (object) Contains privileges for specific features. When the `feature` privileges are specified, you are unable to use the `base` section. To retrieve a list of available features, use the <>. -`spaces` ::: +`spaces` ::: (list) The spaces to apply the privileges to. To grant access to all spaces, set to `["*"]`, or omit the value. [[role-management-api-put-response-codes]] ==== Response code -`204`:: +`204`:: Indicates a successful call. ===== Examples Grant access to various features in all spaces: -[source,js] +[source,sh] -------------------------------------------------- -PUT /api/security/role/my_kibana_role +$ curl -X PUT "localhost:5601/api/security/role/my_kibana_role" { "metadata" : { "version" : 1 @@ -127,9 +125,9 @@ PUT /api/security/role/my_kibana_role Grant dashboard-only access to only the Marketing space: -[source,js] +[source,sh] -------------------------------------------------- -PUT /api/security/role/my_kibana_role +$ curl -X PUT "localhost:5601/api/security/role/my_kibana_role" { "metadata" : { "version" : 1 @@ -155,9 +153,9 @@ PUT /api/security/role/my_kibana_role Grant full access to all features in the Default space: -[source,js] +[source,sh] -------------------------------------------------- -PUT /api/security/role/my_kibana_role +$ curl -X PUT "localhost:5601/api/security/role/my_kibana_role" { "metadata" : { "version" : 1 @@ -182,9 +180,9 @@ PUT /api/security/role/my_kibana_role Grant different access to different spaces: -[source,js] +[source,sh] -------------------------------------------------- -PUT /api/security/role/my_kibana_role +$ curl -X PUT "localhost:5601/api/security/role/my_kibana_role" { "metadata" : { "version" : 1 @@ -216,11 +214,11 @@ PUT /api/security/role/my_kibana_role -------------------------------------------------- // KIBANA -Grant access to {kib} and Elasticsearch: +Grant access to {kib} and {es}: -[source,js] +[source,sh] -------------------------------------------------- -PUT /api/security/role/my_kibana_role +$ curl -X PUT "localhost:5601/api/security/role/my_kibana_role" { "metadata" : { "version" : 1 diff --git a/docs/api/saved-objects/bulk_create.asciidoc b/docs/api/saved-objects/bulk_create.asciidoc index d649684bc30f2..9daba224b317c 100644 --- a/docs/api/saved-objects/bulk_create.asciidoc +++ b/docs/api/saved-objects/bulk_create.asciidoc @@ -9,9 +9,9 @@ experimental[] Create multiple {kib} saved objects. [[saved-objects-api-bulk-create-request]] ==== Request -`POST /api/saved_objects/_bulk_create` +`POST :/api/saved_objects/_bulk_create` -`POST /s//api/saved_objects/_bulk_create` +`POST :/s//api/saved_objects/_bulk_create` [[saved-objects-api-bulk-create-path-params]] @@ -63,9 +63,9 @@ Saved objects that are unable to persist are replaced with an error object. Create an index pattern with the `my-pattern` ID, and a dashboard with the `my-dashboard` ID: -[source,js] +[source,sh] -------------------------------------------------- -POST api/saved_objects/_bulk_create +$ curl -X POST "localhost:5601/api/saved_objects/_bulk_create" [ { "type": "index-pattern", @@ -87,7 +87,7 @@ POST api/saved_objects/_bulk_create The API returns the following: -[source,js] +[source,sh] -------------------------------------------------- { "saved_objects": [ diff --git a/docs/api/saved-objects/bulk_get.asciidoc b/docs/api/saved-objects/bulk_get.asciidoc index 3ef5823716d79..a6fdeb69ba925 100644 --- a/docs/api/saved-objects/bulk_get.asciidoc +++ b/docs/api/saved-objects/bulk_get.asciidoc @@ -9,9 +9,9 @@ experimental[] Retrieve multiple {kib} saved objects by ID. [[saved-objects-api-bulk-get-request]] ==== Request -`POST /api/saved_objects/_bulk_get` +`POST :/api/saved_objects/_bulk_get` -`POST /s//api/saved_objects/_bulk_get` +`POST :/s//api/saved_objects/_bulk_get` [[saved-objects-api-bulk-get-path-params]] ==== Path parameters @@ -50,9 +50,9 @@ Saved objects that are unable to persist are replaced with an error object. Retrieve an index pattern with the `my-pattern` ID, and a dashboard with the `my-dashboard` ID: -[source,js] +[source,sh] -------------------------------------------------- -POST api/saved_objects/_bulk_get +$ curl -X POST "localhost:5601/api/saved_objects/_bulk_get" [ { "type": "index-pattern", @@ -68,7 +68,7 @@ POST api/saved_objects/_bulk_get The API returns the following: -[source,js] +[source,sh] -------------------------------------------------- { "saved_objects": [ diff --git a/docs/api/saved-objects/create.asciidoc b/docs/api/saved-objects/create.asciidoc index 634c71bb4eefe..dc010c80fd012 100644 --- a/docs/api/saved-objects/create.asciidoc +++ b/docs/api/saved-objects/create.asciidoc @@ -9,11 +9,11 @@ experimental[] Create {kib} saved objects. [[saved-objects-api-create-request]] ==== Request -`POST /api/saved_objects/` + +`POST :/api/saved_objects/` + -`POST /api/saved_objects//` +`POST :/api/saved_objects//` -`POST /s//saved_objects/` +`POST :/s//saved_objects/` [[saved-objects-api-create-path-params]] ==== Path parameters @@ -55,9 +55,9 @@ any data that you send to the API is properly formed. [[saved-objects-api-create-example]] ==== Example -[source,js] +[source,sh] -------------------------------------------------- -POST api/saved_objects/index-pattern/my-pattern +$ curl -X POST "localhost:5601/api/saved_objects/index-pattern/my-pattern" { "attributes": { "title": "my-pattern-*" @@ -68,7 +68,7 @@ POST api/saved_objects/index-pattern/my-pattern The API returns the following: -[source,js] +[source,sh] -------------------------------------------------- { "id": "my-pattern", <1> diff --git a/docs/api/saved-objects/delete.asciidoc b/docs/api/saved-objects/delete.asciidoc index c34f9b67dfd22..65c955e15d360 100644 --- a/docs/api/saved-objects/delete.asciidoc +++ b/docs/api/saved-objects/delete.asciidoc @@ -4,16 +4,16 @@ Delete object ++++ -experimental[] Remove {kib} saved objects. +experimental[] Remove {kib} saved objects. WARNING: Once you delete a saved object, _it cannot be recovered_. [[saved-objects-api-delete-request]] ==== Request -`DELETE /api/saved_objects//` +`DELETE :/api/saved_objects//` -`DELETE /s//api/saved_objects//` +`DELETE :/s//api/saved_objects//` [[saved-objects-api-delete-path-params]] ==== Path parameters @@ -33,12 +33,12 @@ WARNING: Once you delete a saved object, _it cannot be recovered_. `200`:: Indicates a successful call. -==== Examples +==== Example Delete an index pattern object with the `my-pattern` ID: -[source,js] +[source,sh] -------------------------------------------------- -DELETE api/saved_objects/index-pattern/my-pattern +$ curl -X DELETE "localhost:5601/api/saved_objects/index-pattern/my-pattern" -------------------------------------------------- // KIBANA diff --git a/docs/api/saved-objects/export.asciidoc b/docs/api/saved-objects/export.asciidoc index 1b4f50dda2ddb..e8c762b9543a1 100644 --- a/docs/api/saved-objects/export.asciidoc +++ b/docs/api/saved-objects/export.asciidoc @@ -9,9 +9,9 @@ experimental[] Retrieve sets of saved objects that you want to import into {kib} [[saved-objects-api-export-request]] ==== Request -`POST /api/saved_objects/_export` +`POST :/api/saved_objects/_export` -`POST /s//api/saved_objects/_export` +`POST :/s//api/saved_objects/_export` [[saved-objects-api-export-path-params]] ==== Path parameters @@ -39,7 +39,7 @@ TIP: You must include `type` or `objects` in the request body. [[saved-objects-api-export-request-response-body]] ==== Response body -The format of the response body is newline delimited JSON. Each exported object is exported as a valid JSON record and separated by the newline character '\n'. +The format of the response body is newline delimited JSON. Each exported object is exported as a valid JSON record and separated by the newline character '\n'. When `excludeExportDetails=false` (the default) we append an export result details record at the end of the file after all the saved object records. The export result details object has the following format: @@ -66,9 +66,9 @@ When `excludeExportDetails=false` (the default) we append an export result detai Export all index pattern saved objects: -[source,js] +[source,sh] -------------------------------------------------- -POST api/saved_objects/_export +$ curl -X POST "localhost:5601/api/saved_objects/_export" { "type": "index-pattern" } @@ -77,9 +77,9 @@ POST api/saved_objects/_export Export all index pattern saved objects and exclude the export summary from the stream: -[source,js] +[source,sh] -------------------------------------------------- -POST api/saved_objects/_export +$ curl -X POST "localhost:5601/api/saved_objects/_export" { "type": "index-pattern", "excludeExportDetails": true @@ -89,9 +89,9 @@ POST api/saved_objects/_export Export a specific saved object: -[source,js] +[source,sh] -------------------------------------------------- -POST api/saved_objects/_export +$ curl -X POST "localhost:5601/api/saved_objects/_export" { "objects": [ { @@ -105,9 +105,9 @@ POST api/saved_objects/_export Export a specific saved object and it's related objects : -[source,js] +[source,sh] -------------------------------------------------- -POST api/saved_objects/_export +$ curl -X POST "localhost:5601/api/saved_objects/_export" { "objects": [ { diff --git a/docs/api/saved-objects/find.asciidoc b/docs/api/saved-objects/find.asciidoc index 955c50922fde7..93e60be5d4923 100644 --- a/docs/api/saved-objects/find.asciidoc +++ b/docs/api/saved-objects/find.asciidoc @@ -9,9 +9,9 @@ experimental[] Retrieve a paginated set of {kib} saved objects by various condit [[saved-objects-api-find-request]] ==== Request -`GET /api/saved_objects/_find` +`GET :/api/saved_objects/_find` -`GET /s//api/saved_objects/_find` +`GET :/s//api/saved_objects/_find` [[saved-objects-api-find-path-params]] ==== Path parameters @@ -67,15 +67,15 @@ change. Use the find API for traditional paginated results, but avoid using it t Find index patterns with titles that start with `my`: -[source,js] +[source,sh] -------------------------------------------------- -GET api/saved_objects/_find?type=index-pattern&search_fields=title&search=my* +$ curl -X GET "localhost:5601/api/saved_objects/_find?type=index-pattern&search_fields=title&search=my*" -------------------------------------------------- // KIBANA The API returns the following: -[source,js] +[source,sh] -------------------------------------------------- { "total": 1, @@ -95,8 +95,8 @@ The API returns the following: For parameters that accept multiple values (e.g. `fields`), repeat the query parameter for each value: -[source,js] +[source,sh] -------------------------------------------------- -GET api/saved_objects/_find?fields=id&fields=title +$ curl -X GET "localhost:5601/api/saved_objects/_find?fields=id&fields=title" -------------------------------------------------- // KIBANA diff --git a/docs/api/saved-objects/get.asciidoc b/docs/api/saved-objects/get.asciidoc index 29f8ef67e0a83..86b86795b534f 100644 --- a/docs/api/saved-objects/get.asciidoc +++ b/docs/api/saved-objects/get.asciidoc @@ -9,9 +9,9 @@ experimental[] Retrieve a single {kib} saved object by ID. [[saved-objects-api-get-request]] ==== Request -`GET /api/saved_objects//` +`GET :/api/saved_objects//` -`GET /s//api/saved_objects//` +`GET :/s//api/saved_objects//` [[saved-objects-api-get-params]] ==== Path parameters @@ -37,15 +37,15 @@ experimental[] Retrieve a single {kib} saved object by ID. Retrieve the index pattern object with the `my-pattern` ID: -[source,js] +[source,sh] -------------------------------------------------- -GET api/saved_objects/index-pattern/my-pattern +$ curl -X GET "localhost:5601/api/saved_objects/index-pattern/my-pattern" -------------------------------------------------- // KIBANA The API returns the following: -[source,js] +[source,sh] -------------------------------------------------- { "id": "my-pattern", @@ -57,17 +57,17 @@ The API returns the following: } -------------------------------------------------- -The following example retrieves a dashboard object in the `testspace` by id. +Retrieve a dashboard object in the `testspace` by ID: -[source,js] +[source,sh] -------------------------------------------------- -GET /s/testspace/api/saved_objects/dashboard/7adfa750-4c81-11e8-b3d7-01146121b73d +$ curl -X GET "localhost:5601/s/testspace/api/saved_objects/dashboard/7adfa750-4c81-11e8-b3d7-01146121b73d" -------------------------------------------------- // KIBANA The API returns the following: -[source,js] +[source,sh] -------------------------------------------------- { "id": "7adfa750-4c81-11e8-b3d7-01146121b73d", diff --git a/docs/api/saved-objects/import.asciidoc b/docs/api/saved-objects/import.asciidoc index 1a380830ed21a..b3e4c48696a17 100644 --- a/docs/api/saved-objects/import.asciidoc +++ b/docs/api/saved-objects/import.asciidoc @@ -9,9 +9,9 @@ experimental[] Create sets of {kib} saved objects from a file created by the exp [[saved-objects-api-import-request]] ==== Request -`POST /api/saved_objects/_import` +`POST :/api/saved_objects/_import` -`POST /s//api/saved_objects/_import` +`POST :/s//api/saved_objects/_import` [[saved-objects-api-import-path-params]] ==== Path parameters @@ -55,14 +55,15 @@ The request body must include the multipart/form-data type. Import an index pattern and dashboard: -[source,js] +[source,sh] -------------------------------------------------- $ curl -X POST "localhost:5601/api/saved_objects/_import" -H "kbn-xsrf: true" --form file=@file.ndjson -------------------------------------------------- +// KIBANA The `file.ndjson` file contains the following: -[source,js] +[source,sh] -------------------------------------------------- {"type":"index-pattern","id":"my-pattern","attributes":{"title":"my-pattern-*"}} {"type":"dashboard","id":"my-dashboard","attributes":{"title":"Look at my dashboard"}} @@ -70,7 +71,7 @@ The `file.ndjson` file contains the following: The API returns the following: -[source,js] +[source,sh] -------------------------------------------------- { "success": true, @@ -80,14 +81,15 @@ The API returns the following: Import an index pattern and dashboard that includes a conflict on the index pattern: -[source,js] +[source,sh] -------------------------------------------------- $ curl -X POST "localhost:5601/api/saved_objects/_import" -H "kbn-xsrf: true" --form file=@file.ndjson -------------------------------------------------- +// KIBANA The `file.ndjson` file contains the following: -[source,js] +[source,sh] -------------------------------------------------- {"type":"index-pattern","id":"my-pattern","attributes":{"title":"my-pattern-*"}} {"type":"dashboard","id":"my-dashboard","attributes":{"title":"Look at my dashboard"}} @@ -95,7 +97,7 @@ The `file.ndjson` file contains the following: The API returns the following: -[source,js] +[source,sh] -------------------------------------------------- { "success": false, @@ -115,14 +117,15 @@ The API returns the following: Import a visualization and dashboard with an index pattern for the visualization reference that doesn't exist: -[source,js] +[source,sh] -------------------------------------------------- $ curl -X POST "localhost:5601/api/saved_objects/_import" -H "kbn-xsrf: true" --form file=@file.ndjson -------------------------------------------------- +// KIBANA The `file.ndjson` file contains the following: -[source,js] +[source,sh] -------------------------------------------------- {"type":"visualization","id":"my-vis","attributes":{"title":"my-vis"},"references":[{"name":"ref_0","type":"index-pattern","id":"my-pattern-*"}]} {"type":"dashboard","id":"my-dashboard","attributes":{"title":"Look at my dashboard"},"references":[{"name":"ref_0","type":"visualization","id":"my-vis"}]} @@ -130,7 +133,7 @@ The `file.ndjson` file contains the following: The API returns the following: -[source,js] +[source,sh] -------------------------------------------------- "success": false, "successCount": 0, diff --git a/docs/api/saved-objects/resolve_import_errors.asciidoc b/docs/api/saved-objects/resolve_import_errors.asciidoc index b64e5deb361b2..ec03917390d36 100644 --- a/docs/api/saved-objects/resolve_import_errors.asciidoc +++ b/docs/api/saved-objects/resolve_import_errors.asciidoc @@ -17,9 +17,9 @@ To resolve errors, you can: [[saved-objects-api-resolve-import-errors-request]] ==== Request -`POST /api/saved_objects/_resolve_import_errors` +`POST :/api/saved_objects/_resolve_import_errors` -`POST /s//api/saved_objects/_resolve_import_errors` +`POST :/s//api/saved_objects/_resolve_import_errors` [[saved-objects-api-resolve-import-errors-path-params]] ==== Path parameters @@ -61,21 +61,22 @@ The request body must include the multipart/form-data type. Retry a dashboard import: -[source,js] +[source,sh] -------------------------------------------------- $ curl -X POST "localhost:5601/api/saved_objects/_resolve_import_errors" -H "kbn-xsrf: true" --form file=@file.ndjson --form retries='[{"type":"dashboard","id":"my-dashboard"}]' -------------------------------------------------- +// KIBANA The `file.ndjson` file contains the following: -[source,js] +[source,sh] -------------------------------------------------- {"type":"dashboard","id":"my-dashboard","attributes":{"title":"Look at my dashboard"}} -------------------------------------------------- The API returns the following: -[source,js] +[source,sh] -------------------------------------------------- { "success": true, @@ -85,14 +86,15 @@ The API returns the following: Resolve errors for a dashboard and overwrite the existing saved object: -[source,js] +[source,sh] -------------------------------------------------- $ curl -X POST "localhost:5601/api/saved_objects/_resolve_import_errors" -H "kbn-xsrf: true" --form file=@file.ndjson --form retries='[{"type":"dashboard","id":"my-dashboard","overwrite":true}]' -------------------------------------------------- +// KIBANA The `file.ndjson` file contains the following: -[source,js] +[source,sh] -------------------------------------------------- {"type":"index-pattern","id":"my-pattern","attributes":{"title":"my-pattern-*"}} {"type":"dashboard","id":"my-dashboard","attributes":{"title":"Look at my dashboard"}} @@ -100,7 +102,7 @@ The `file.ndjson` file contains the following: The API returns the following: -[source,js] +[source,sh] -------------------------------------------------- { "success": true, @@ -110,21 +112,22 @@ The API returns the following: Resolve errors for a visualization by replacing the index pattern with another: -[source,js] +[source,sh] -------------------------------------------------- $ curl -X POST "localhost:5601/api/saved_objects/_resolve_import_errors" -H "kbn-xsrf: true" --form file=@file.ndjson --form retries='[{"type":"visualization","id":"my-vis","replaceReferences":[{"type":"index-pattern","from":"missing","to":"existing"}]}]' -------------------------------------------------- +// KIBANA The `file.ndjson` file contains the following: -[source,js] +[source,sh] -------------------------------------------------- {"type":"visualization","id":"my-vis","attributes":{"title":"Look at my visualization"},"references":[{"name":"ref_0","type":"index-pattern","id":"missing"}]} -------------------------------------------------- The API returns the following: -[source,js] +[source,sh] -------------------------------------------------- { "success": true, diff --git a/docs/api/saved-objects/update.asciidoc b/docs/api/saved-objects/update.asciidoc index 99a9bd4ad15bb..62f4104debc77 100644 --- a/docs/api/saved-objects/update.asciidoc +++ b/docs/api/saved-objects/update.asciidoc @@ -9,9 +9,9 @@ experimental[] Update the attributes for existing {kib} saved objects. [[saved-objects-api-update-request]] ==== Request -`PUT /api/saved_objects//` +`PUT :/api/saved_objects//` -`PUT /s//api/saved_objects//` +`PUT :/s//api/saved_objects//` [[saved-objects-api-update-path-params]] ==== Path parameters @@ -47,9 +47,9 @@ WARNING: When you update, attributes are not validated, which allows you to pass Update an existing index pattern object,`my-pattern`, with a different title: -[source,js] +[source,sh] -------------------------------------------------- -PUT api/saved_objects/index-pattern/my-pattern +$ curl -X PUT "localhost:5601/api/saved_objects/index-pattern/my-pattern" { "attributes": { "title": "some-other-pattern-*" @@ -60,7 +60,7 @@ PUT api/saved_objects/index-pattern/my-pattern The API returns the following: -[source,js] +[source,sh] -------------------------------------------------- { "id": "my-pattern", diff --git a/docs/api/spaces-management/copy_saved_objects.asciidoc b/docs/api/spaces-management/copy_saved_objects.asciidoc index c07b5f35efe09..e23a137485b2d 100644 --- a/docs/api/spaces-management/copy_saved_objects.asciidoc +++ b/docs/api/spaces-management/copy_saved_objects.asciidoc @@ -5,225 +5,75 @@ Copy saved objects to space ++++ -experimental["The underlying Spaces concepts are stable, but the APIs for managing Spaces are experimental."] - -//// -Use the appropriate heading levels for your book. -Add anchors for each section. -FYI: The section titles use attributes in case those terms change. -//// - -[[spaces-api-copy-saved-objects-request]] -==== {api-request-title} -//// -This section show the basic endpoint, without the body or optional parameters. -Variables should use <...> syntax. -If an API supports both PUT and POST, include both here. -//// - -`POST /api/spaces/_copy_saved_objects` - -`POST /s//api/spaces/_copy_saved_objects` - - -//// -[[spaces-api-copy-saved-objects-prereqs]] -==== {api-prereq-title} -//// -//// -Optional list of prerequisites. - -For example: - -* A snapshot of an index created in 5.x can be restored to 6.x. You must... -* If the {es} {security-features} are enabled, you must have `write`, `monitor`, -and `manage_follow_index` index privileges... -//// - - -[[spaces-api-copy-saved-objects-desc]] -==== {api-description-title} - -Copy saved objects between spaces. +experimental[] Copy saved objects between spaces. It also allows you to automatically copy related objects, so when you copy a `dashboard`, this can automatically copy over the associated visualizations, index patterns, and saved searches, as required. -You can request to overwrite any objects that already exist in the target space if they share an ID, or you can use the +You can request to overwrite any objects that already exist in the target space if they share an ID, or you can use the <> to do this on a per-object basis. -//// -Add a more detailed description the context. -Link to related APIs if appropriate. +[[spaces-api-copy-saved-objects-request]] +==== {api-request-title} -Guidelines for parameter documentation -*************************************** -* Use a definition list. -* End each definition with a period. -* Include whether the parameter is Optional or Required and the data type. -* Include default values as the last sentence of the first paragraph. -* Include a range of valid values, if applicable. -* If the parameter requires a specific delimiter for multiple values, say so. -* If the parameter supports wildcards, ditto. -* For large or nested objects, consider linking to a separate definition list. -*************************************** -//// +`POST :/api/spaces/_copy_saved_objects` +`POST :/s//api/spaces/_copy_saved_objects` [[spaces-api-copy-saved-objects-path-params]] ==== {api-path-parms-title} -//// -A list of all the parameters within the path of the endpoint (before the query string (?)). -For example: -``:: -(Required, string) Name of the follower index -//// `space_id`:: -(Optional, string) Identifies the source space from which saved objects will be copied. If `space_id` is not specified in the URL, the default space is used. - -//// -[[spaces-api-copy-saved-objects-params]] -==== {api-query-parms-title} -//// -//// -A list of the parameters in the query string of the endpoint (after the ?). - -For example: -`wait_for_active_shards`:: -(Optional, integer) Specifies the number of shards to wait on being active before -responding. A shard must be restored from the leader index being active. -Restoring a follower shard requires transferring all the remote Lucene segment -files to the follower index. The default is `0`, which means waiting on none of -the shards to be active. -//// +(Optional, string) The ID of the space that contains the saved objects you want to copy. When `space_id` is unspecified in the URL, the default space is used. [[spaces-api-copy-saved-objects-request-body]] ==== {api-request-body-title} -//// -A list of the properties you can specify in the body of the request. -For example: -`remote_cluster`:: -(Required, string) The <> that contains -the leader index. +`spaces`:: + (Required, string array) The IDs of the spaces where you want to copy the specified objects. -`leader_index`:: -(Required, string) The name of the index in the leader cluster to follow. -//// -`spaces` :: - (Required, string array) The ids of the spaces the specified object(s) will be copied into. - -`objects` :: +`objects`:: (Required, object array) The saved objects to copy. - `type` ::: + `type`::: (Required, string) The saved object type. - `id` ::: - (Required, string) The saved object id. + `id`::: + (Required, string) The saved object ID. -`includeReferences` :: +`includeReferences`:: (Optional, boolean) When set to `true`, all saved objects related to the specified saved objects will also be copied into the target spaces. The default value is `false`. -`overwrite` :: - (Optional, boolean) When set to `true`, all conflicts will be automatically overidden. If a saved object with a matching `type` and `id` exists in the target space, then that version will be replaced with the version from the source space. The default value is `false`. +`overwrite`:: + (Optional, boolean) When set to `true`, all conflicts are automatically overidden. When a saved object with a matching `type` and `id` exists in the target space, that version is replaced with the version from the source space. The default value is `false`. [[spaces-api-copy-saved-objects-response-body]] ==== {api-response-body-title} -//// -Response body is only required for detailed responses. - -For example: -`auto_follow_stats`:: - (object) An object representing stats for the auto-follow coordinator. This - object consists of the following fields: - -`auto_follow_stats.number_of_successful_follow_indices`::: - (long) the number of indices that the auto-follow coordinator successfully - followed -... - -//// ``:: - (object) Specifies the dynamic keys that are included in the response. An object describing the result of the copy operation for this particular space. + (object) An object that describes the result of the copy operation for the space. Includes the dynamic keys in the response. `success`::: - (boolean) Indicates if the copy operation was successful. Note that some objects may have been copied even if this is set to `false`. Consult the `successCount` and `errors` properties of the response for additional information. + (boolean) The copy operation was successful. When set to `false`, some objects may have been copied. For additional information, refer to the `successCount` and `errors` properties. `successCount`::: - (number) The number of objects that were successfully copied. + (number) The number of objects that successfully copied. `errors`::: - (Optional, array) Collection of any errors that were encountered during the copy operation. If any errors are reported, then the `success` flag will be set to `false`. + (Optional, array) The errors that occurred during the copy operation. When errors are reported, the `success` flag is set to `false`.v `id`:::: - (string) The saved object id which failed to copy. + (string) The saved object ID that failed to copy. `type`:::: - (string) The type of saved object which failed to copy. + (string) The type of saved object that failed to copy. `error`:::: - (object) The error which caused the copy operation to fail. + (object) The error that caused the copy operation to fail. `type`::::: - (string) Indicates the type of error. May be one of: `conflict`, `unsupported_type`, `missing_references`, `unknown`. Errors marked as `conflict` may be resolved by using the <>. - -//// -[[spaces-api-copy-saved-objects-response-codes]] -==== {api-response-codes-title} -//// -//// -Response codes are only required when needed to understand the response body. - -For example: -`200`:: -Indicates all listed indices or index aliases exist. - - `404`:: -Indicates one or more listed indices or index aliases **do not** exist. -//// - + (string) The type of error. For example, `unsupported_type`, `missing_references`, or `unknown`. Errors marked as `conflict` may be resolved by using the <>. [[spaces-api-copy-saved-objects-example]] ==== {api-examples-title} -//// -Optional brief example. -Use an 'Examples' heading if you include multiple examples. +Copy a dashboard with the `my-dashboard` ID, including all references from the `default` space to the `marketing` and `sales` spaces: -[source,js] +[source,sh] ---- -PUT /follower_index/_ccr/follow?wait_for_active_shards=1 -{ - "remote_cluster" : "remote_cluster", - "leader_index" : "leader_index", - "max_read_request_operation_count" : 1024, - "max_outstanding_read_requests" : 16, - "max_read_request_size" : "1024k", - "max_write_request_operation_count" : 32768, - "max_write_request_size" : "16k", - "max_outstanding_write_requests" : 8, - "max_write_buffer_count" : 512, - "max_write_buffer_size" : "512k", - "max_retry_delay" : "10s", - "read_poll_timeout" : "30s" -} ----- -// CONSOLE -// TEST[setup:remote_cluster_and_leader_index] - -The API returns the following result: - -[source,js] ----- -{ - "follow_index_created" : true, - "follow_index_shards_acked" : true, - "index_following_started" : true -} ----- -// TESTRESPONSE -//// - -The following example attempts to copy a dashboard with id `my-dashboard`, including all references from the `default` space to the `marketing` and `sales` spaces. The `marketing` space succeeds, while the `sales` space fails due to a conflict on the underlying index pattern: - -[source,js] ----- -POST /api/spaces/_copy_saved_objects +$ curl -X POST "localhost:5601/api/spaces/_copy_saved_objects" { "objects": [{ "type": "dashboard", @@ -235,9 +85,9 @@ POST /api/spaces/_copy_saved_objects ---- // KIBANA -The API returns the following result: +The API returns the following: -[source,js] +[source,sh] ---- { "marketing": { @@ -258,11 +108,13 @@ The API returns the following result: } ---- -The following example successfully copies a visualization with id `my-viz` from the `marketing` space to the `default` space: +The `marketing` space succeeds, but the `sales` space fails due to a conflict in the index pattern. + +Copy a visualization with the `my-viz` ID from the `marketing` space to the `default` space: -[source,js] +[source,sh] ---- -POST /s/marketing/api/spaces/_copy_saved_objects +$ curl -X POST "localhost:5601/s/marketing/api/spaces/_copy_saved_objects" { "objects": [{ "type": "visualization", @@ -273,9 +125,9 @@ POST /s/marketing/api/spaces/_copy_saved_objects ---- // KIBANA -The API returns the following result: +The API returns the following: -[source,js] +[source,sh] ---- { "default": { diff --git a/docs/api/spaces-management/delete.asciidoc b/docs/api/spaces-management/delete.asciidoc index c66307ea3070f..5b4db78c056dd 100644 --- a/docs/api/spaces-management/delete.asciidoc +++ b/docs/api/spaces-management/delete.asciidoc @@ -4,22 +4,20 @@ Delete space ++++ -Delete a {kib} space. +experimental[] Delete a {kib} space. -experimental["The underlying Spaces concepts are stable, but the APIs for managing Spaces are experimental."] - -WARNING: When you delete a space, all saved objects that belong to the space are automatically deleted, which is permanent and cannot be undone. +WARNING: When you delete a space, all saved objects that belong to the space are automatically deleted, which is permanent and cannot be undone. [[spaces-api-delete-request]] ==== Request -`DELETE /api/spaces/space/marketing` +`DELETE :/api/spaces/space/marketing` [[spaces-api-delete-errors-codes]] ==== Response codes -`204`:: +`204`:: Indicates a successful call. - + `404`:: Indicates that the request failed. diff --git a/docs/api/spaces-management/get.asciidoc b/docs/api/spaces-management/get.asciidoc index 49119d7602b20..48245b7786604 100644 --- a/docs/api/spaces-management/get.asciidoc +++ b/docs/api/spaces-management/get.asciidoc @@ -4,14 +4,12 @@ Get space ++++ -Retrieve a specified {kib} space. - -experimental["The underlying Spaces concepts are stable, but the APIs for managing Spaces are experimental."] +experimental[] Retrieve a specified {kib} space. [[spaces-api-get-request]] ==== Request -`GET /api/spaces/space/marketing` +`GET :/api/spaces/space/marketing` [[spaces-api-get-response-codes]] ==== Response code @@ -24,7 +22,7 @@ experimental["The underlying Spaces concepts are stable, but the APIs for managi The API returns the following: -[source,js] +[source,sh] -------------------------------------------------- { "id": "marketing", @@ -35,4 +33,4 @@ The API returns the following: "disabledFeatures": [], "imageUrl": "" } --------------------------------------------------- \ No newline at end of file +-------------------------------------------------- diff --git a/docs/api/spaces-management/get_all.asciidoc b/docs/api/spaces-management/get_all.asciidoc index f7fb92baa165f..8f7ba86f332de 100644 --- a/docs/api/spaces-management/get_all.asciidoc +++ b/docs/api/spaces-management/get_all.asciidoc @@ -4,14 +4,12 @@ Get all spaces ++++ -Retrieve all {kib} spaces. - -experimental["The underlying Spaces concepts are stable, but the APIs for managing Spaces are experimental."] +experimental[] Retrieve all {kib} spaces. [[spaces-api-get-all-request]] ==== Request -`GET /api/spaces/space` +`GET :/api/spaces/space` [[spaces-api-get-all-response-codes]] ==== Response code @@ -24,7 +22,7 @@ experimental["The underlying Spaces concepts are stable, but the APIs for managi The API returns the following: -[source,js] +[source,sh] -------------------------------------------------- [ { diff --git a/docs/api/spaces-management/post.asciidoc b/docs/api/spaces-management/post.asciidoc index 4d4627e98899e..b96fbe6364c34 100644 --- a/docs/api/spaces-management/post.asciidoc +++ b/docs/api/spaces-management/post.asciidoc @@ -4,14 +4,12 @@ Create space ++++ -Create a {kib} space. - -experimental["The underlying Spaces concepts are stable, but the APIs for managing Spaces are experimental."] +experimental[] Create a {kib} space. [[spaces-api-post-request]] ==== Request -`POST /api/spaces/space` +`POST :/api/spaces/space` [[spaces-api-post-request-body]] ==== Request body @@ -29,13 +27,13 @@ experimental["The underlying Spaces concepts are stable, but the APIs for managi (Optional, string array) The list of disabled features for the space. To get a list of available feature IDs, use the <>. `initials`:: - (Optional, string) Specifies the initials shown in the space avatar. By default, the initials are automatically generated from the space name. Initials must be 1 or 2 characters. + (Optional, string) The initials shown in the space avatar. By default, the initials are automatically generated from the space name. Initials must be 1 or 2 characters. `color`:: - (Optional, string) Specifies the hexadecimal color code used in the space avatar. By default, the color is automatically generated from the space name. + (Optional, string) The hexadecimal color code used in the space avatar. By default, the color is automatically generated from the space name. `imageUrl`:: - (Optional, string) Specifies the data-url encoded image to display in the space avatar. If specified, `initials` will not be displayed, and the `color` will be visible as the background color for transparent images. + (Optional, string) The data-URL encoded image to display in the space avatar. If specified, `initials` will not be displayed, and the `color` will be visible as the background color for transparent images. For best results, your image should be 64x64. Images will not be optimized by this API call, so care should be taken when using custom images. [[spaces-api-post-response-codes]] @@ -47,9 +45,9 @@ experimental["The underlying Spaces concepts are stable, but the APIs for managi [[spaces-api-post-example]] ==== Example -[source,js] +[source,sh] -------------------------------------------------- -POST /api/spaces/space +$ curl -X POST "localhost:5601/api/spaces/space" { "id": "marketing", "name": "Marketing", diff --git a/docs/api/spaces-management/put.asciidoc b/docs/api/spaces-management/put.asciidoc index 586818707c76f..f405d57975a70 100644 --- a/docs/api/spaces-management/put.asciidoc +++ b/docs/api/spaces-management/put.asciidoc @@ -4,37 +4,35 @@ Update space ++++ -Update an existing {kib} space. - -experimental["The underlying Spaces concepts are stable, but the APIs for managing Spaces are experimental."] +experimental[] Update an existing {kib} space. [[spaces-api-put-api-request]] ==== Request -`PUT /api/spaces/space/` +`PUT :/api/spaces/space/` [[spaces-api-put-request-body]] ==== Request body -`id`:: +`id`:: (Required, string) The space ID that is part of the {kib} URL when inside the space. You are unable to change the ID with the update operation. -`name`:: +`name`:: (Required, string) The display name for the space. -`description`:: +`description`:: (Optional, string) The description for the space. -`disabledFeatures`:: +`disabledFeatures`:: (Optional, string array) The list of disabled features for the space. To get a list of available feature IDs, use the <>. -`initials`:: +`initials`:: (Optional, string) Specifies the initials shown in the space avatar. By default, the initials are automatically generated from the space name. Initials must be 1 or 2 characters. -`color`:: +`color`:: (Optional, string) Specifies the hexadecimal color code used in the space avatar. By default, the color is automatically generated from the space name. -`imageUrl`:: +`imageUrl`:: (Optional, string) Specifies the data-url encoded image to display in the space avatar. If specified, `initials` will not be displayed, and the `color` will be visible as the background color for transparent images. For best results, your image should be 64x64. Images will not be optimized by this API call, so care should be taken when using custom images. @@ -43,13 +41,13 @@ experimental["The underlying Spaces concepts are stable, but the APIs for managi `200`:: Indicates a successful call. - + [[sample-api-example]] ==== Example -[source,js] +[source,sh] -------------------------------------------------- -PUT /api/spaces/space/marketing +$ curl -X PUT "localhost:5601/api/spaces/space/marketing" { "id": "marketing", "name": "Marketing", diff --git a/docs/api/spaces-management/resolve_copy_saved_objects_conflicts.asciidoc b/docs/api/spaces-management/resolve_copy_saved_objects_conflicts.asciidoc index 7b52125599c05..8e874bb9f94e5 100644 --- a/docs/api/spaces-management/resolve_copy_saved_objects_conflicts.asciidoc +++ b/docs/api/spaces-management/resolve_copy_saved_objects_conflicts.asciidoc @@ -5,227 +5,80 @@ Resolve copy to space conflicts ++++ -Overwrite specific saved objects that were returned as errors from the <>. - -experimental["The underlying Spaces concepts are stable, but the APIs for managing Spaces are experimental."] - -//// -Use the appropriate heading levels for your book. -Add anchors for each section. -FYI: The section titles use attributes in case those terms change. -//// +experimental[] Overwrite saved objects that are returned as errors from the <>. [[spaces-api-resolve-copy-saved-objects-conflicts-request]] ==== {api-request-title} -//// -This section show the basic endpoint, without the body or optional parameters. -Variables should use <...> syntax. -If an API supports both PUT and POST, include both here. -//// - -`POST /api/spaces/_resolve_copy_saved_objects_errors` - -`POST /s//api/spaces/_resolve_copy_saved_objects_errors` +`POST :/api/spaces/_resolve_copy_saved_objects_errors` +`POST :/s//api/spaces/_resolve_copy_saved_objects_errors` [[spaces-api-resolve-copy-saved-objects-conflicts-prereqs]] ==== {api-prereq-title} -//// -Optional list of prerequisites. - -For example: - -* A snapshot of an index created in 5.x can be restored to 6.x. You must... -* If the {es} {security-features} are enabled, you must have `write`, `monitor`, -and `manage_follow_index` index privileges... -//// -* Executed the <>, which returned one or more `conflict` errors that you wish to resolve. - -//// -[[spaces-api-resolve-copy-saved-objects-conflicts-desc]] -==== {api-description-title} - -Allows saved objects to be selectively overridden in the target spaces. -//// - -//// -Add a more detailed description the context. -Link to related APIs if appropriate. - -Guidelines for parameter documentation -*************************************** -* Use a definition list. -* End each definition with a period. -* Include whether the parameter is Optional or Required and the data type. -* Include default values as the last sentence of the first paragraph. -* Include a range of valid values, if applicable. -* If the parameter requires a specific delimiter for multiple values, say so. -* If the parameter supports wildcards, ditto. -* For large or nested objects, consider linking to a separate definition list. -*************************************** -//// +Execute the <>, which returns the errors for you to resolve. [[spaces-api-resolve-copy-saved-objects-conflicts-path-params]] ==== {api-path-parms-title} -//// -A list of all the parameters within the path of the endpoint (before the query string (?)). -For example: -``:: -(Required, string) Name of the follower index -//// `space_id`:: -(Optional, string) Identifies the source space from which saved objects will be copied. If `space_id` is not specified in the URL, the default space is used. Must be the same value that was used during the failed <> operation. - -//// -[[spaces-api-resolve-copy-saved-objects-conflicts-request-params]] -==== {api-query-parms-title} -//// -//// -A list of the parameters in the query string of the endpoint (after the ?). - -For example: -`wait_for_active_shards`:: -(Optional, integer) Specifies the number of shards to wait on being active before -responding. A shard must be restored from the leader index being active. -Restoring a follower shard requires transferring all the remote Lucene segment -files to the follower index. The default is `0`, which means waiting on none of -the shards to be active. -//// +(Optional, string) The ID of the space that contains the saved objects you want to copy. When `space_id` is unspecified in the URL, the default space is used. The `space_id` must be the same value used during the failed <> operation. [[spaces-api-resolve-copy-saved-objects-conflicts-request-body]] ==== {api-request-body-title} -//// -A list of the properties you can specify in the body of the request. - -For example: -`remote_cluster`:: -(Required, string) The <> that contains -the leader index. -`leader_index`:: -(Required, string) The name of the index in the leader cluster to follow. -//// -`objects` :: - (Required, object array) The saved objects to copy. Must be the same value that was used during the failed <> operation. - `type` ::: +`objects`:: + (Required, object array) The saved objects to copy. The `objects` must be the same values used during the failed <> operation. + `type`::: (Required, string) The saved object type. - `id` ::: - (Required, string) The saved object id. + `id`::: + (Required, string) The saved object ID. -`includeReferences` :: - (Optional, boolean) When set to `true`, all saved objects related to the specified saved objects will also be copied into the target spaces. You must set this to the same value that you used when executing the <>. The default value is `false`. +`includeReferences`:: + (Optional, boolean) When set to `true`, all saved objects related to the specified saved objects are copied into the target spaces. The `includeReferences` must be the same values used during the failed <> operation. The default value is `false`. `retries`:: - (Required, object) The retry operations to attempt. Object keys represent the target space ids. - `` ::: - (Required, array) The the conflicts to resolve for the indicated ``. - `type` :::: + (Required, object) The retry operations to attempt. Object keys represent the target space IDs. + ``::: + (Required, array) The errors to resolve for the specified ``. + `type`:::: (Required, string) The saved object type. - `id` :::: - (Required, string) The saved object id. - `overwrite` :::: - (Required, boolean) when set to `true`, the saved object from the source space (desigated by the <>) will overwrite the the conflicting object in the destination space. When `false`, this does nothing. + `id`:::: + (Required, string) The saved object ID. + `overwrite`:::: + (Required, boolean) When set to `true`, the saved object from the source space (desigated by the <>) overwrites the conflicting object in the destination space. When set to `false`, this does nothing. [[spaces-api-resolve-copy-saved-objects-conflicts-response-body]] ==== {api-response-body-title} -//// -Response body is only required for detailed responses. - -For example: -`auto_follow_stats`:: - (object) An object representing stats for the auto-follow coordinator. This - object consists of the following fields: - -`auto_follow_stats.number_of_successful_follow_indices`::: - (long) the number of indices that the auto-follow coordinator successfully - followed -... - -//// ``:: - (object) Specifies the dynamic keys that are included in the response. An object describing the result of the copy operation for this particular space. + (object) An object that describes the result of the copy operation for the space. Includes the dynamic keys in the response. `success`::: - (boolean) Indicates if the copy operation was successful. Note that some objects may have been copied even if this is set to `false`. Consult the `successCount` and `errors` properties of the response for additional information. + (boolean) The copy operation was successful. When set to `false`, some objects may have been copied. For additional information, refer to the `successCount` and `errors` properties. `successCount`::: - (number) The number of objects that were successfully copied. + (number) The number of objects that successfully copied. `errors`::: - (Optional, array) Collection of any errors that were encountered during the copy operation. If any errors are reported, then the `success` flag will be set to `false`. + (Optional, array) The errors that occurred during the copy operation. When errors are reported, the `success` flag is set to `false`. `id`:::: - (string) The saved object id which failed to copy. + (string) The saved object ID that failed to copy. `type`:::: - (string) The type of saved object which failed to copy. + (string) The type of saved object that failed to copy. `error`:::: - (object) The error which caused the copy operation to fail. + (object) The error that caused the copy operation to fail. `type`::::: - (string) Indicates the type of error. May be one of: `unsupported_type`, `missing_references`, `unknown`. - -//// -[[spaces-api-resolve-copy-saved-objects-conflicts-response-codes]] -==== {api-response-codes-title} -//// -//// -Response codes are only required when needed to understand the response body. - -For example: -`200`:: -Indicates all listed indices or index aliases exist. - - `404`:: -Indicates one or more listed indices or index aliases **do not** exist. -//// + (string) The type of error. For example, `unsupported_type`, `missing_references`, or `unknown`. [[spaces-api-resolve-copy-saved-objects-conflicts-example]] ==== {api-examples-title} -//// -Optional brief example. -Use an 'Examples' heading if you include multiple examples. - - -[source,js] ----- -PUT /follower_index/_ccr/follow?wait_for_active_shards=1 -{ - "remote_cluster" : "remote_cluster", - "leader_index" : "leader_index", - "max_read_request_operation_count" : 1024, - "max_outstanding_read_requests" : 16, - "max_read_request_size" : "1024k", - "max_write_request_operation_count" : 32768, - "max_write_request_size" : "16k", - "max_outstanding_write_requests" : 8, - "max_write_buffer_count" : 512, - "max_write_buffer_size" : "512k", - "max_retry_delay" : "10s", - "read_poll_timeout" : "30s" -} ----- -// CONSOLE -// TEST[setup:remote_cluster_and_leader_index] - -The API returns the following result: - -[source,js] ----- -{ - "follow_index_created" : true, - "follow_index_shards_acked" : true, - "index_following_started" : true -} ----- -// TESTRESPONSE -//// -The following example overwrites an index pattern in the marketing space, and a visualization in the sales space. +Overwrite an index pattern in the `marketing` space, and a visualization in the `sales` space: -[source,js] +[source,sh] ---- -POST api/spaces/_resolve_copy_saved_objects_errors +$ curl -X POST "localhost:5601/api/spaces/_resolve_copy_saved_objects_errors" { "objects": [{ "type": "dashboard", @@ -248,9 +101,9 @@ POST api/spaces/_resolve_copy_saved_objects_errors ---- // KIBANA -The API returns the following result: +The API returns the following: -[source,js] +[source,sh] ---- { "marketing": { diff --git a/docs/api/upgrade-assistant.asciidoc b/docs/api/upgrade-assistant.asciidoc index 3e9c416b292cf..15d87fbd0dc9d 100644 --- a/docs/api/upgrade-assistant.asciidoc +++ b/docs/api/upgrade-assistant.asciidoc @@ -2,7 +2,7 @@ [[upgrade-assistant-api]] == Upgrade assistant APIs -Check the upgrade status of your Elasticsearch cluster and reindex indices that were created in the previous major version. The assistant helps you prepare for the next major version of Elasticsearch. +Check the upgrade status of your {es} cluster and reindex indices that were created in the previous major version. The assistant helps you prepare for the next major version of {es}. The following upgrade assistant APIs are available: @@ -16,7 +16,7 @@ The following upgrade assistant APIs are available: * <> to check the status of the reindex operation -* <> to cancel reindexes that are waiting for the Elasticsearch reindex task to complete +* <> to cancel reindexes that are waiting for the {es} reindex task to complete include::upgrade-assistant/status.asciidoc[] include::upgrade-assistant/reindexing.asciidoc[] diff --git a/docs/api/upgrade-assistant/cancel_reindex.asciidoc b/docs/api/upgrade-assistant/cancel_reindex.asciidoc index d31894cd06a05..04ab3bdde35fc 100644 --- a/docs/api/upgrade-assistant/cancel_reindex.asciidoc +++ b/docs/api/upgrade-assistant/cancel_reindex.asciidoc @@ -4,14 +4,14 @@ Cancel reindex ++++ -experimental["The underlying Upgrade Assistant concepts are stable, but the APIs for managing Upgrade Assistant are experimental."] +experimental[] Cancel reindexes that are waiting for the {es} reindex task to complete. For example, `lastCompletedStep` set to `40`. Cancel reindexes that are waiting for the Elasticsearch reindex task to complete. For example, `lastCompletedStep` set to `40`. [[cancel-reindex-request]] ==== Request -`POST /api/upgrade_assistant/reindex/myIndex/cancel` +`POST :/api/upgrade_assistant/reindex/myIndex/cancel` [[cancel-reindex-response-codes]] ==== Response codes @@ -24,7 +24,7 @@ Cancel reindexes that are waiting for the Elasticsearch reindex task to complete The API returns the following: -[source,js] +[source,sh] -------------------------------------------------- { "acknowledged": true diff --git a/docs/api/upgrade-assistant/check_reindex_status.asciidoc b/docs/api/upgrade-assistant/check_reindex_status.asciidoc index c422e5764c69f..00801f201d1e1 100644 --- a/docs/api/upgrade-assistant/check_reindex_status.asciidoc +++ b/docs/api/upgrade-assistant/check_reindex_status.asciidoc @@ -4,27 +4,27 @@ Check reindex status ++++ -experimental["The underlying Upgrade Assistant concepts are stable, but the APIs for managing Upgrade Assistant are experimental."] +experimental[] Check the status of the reindex operation. Check the status of the reindex operation. [[check-reindex-status-request]] ==== Request -`GET /api/upgrade_assistant/reindex/myIndex` +`GET :/api/upgrade_assistant/reindex/myIndex` [[check-reindex-status-response-codes]] ==== Response codes `200`:: Indicates a successful call. - + [[check-reindex-status-example]] ==== Example The API returns the following: -[source,js] +[source,sh] -------------------------------------------------- { "reindexOp": { @@ -53,59 +53,58 @@ The API returns the following: [[status-code]] ==== Status codes -`0`:: +`0`:: In progress -`1`:: +`1`:: Completed -`2`:: +`2`:: Failed - -`3`:: + +`3`:: Paused NOTE: If the {kib} node that started the reindex is shutdown or restarted, the reindex goes into a paused state after some time. To resume the reindex, you must submit a new POST request to the `/api/upgrade_assistant/reindex/` endpoint. -`4`:: +`4`:: Cancelled [[step-code]] ==== Step codes -`0`:: +`0`:: The reindex operation has been created in Kibana. - -`10`:: + +`10`:: The index group services stopped. Only applies to some system indices. - -`20`:: - The index is set to `readonly`. - -`30`:: + +`20`:: + The index is set to `readonly`. + +`30`:: The new destination index has been created. - -`40`:: + +`40`:: The reindex task in Elasticsearch has started. - -`50`:: + +`50`:: The reindex task in Elasticsearch has completed. - -`60`:: + +`60`:: Aliases were created to point to the new index, and the old index has been deleted. - -`70`:: + +`70`:: The index group services have resumed. Only applies to some system indices. [[warning-code]] ==== Warning codes -`0`:: +`0`:: Specifies to remove the `_all` meta field. - -`1`:: + +`1`:: Specifies to convert any coerced boolean values in the source document. For example, `yes`, `1`, and `off`. - -`2`:: - Specifies to convert documents to support Elastic Common Schema. Only applies to APM indices created in 6.x. +`2`:: + Specifies to convert documents to support Elastic Common Schema. Only applies to APM indices created in 6.x. diff --git a/docs/api/upgrade-assistant/reindexing.asciidoc b/docs/api/upgrade-assistant/reindexing.asciidoc index 51e7b917b67ac..ce5670822e5ad 100644 --- a/docs/api/upgrade-assistant/reindexing.asciidoc +++ b/docs/api/upgrade-assistant/reindexing.asciidoc @@ -4,14 +4,14 @@ Start or resume reindex ++++ -experimental["The underlying Upgrade Assistant concepts are stable, but the APIs for managing Upgrade Assistant are experimental."] +experimental[] Start a new reindex or resume a paused reindex. Start a new reindex or resume a paused reindex. [[start-resume-reindex-request]] ==== Request -`POST /api/upgrade_assistant/reindex/myIndex` +`POST :/api/upgrade_assistant/reindex/myIndex` [[start-resume-reindex-codes]] ==== Response code @@ -24,7 +24,7 @@ Start a new reindex or resume a paused reindex. The API returns the following: -[source,js] +[source,sh] -------------------------------------------------- { "indexName": ".ml-state", @@ -37,9 +37,9 @@ The API returns the following: } -------------------------------------------------- -<1> Name of the new index that is being created. -<2> Current status of the reindex. For details, see <>. -<3> Last successfully completed step of the reindex. For details, see <> table. -<4> Task ID of the reindex task in Elasticsearch. Only present if reindexing has started. -<5> Percentage of how far the reindexing task in Elasticsearch has progressed, in decimal from from 0 to 1. -<6> Error that caused the reindex to fail, if it failed. +<1> The name of the new index. +<2> The reindex status. For more information, refer to <>. +<3> The last successfully completed step of the reindex. For more information, refer to <>. +<4> The task ID of the reindex task in {es}. Appears when the reindexing starts. +<5> The progress of the reindexing task in {es}. Appears in decimal form, from 0 to 1. +<6> The error that caused the reindex to fail, if it failed. diff --git a/docs/api/upgrade-assistant/status.asciidoc b/docs/api/upgrade-assistant/status.asciidoc index b087a66fa3bcd..42030061c4289 100644 --- a/docs/api/upgrade-assistant/status.asciidoc +++ b/docs/api/upgrade-assistant/status.asciidoc @@ -4,14 +4,14 @@ Upgrade readiness status ++++ -experimental["The underlying Upgrade Assistant concepts are stable, but the APIs for managing Upgrade Assistant are experimental."] +experimental[] Check the status of your cluster. Check the status of your cluster. [[upgrade-assistant-api-status-request]] ==== Request -`GET /api/upgrade_assistant/status` +`GET :/api/upgrade_assistant/status` [[upgrade-assistant-api-status-response-codes]] ==== Response codes @@ -24,7 +24,7 @@ Check the status of your cluster. The API returns the following: -[source,js] +[source,sh] -------------------------------------------------- { "readyForUpgrade": false, diff --git a/docs/api/url-shortening.asciidoc b/docs/api/url-shortening.asciidoc index 8bc701a3d5d12..a62529e11a9ba 100644 --- a/docs/api/url-shortening.asciidoc +++ b/docs/api/url-shortening.asciidoc @@ -12,18 +12,18 @@ Short URLs are designed to make sharing {kib} URLs easier. [[url-shortening-api-request]] ==== Request -`POST /api/shorten_url` +`POST :/api/shorten_url` [[url-shortening-api-request-body]] ==== Request body `url`:: - (Required, string) The {kib} URL that you want to shorten, Relative to `/app/kibana`. + (Required, string) The {kib} URL that you want to shorten, relative to `/app/kibana`. [[url-shortening-api-response-body]] ==== Response body -urlId:: A top level property that contains the shortened URL token for the provided request body. +urlId:: A top-level property that contains the shortened URL token for the provided request body. [[url-shortening-api-codes]] ==== Response code @@ -31,21 +31,21 @@ urlId:: A top level property that contains the shortened URL token for the provi `200`:: Indicates a successful call. -[[url-shortening-api-example]] +[[url-shortening-api-example]] ==== Example -[source,js] +[source,sh] -------------------------------------------------- -POST api/shorten_url +$ curl -X POST "localhost:5601/api/shorten_url" { "url": "/app/kibana#/dashboard?_g=()&_a=(description:'',filters:!(),fullScreenMode:!f,options:(hidePanelTitles:!f,useMargins:!t),panels:!((embeddableConfig:(),gridData:(h:15,i:'1',w:24,x:0,y:0),id:'8f4d0c00-4c86-11e8-b3d7-01146121b73d',panelIndex:'1',type:visualization,version:'7.0.0-alpha1')),query:(language:lucene,query:''),timeRestore:!f,title:'New%20Dashboard',viewMode:edit)" } -------------------------------------------------- // KIBANA -The API returns the following result: +The API returns the following: -[source,js] +[source,sh] -------------------------------------------------- { "urlId": "f73b295ff92718b26bc94edac766d8e3" diff --git a/docs/api/using-api.asciidoc b/docs/api/using-api.asciidoc index 37c5315025dc4..aba65f2e921c2 100644 --- a/docs/api/using-api.asciidoc +++ b/docs/api/using-api.asciidoc @@ -33,6 +33,7 @@ For example, the following `curl` command exports a dashboard: -- curl -X POST -u $USER:$PASSWORD "localhost:5601/api/kibana/dashboards/export?dashboard=942dcef0-b2cd-11e8-ad8e-85441f0c2e5c" -- +// KIBANA [float] [[api-request-headers]] @@ -43,14 +44,14 @@ For all APIs, you must use a request header. The {kib} APIs support the `kbn-xsr `kbn-xsrf: true`:: By default, you must use `kbn-xsrf` for all API calls, except in the following scenarios: -* The API endpoint uses the `GET` or `HEAD` methods +* The API endpoint uses the `GET` or `HEAD` operations * The path is whitelisted using the <> setting * XSRF protections are disabled using the `server.xsrf.disableProtection` setting `Content-Type: application/json`:: - Applicable only when you send a payload in the API request. {kib} API requests and responses use JSON. Typically, if you include the `kbn-xsrf` header, you must also include the `Content-Type` header. + Applicable only when you send a payload in the API request. {kib} API requests and responses use JSON. Typically, if you include the `kbn-xsrf` header, you must also include the `Content-Type` header. Request header example: From 0bf199757fbfb6b3f21f6a61edc78c8127cf7059 Mon Sep 17 00:00:00 2001 From: Brittany Joiner Date: Fri, 20 Mar 2020 17:05:46 -0500 Subject: [PATCH 16/31] Change "url" to "urls" in APM agent instructions (#60790) --- .../apm/server/tutorial/instructions/apm_agent_instructions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/apm/server/tutorial/instructions/apm_agent_instructions.ts b/x-pack/plugins/apm/server/tutorial/instructions/apm_agent_instructions.ts index 54dab4d13845e..d076008da9d8e 100644 --- a/x-pack/plugins/apm/server/tutorial/instructions/apm_agent_instructions.ts +++ b/x-pack/plugins/apm/server/tutorial/instructions/apm_agent_instructions.ts @@ -689,7 +689,7 @@ Do **not** add the agent as a dependency to your application.', ), commands: `java -javaagent:/path/to/elastic-apm-agent-.jar \\ -Delastic.apm.service_name=my-application \\ - -Delastic.apm.server_url=${apmServerUrl || 'http://localhost:8200'} \\ + -Delastic.apm.server_urls=${apmServerUrl || 'http://localhost:8200'} \\ -Delastic.apm.secret_token=${secretToken} \\ -Delastic.apm.application_packages=org.example \\ -jar my-application.jar`.split('\n'), From 677055f3adda7839193c010dc00b64d535bbd75c Mon Sep 17 00:00:00 2001 From: kqualters-elastic <56408403+kqualters-elastic@users.noreply.github.com> Date: Fri, 20 Mar 2020 18:07:41 -0400 Subject: [PATCH 17/31] Flatten child api response for resolver (#60810) --- .../embeddables/resolver/store/middleware.ts | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/endpoint/public/embeddables/resolver/store/middleware.ts b/x-pack/plugins/endpoint/public/embeddables/resolver/store/middleware.ts index 23e4a4fe7d7ed..4e57212e5c0c2 100644 --- a/x-pack/plugins/endpoint/public/embeddables/resolver/store/middleware.ts +++ b/x-pack/plugins/endpoint/public/embeddables/resolver/store/middleware.ts @@ -16,6 +16,19 @@ type MiddlewareFactory = ( ) => ( api: MiddlewareAPI, S> ) => (next: Dispatch) => (action: ResolverAction) => unknown; +interface Lifecycle { + lifecycle: ResolverEvent[]; +} +type ChildResponse = [Lifecycle]; + +function flattenEvents(events: ChildResponse): ResolverEvent[] { + return events + .map((child: Lifecycle) => child.lifecycle) + .reduce( + (accumulator: ResolverEvent[], value: ResolverEvent[]) => accumulator.concat(value), + [] + ); +} export const resolverMiddlewareFactory: MiddlewareFactory = context => { return api => next => async (action: ResolverAction) => { @@ -47,7 +60,7 @@ export const resolverMiddlewareFactory: MiddlewareFactory = context => { query: { legacyEndpointID }, }), ]); - childEvents = children.length > 0 ? children.map((child: any) => child.lifecycle) : []; + childEvents = children.length > 0 ? flattenEvents(children) : []; } else { const uniquePid = action.payload.selectedEvent.process.entity_id; const ppid = action.payload.selectedEvent.process.parent?.entity_id; @@ -67,7 +80,7 @@ export const resolverMiddlewareFactory: MiddlewareFactory = context => { getAncestors(ppid), ]); } - childEvents = children.length > 0 ? children.map((child: any) => child.lifecycle) : []; + childEvents = children.length > 0 ? flattenEvents(children) : []; response = [...lifecycle, ...childEvents, ...relatedEvents, ...ancestors]; api.dispatch({ type: 'serverReturnedResolverData', From 74ceceb324e9e6cc677218725a94f9e80113666b Mon Sep 17 00:00:00 2001 From: Frank Hassanabad Date: Fri, 20 Mar 2020 17:33:09 -0600 Subject: [PATCH 18/31] [SIEM][Detection Engine] Adds test scripts for machine learning feature ## Summary * Adds ad-hoc testing scripts for machine learning feature ## Testing ```ts ./post_rule.sh ./rules/queries/query_with_machine_learning.json ./update_rule.sh ./rules/updates/update_machine_learning.json ./patch_rule.sh ./rules/patches/update_machine_learning.json ``` --- .../scripts/rules/patches/update_machine_learning.json | 4 ++++ .../rules/queries/query_with_machine_learning.json | 10 ++++++++++ .../scripts/rules/updates/update_machine_learning.json | 10 ++++++++++ 3 files changed, 24 insertions(+) create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/rules/patches/update_machine_learning.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/rules/queries/query_with_machine_learning.json create mode 100644 x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/rules/updates/update_machine_learning.json diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/rules/patches/update_machine_learning.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/rules/patches/update_machine_learning.json new file mode 100644 index 0000000000000..638c2a35c2a65 --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/rules/patches/update_machine_learning.json @@ -0,0 +1,4 @@ +{ + "rule_id": "machine-learning", + "anomaly_threshold": 10 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/rules/queries/query_with_machine_learning.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/rules/queries/query_with_machine_learning.json new file mode 100644 index 0000000000000..db2664978807e --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/rules/queries/query_with_machine_learning.json @@ -0,0 +1,10 @@ +{ + "name": "Query with a machine learning job", + "description": "Query with a machine learning job", + "rule_id": "machine-learning", + "risk_score": 1, + "severity": "high", + "type": "machine_learning", + "machine_learning_job_id": "linux_anomalous_network_activity_ecs", + "anomaly_threshold": 50 +} diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/rules/updates/update_machine_learning.json b/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/rules/updates/update_machine_learning.json new file mode 100644 index 0000000000000..dfa82c337a68b --- /dev/null +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/scripts/rules/updates/update_machine_learning.json @@ -0,0 +1,10 @@ +{ + "name": "Query with a machine learning job", + "description": "Query with a machine learning job", + "rule_id": "machine-learning", + "risk_score": 1, + "severity": "high", + "type": "machine_learning", + "machine_learning_job_id": "linux_anomalous_network_activity_ecs", + "anomaly_threshold": 100 +} From e73159281e72d92a7139dd0886d8c8a549bdd251 Mon Sep 17 00:00:00 2001 From: Patrick Mueller Date: Fri, 20 Mar 2020 20:00:47 -0400 Subject: [PATCH 19/31] [Alerting] fix flaky test for index threshold grouping (#60792) resolves https://github.com/elastic/kibana/issues/60744 This is a fairly complex test, with alerts that run actions that write to an index which we then do queries over. The tests didn't account for some slop in all that async activity, but now should be about as flake-free as they can be. --- .../builtin_alert_types/index_threshold/alert.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/index_threshold/alert.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/index_threshold/alert.ts index 87acbcf99d383..8f161cfa37c93 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/index_threshold/alert.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/index_threshold/alert.ts @@ -135,7 +135,8 @@ export default function alertTests({ getService }: FtrProviderContext) { } // there should be 2 docs in group-0, rando split between others - expect(inGroup0).to.be(2); + // allow for some flakiness ... + expect(inGroup0).to.be.greaterThan(0); }); it('runs correctly: sum all between', async () => { @@ -238,7 +239,8 @@ export default function alertTests({ getService }: FtrProviderContext) { } // there should be 2 docs in group-2, rando split between others - expect(inGroup2).to.be(2); + // allow for some flakiness ... + expect(inGroup2).to.be.greaterThan(0); }); it('runs correctly: min grouped', async () => { @@ -279,7 +281,8 @@ export default function alertTests({ getService }: FtrProviderContext) { } // there should be 2 docs in group-0, rando split between others - expect(inGroup0).to.be(2); + // allow for some flakiness ... + expect(inGroup0).to.be.greaterThan(0); }); async function createEsDocumentsInGroups(groups: number) { From 9de2d815fc2f162469f2390628b9055eb5946c9c Mon Sep 17 00:00:00 2001 From: Oliver Gupte Date: Fri, 20 Mar 2020 18:56:08 -0700 Subject: [PATCH 20/31] [APM] Service Map - Separate overlapping edges by rotating nodes (#60477) * Adds rotation transform which does the top->bottom to left->right transformation + an extra 5 degrees which results in taxi edges separating when rendered. * PR feedback to reduce edge width on hover, and assure that connected edges are highlighted when node is selected/focused * update disabled kuery bar placeholder text for service map --- .../components/app/ServiceMap/Cytoscape.tsx | 62 ++++++++++++++----- .../app/ServiceMap/cytoscapeOptions.ts | 9 ++- .../components/shared/KueryBar/index.tsx | 2 +- 3 files changed, 55 insertions(+), 18 deletions(-) diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Cytoscape.tsx b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Cytoscape.tsx index 3197c269fd90c..e0a188b4915a2 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Cytoscape.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Cytoscape.tsx @@ -57,6 +57,20 @@ function useCytoscape(options: cytoscape.CytoscapeOptions) { return [ref, cy] as [React.MutableRefObject, cytoscape.Core | undefined]; } +function rotatePoint( + { x, y }: { x: number; y: number }, + degreesRotated: number +) { + const radiansPerDegree = Math.PI / 180; + const θ = radiansPerDegree * degreesRotated; + const cosθ = Math.cos(θ); + const sinθ = Math.sin(θ); + return { + x: x * cosθ - y * sinθ, + y: x * sinθ + y * cosθ + }; +} + function getLayoutOptions( selectedRoots: string[], height: number, @@ -71,10 +85,11 @@ function getLayoutOptions( animate: true, animationEasing: animationOptions.easing, animationDuration: animationOptions.duration, - // Rotate nodes from top -> bottom to display left -> right // @ts-ignore - transform: (node: any, { x, y }: cytoscape.Position) => ({ x: y, y: -x }), - // swap width/height of boundingBox to compensation for the rotation + // Rotate nodes counter-clockwise to transform layout from top→bottom to left→right. + // The extra 5° achieves the effect of separating overlapping taxi-styled edges. + transform: (node: any, pos: cytoscape.Position) => rotatePoint(pos, -95), + // swap width/height of boundingBox to compensate for the rotation boundingBox: { x1: 0, y1: 0, w: height, h: width } }; } @@ -109,20 +124,31 @@ export function Cytoscape({ // is required and can trigger rendering when changed. const divStyle = { ...style, height }; - const dataHandler = useCallback( - event => { + const resetConnectedEdgeStyle = useCallback( + (node?: cytoscape.NodeSingular) => { if (cy) { cy.edges().removeClass('highlight'); - if (serviceName) { - const focusedNode = cy.getElementById(serviceName); - focusedNode.connectedEdges().addClass('highlight'); + if (node) { + node.connectedEdges().addClass('highlight'); } + } + }, + [cy] + ); - // Add the "primary" class to the node if its id matches the serviceName. - if (cy.nodes().length > 0 && serviceName) { - cy.nodes().removeClass('primary'); - cy.getElementById(serviceName).addClass('primary'); + const dataHandler = useCallback( + event => { + if (cy) { + if (serviceName) { + resetConnectedEdgeStyle(cy.getElementById(serviceName)); + // Add the "primary" class to the node if its id matches the serviceName. + if (cy.nodes().length > 0) { + cy.nodes().removeClass('primary'); + cy.getElementById(serviceName).addClass('primary'); + } + } else { + resetConnectedEdgeStyle(); } if (event.cy.elements().length > 0) { const selectedRoots = selectRoots(event.cy); @@ -141,7 +167,7 @@ export function Cytoscape({ } } }, - [cy, serviceName, height, width] + [cy, resetConnectedEdgeStyle, serviceName, height, width] ); // Trigger a custom "data" event when data changes @@ -162,12 +188,20 @@ export function Cytoscape({ event.target.removeClass('hover'); event.target.connectedEdges().removeClass('nodeHover'); }; + const selectHandler: cytoscape.EventHandler = event => { + resetConnectedEdgeStyle(event.target); + }; + const unselectHandler: cytoscape.EventHandler = event => { + resetConnectedEdgeStyle(); + }; if (cy) { cy.on('data', dataHandler); cy.ready(dataHandler); cy.on('mouseover', 'edge, node', mouseoverHandler); cy.on('mouseout', 'edge, node', mouseoutHandler); + cy.on('select', 'node', selectHandler); + cy.on('unselect', 'node', unselectHandler); } return () => { @@ -181,7 +215,7 @@ export function Cytoscape({ cy.removeListener('mouseout', 'edge, node', mouseoutHandler); } }; - }, [cy, dataHandler, serviceName]); + }, [cy, dataHandler, resetConnectedEdgeStyle, serviceName]); return ( diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/cytoscapeOptions.ts b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/cytoscapeOptions.ts index 30b36b58cb001..e19cb8ae4b646 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/cytoscapeOptions.ts +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/cytoscapeOptions.ts @@ -121,15 +121,18 @@ const style: cytoscape.Stylesheet[] = [ { selector: 'edge.nodeHover', style: { - width: 4, + width: 2, // @ts-ignore - 'z-index': zIndexEdgeHover + 'z-index': zIndexEdgeHover, + 'line-color': theme.euiColorDarkShade, + 'source-arrow-color': theme.euiColorDarkShade, + 'target-arrow-color': theme.euiColorDarkShade } }, { selector: 'node.hover', style: { - 'border-width': 4 + 'border-width': 2 } }, { diff --git a/x-pack/legacy/plugins/apm/public/components/shared/KueryBar/index.tsx b/x-pack/legacy/plugins/apm/public/components/shared/KueryBar/index.tsx index bea1de18384a3..dba31822dd23e 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/KueryBar/index.tsx +++ b/x-pack/legacy/plugins/apm/public/components/shared/KueryBar/index.tsx @@ -79,7 +79,7 @@ export function KueryBar() { const disabled = /\/service-map$/.test(location.pathname); const disabledPlaceholder = i18n.translate( 'xpack.apm.kueryBar.disabledPlaceholder', - { defaultMessage: 'Search is not available for service maps' } + { defaultMessage: 'Search is not available for service map' } ); async function onChange(inputValue: string, selectionStart: number) { From 9e911469a3e45bc6c9a1b1f28221e022591c19c8 Mon Sep 17 00:00:00 2001 From: Ryland Herrick Date: Fri, 20 Mar 2020 21:32:51 -0500 Subject: [PATCH 21/31] [SIEM] Fix patching of ML Rules (#60830) * Allow ML Rules to be patched * Test passing of params from our patch routes to our helpers Since patchRules accepts a partial there's no way to verify this in typescript, we need regression tests instead. * Update lists when importing with overwrite This was simply missed earlier. Co-authored-by: Elastic Machine --- .../routes/rules/import_rules_route.ts | 1 + .../rules/patch_rules_bulk_route.test.ts | 26 +++++++++++++++++++ .../routes/rules/patch_rules_bulk_route.ts | 4 +++ .../routes/rules/patch_rules_route.test.ts | 24 +++++++++++++++++ .../routes/rules/patch_rules_route.ts | 4 +++ 5 files changed, 59 insertions(+) diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/import_rules_route.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/import_rules_route.ts index 72a6e70cbb14a..4a5ea33025d49 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/import_rules_route.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/import_rules_route.ts @@ -234,6 +234,7 @@ export const importRulesRoute = (router: IRouter, config: LegacyServices['config references, note, version, + lists, anomalyThreshold, machineLearningJobId, }); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/patch_rules_bulk_route.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/patch_rules_bulk_route.test.ts index 4c980c8cc60d2..4c00cfa51c8ee 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/patch_rules_bulk_route.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/patch_rules_bulk_route.test.ts @@ -56,6 +56,32 @@ describe('patch_rules_bulk', () => { ]); }); + test('allows ML Params to be patched', async () => { + const request = requestMock.create({ + method: 'patch', + path: `${DETECTION_ENGINE_RULES_URL}/bulk_update`, + body: [ + { + rule_id: 'my-rule-id', + anomaly_threshold: 4, + machine_learning_job_id: 'some_job_id', + }, + ], + }); + await server.inject(request, context); + + expect(clients.alertsClient.update).toHaveBeenCalledWith( + expect.objectContaining({ + data: expect.objectContaining({ + params: expect.objectContaining({ + anomalyThreshold: 4, + machineLearningJobId: 'some_job_id', + }), + }), + }) + ); + }); + test('returns 404 if alertClient is not available on the route', async () => { context.alerting!.getAlertsClient = jest.fn(); const response = await server.inject(getPatchBulkRequest(), context); diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/patch_rules_bulk_route.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/patch_rules_bulk_route.ts index 698f58438a5e6..a80f3fee6b433 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/patch_rules_bulk_route.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/patch_rules_bulk_route.ts @@ -75,6 +75,8 @@ export const patchRulesBulkRoute = (router: IRouter) => { references, note, version, + anomaly_threshold: anomalyThreshold, + machine_learning_job_id: machineLearningJobId, } = payloadRule; const idOrRuleIdOrUnknown = id ?? ruleId ?? '(unknown id)'; try { @@ -111,6 +113,8 @@ export const patchRulesBulkRoute = (router: IRouter) => { references, note, version, + anomalyThreshold, + machineLearningJobId, }); if (rule != null) { const ruleStatuses = await savedObjectsClient.find< diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/patch_rules_route.test.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/patch_rules_route.test.ts index b92c18827557c..07519733db291 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/patch_rules_route.test.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/patch_rules_route.test.ts @@ -85,6 +85,30 @@ describe('patch_rules', () => { status_code: 500, }); }); + + test('allows ML Params to be patched', async () => { + const request = requestMock.create({ + method: 'patch', + path: DETECTION_ENGINE_RULES_URL, + body: { + rule_id: 'my-rule-id', + anomaly_threshold: 4, + machine_learning_job_id: 'some_job_id', + }, + }); + await server.inject(request, context); + + expect(clients.alertsClient.update).toHaveBeenCalledWith( + expect.objectContaining({ + data: expect.objectContaining({ + params: expect.objectContaining({ + anomalyThreshold: 4, + machineLearningJobId: 'some_job_id', + }), + }), + }) + ); + }); }); describe('request validation', () => { diff --git a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/patch_rules_route.ts b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/patch_rules_route.ts index 4493bb380d03d..c5ecb109f4595 100644 --- a/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/patch_rules_route.ts +++ b/x-pack/legacy/plugins/siem/server/lib/detection_engine/routes/rules/patch_rules_route.ts @@ -59,6 +59,8 @@ export const patchRulesRoute = (router: IRouter) => { references, note, version, + anomaly_threshold: anomalyThreshold, + machine_learning_job_id: machineLearningJobId, } = request.body; const siemResponse = buildSiemResponse(response); @@ -108,6 +110,8 @@ export const patchRulesRoute = (router: IRouter) => { references, note, version, + anomalyThreshold, + machineLearningJobId, }); if (rule != null) { const ruleStatuses = await savedObjectsClient.find< From 0390251f6972009b11d178041456240d6187b81b Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Fri, 20 Mar 2020 21:29:06 -0700 Subject: [PATCH 22/31] Fixed UI/UX issues: alerts delete confirmation, combobox behaviors (#60703) * Fixed UI/UX issues: alerts delete confirmation * Fixed 4. Popover disappears when clearing the field selector * Fixed tests * Fixed due to comments * fixed tests * Fixed test --- .../components/delete_connectors_modal.tsx | 91 --------------- .../components/delete_modal_confirmation.tsx | 105 ++++++++++++++++++ .../public/application/lib/alert_api.test.ts | 16 +-- .../public/application/lib/alert_api.ts | 18 ++- .../components/actions_connectors_list.tsx | 53 +++++---- .../alerts_list/components/alerts_list.tsx | 46 +++++++- .../components/collapsed_item_actions.tsx | 8 +- .../components/alert_quick_edit_buttons.tsx | 5 +- .../with_bulk_alert_api_operations.test.tsx | 4 +- .../with_bulk_alert_api_operations.tsx | 17 ++- .../public/common/expression_items/of.tsx | 4 +- .../apps/triggers_actions_ui/alerts.ts | 21 +++- .../apps/triggers_actions_ui/connectors.ts | 12 +- 13 files changed, 242 insertions(+), 158 deletions(-) delete mode 100644 x-pack/plugins/triggers_actions_ui/public/application/components/delete_connectors_modal.tsx create mode 100644 x-pack/plugins/triggers_actions_ui/public/application/components/delete_modal_confirmation.tsx diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/delete_connectors_modal.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/delete_connectors_modal.tsx deleted file mode 100644 index b7d1a4ffe2966..0000000000000 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/delete_connectors_modal.tsx +++ /dev/null @@ -1,91 +0,0 @@ -/* - * 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. - */ -import { EuiConfirmModal, EuiOverlayMask } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import React from 'react'; -import { useAppDependencies } from '../app_context'; -import { deleteActions } from '../lib/action_connector_api'; - -export const DeleteConnectorsModal = ({ - connectorsToDelete, - callback, -}: { - connectorsToDelete: string[]; - callback: (deleted?: string[]) => void; -}) => { - const { http, toastNotifications } = useAppDependencies(); - const numConnectorsToDelete = connectorsToDelete.length; - if (!numConnectorsToDelete) { - return null; - } - const confirmModalText = i18n.translate( - 'xpack.triggersActionsUI.deleteSelectedConnectorsConfirmModal.descriptionText', - { - defaultMessage: - "You can't recover {numConnectorsToDelete, plural, one {a deleted connector} other {deleted connectors}}.", - values: { numConnectorsToDelete }, - } - ); - const confirmButtonText = i18n.translate( - 'xpack.triggersActionsUI.deleteSelectedConnectorsConfirmModal.deleteButtonLabel', - { - defaultMessage: - 'Delete {numConnectorsToDelete, plural, one {connector} other {# connectors}} ', - values: { numConnectorsToDelete }, - } - ); - const cancelButtonText = i18n.translate( - 'xpack.triggersActionsUI.deleteSelectedConnectorsConfirmModal.cancelButtonLabel', - { - defaultMessage: 'Cancel', - } - ); - return ( - - callback()} - onConfirm={async () => { - const { successes, errors } = await deleteActions({ ids: connectorsToDelete, http }); - const numSuccesses = successes.length; - const numErrors = errors.length; - callback(successes); - if (numSuccesses > 0) { - toastNotifications.addSuccess( - i18n.translate( - 'xpack.triggersActionsUI.sections.connectorsList.deleteSelectedConnectorsSuccessNotification.descriptionText', - { - defaultMessage: - 'Deleted {numSuccesses, number} {numSuccesses, plural, one {connector} other {connectors}}', - values: { numSuccesses }, - } - ) - ); - } - - if (numErrors > 0) { - toastNotifications.addDanger( - i18n.translate( - 'xpack.triggersActionsUI.sections.connectorsList.deleteSelectedConnectorsErrorNotification.descriptionText', - { - defaultMessage: - 'Failed to delete {numErrors, number} {numErrors, plural, one {connector} other {connectors}}', - values: { numErrors }, - } - ) - ); - } - }} - cancelButtonText={cancelButtonText} - confirmButtonText={confirmButtonText} - > - {confirmModalText} - - - ); -}; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/delete_modal_confirmation.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/delete_modal_confirmation.tsx new file mode 100644 index 0000000000000..80b59e15644ec --- /dev/null +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/delete_modal_confirmation.tsx @@ -0,0 +1,105 @@ +/* + * 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. + */ +import { EuiConfirmModal, EuiOverlayMask } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import React from 'react'; +import { HttpSetup } from 'kibana/public'; +import { useAppDependencies } from '../app_context'; + +export const DeleteModalConfirmation = ({ + idsToDelete, + apiDeleteCall, + onDeleted, + onCancel, + singleTitle, + multipleTitle, +}: { + idsToDelete: string[]; + apiDeleteCall: ({ + ids, + http, + }: { + ids: string[]; + http: HttpSetup; + }) => Promise<{ successes: string[]; errors: string[] }>; + onDeleted: (deleted: string[]) => void; + onCancel: () => void; + singleTitle: string; + multipleTitle: string; +}) => { + const { http, toastNotifications } = useAppDependencies(); + const numIdsToDelete = idsToDelete.length; + if (!numIdsToDelete) { + return null; + } + const confirmModalText = i18n.translate( + 'xpack.triggersActionsUI.deleteSelectedIdsConfirmModal.descriptionText', + { + defaultMessage: + "You can't recover {numIdsToDelete, plural, one {a deleted {singleTitle}} other {deleted {multipleTitle}}}.", + values: { numIdsToDelete, singleTitle, multipleTitle }, + } + ); + const confirmButtonText = i18n.translate( + 'xpack.triggersActionsUI.deleteSelectedIdsConfirmModal.deleteButtonLabel', + { + defaultMessage: + 'Delete {numIdsToDelete, plural, one {{singleTitle}} other {# {multipleTitle}}} ', + values: { numIdsToDelete, singleTitle, multipleTitle }, + } + ); + const cancelButtonText = i18n.translate( + 'xpack.triggersActionsUI.deleteSelectedIdsConfirmModal.cancelButtonLabel', + { + defaultMessage: 'Cancel', + } + ); + return ( + + onCancel()} + onConfirm={async () => { + const { successes, errors } = await apiDeleteCall({ ids: idsToDelete, http }); + const numSuccesses = successes.length; + const numErrors = errors.length; + onDeleted(successes); + if (numSuccesses > 0) { + toastNotifications.addSuccess( + i18n.translate( + 'xpack.triggersActionsUI.components.deleteSelectedIdsSuccessNotification.descriptionText', + { + defaultMessage: + 'Deleted {numSuccesses, number} {numSuccesses, plural, one {{singleTitle}} other {{multipleTitle}}}', + values: { numSuccesses, singleTitle, multipleTitle }, + } + ) + ); + } + + if (numErrors > 0) { + toastNotifications.addDanger( + i18n.translate( + 'xpack.triggersActionsUI.components.deleteSelectedIdsErrorNotification.descriptionText', + { + defaultMessage: + 'Failed to delete {numErrors, number} {numErrors, plural, one {{singleTitle}} other {{multipleTitle}}}', + values: { numErrors, singleTitle, multipleTitle }, + } + ) + ); + } + }} + cancelButtonText={cancelButtonText} + confirmButtonText={confirmButtonText} + > + {confirmModalText} + + + ); +}; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api.test.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api.test.ts index 0555823d0245e..453fbc4a9eb4f 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api.test.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api.test.ts @@ -8,7 +8,6 @@ import { Alert, AlertType } from '../../types'; import { httpServiceMock } from '../../../../../../src/core/public/mocks'; import { createAlert, - deleteAlert, deleteAlerts, disableAlerts, enableAlerts, @@ -347,24 +346,11 @@ describe('loadAlerts', () => { }); }); -describe('deleteAlert', () => { - test('should call delete API for alert', async () => { - const id = '1'; - const result = await deleteAlert({ http, id }); - expect(result).toEqual(undefined); - expect(http.delete.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - "/api/alert/1", - ] - `); - }); -}); - describe('deleteAlerts', () => { test('should call delete API for each alert', async () => { const ids = ['1', '2', '3']; const result = await deleteAlerts({ http, ids }); - expect(result).toEqual(undefined); + expect(result).toEqual({ errors: [], successes: [undefined, undefined, undefined] }); expect(http.delete.mock.calls).toMatchInlineSnapshot(` Array [ Array [ diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api.ts index 1b18460ba11cb..359c48850549a 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api.ts @@ -93,18 +93,24 @@ export async function loadAlerts({ }); } -export async function deleteAlert({ id, http }: { id: string; http: HttpSetup }): Promise { - await http.delete(`${BASE_ALERT_API_PATH}/${id}`); -} - export async function deleteAlerts({ ids, http, }: { ids: string[]; http: HttpSetup; -}): Promise { - await Promise.all(ids.map(id => deleteAlert({ http, id }))); +}): Promise<{ successes: string[]; errors: string[] }> { + const successes: string[] = []; + const errors: string[] = []; + await Promise.all(ids.map(id => http.delete(`${BASE_ALERT_API_PATH}/${id}`))).then( + function(fulfilled) { + successes.push(...fulfilled); + }, + function(rejected) { + errors.push(...rejected); + } + ); + return { successes, errors }; } export async function createAlert({ diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx index c023f9087d70e..8c2565538f718 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx @@ -20,10 +20,10 @@ import { import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { useAppDependencies } from '../../../app_context'; -import { loadAllActions, loadActionTypes } from '../../../lib/action_connector_api'; +import { loadAllActions, loadActionTypes, deleteActions } from '../../../lib/action_connector_api'; import { ConnectorAddFlyout, ConnectorEditFlyout } from '../../action_connector_form'; import { hasDeleteActionsCapability, hasSaveActionsCapability } from '../../../lib/capabilities'; -import { DeleteConnectorsModal } from '../../../components/delete_connectors_modal'; +import { DeleteModalConfirmation } from '../../../components/delete_modal_confirmation'; import { ActionsConnectorsContextProvider } from '../../../context/actions_connectors_context'; import { checkActionTypeEnabled } from '../../../lib/check_action_type_enabled'; import './actions_connectors_list.scss'; @@ -378,29 +378,38 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { return (
- { - if (deleted) { - if (selectedItems.length === 0 || selectedItems.length === deleted.length) { - const updatedActions = actions.filter( - action => action.id && !connectorsToDelete.includes(action.id) - ); - setActions(updatedActions); - setSelectedItems([]); - } else { - toastNotifications.addDanger({ - title: i18n.translate( - 'xpack.triggersActionsUI.sections.actionsConnectorsList.failedToDeleteActionsMessage', - { defaultMessage: 'Failed to delete action(s)' } - ), - }); - // Refresh the actions from the server, some actions may have beend deleted - loadActions(); - } + { + if (selectedItems.length === 0 || selectedItems.length === deleted.length) { + const updatedActions = actions.filter( + action => action.id && !connectorsToDelete.includes(action.id) + ); + setActions(updatedActions); + setSelectedItems([]); } setConnectorsToDelete([]); }} - connectorsToDelete={connectorsToDelete} + onCancel={async () => { + toastNotifications.addDanger({ + title: i18n.translate( + 'xpack.triggersActionsUI.sections.actionsConnectorsList.failedToDeleteActionsMessage', + { defaultMessage: 'Failed to delete action(s)' } + ), + }); + // Refresh the actions from the server, some actions may have beend deleted + await loadActions(); + setConnectorsToDelete([]); + }} + apiDeleteCall={deleteActions} + idsToDelete={connectorsToDelete} + singleTitle={i18n.translate( + 'xpack.triggersActionsUI.sections.actionsConnectorsList.singleTitle', + { defaultMessage: 'connector' } + )} + multipleTitle={i18n.translate( + 'xpack.triggersActionsUI.sections.actionsConnectorsList.multipleTitle', + { defaultMessage: 'connectors' } + )} /> {/* Render the view based on if there's data or if they can save */} diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx index 18e79a1d93a10..84e4d5794859c 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.tsx @@ -31,10 +31,11 @@ import { AlertQuickEditButtonsWithApi as AlertQuickEditButtons } from '../../com import { CollapsedItemActionsWithApi as CollapsedItemActions } from './collapsed_item_actions'; import { TypeFilter } from './type_filter'; import { ActionTypeFilter } from './action_type_filter'; -import { loadAlerts, loadAlertTypes } from '../../../lib/alert_api'; +import { loadAlerts, loadAlertTypes, deleteAlerts } from '../../../lib/alert_api'; import { loadActionTypes } from '../../../lib/action_connector_api'; import { hasDeleteAlertsCapability, hasSaveAlertsCapability } from '../../../lib/capabilities'; import { routeToAlertDetails, DEFAULT_SEARCH_PAGE_SIZE } from '../../../constants'; +import { DeleteModalConfirmation } from '../../../components/delete_modal_confirmation'; const ENTER_KEY = 13; @@ -85,6 +86,7 @@ export const AlertsList: React.FunctionComponent = () => { }); const [editedAlertItem, setEditedAlertItem] = useState(undefined); const [editFlyoutVisible, setEditFlyoutVisibility] = useState(false); + const [alertsToDelete, setAlertsToDelete] = useState([]); useEffect(() => { loadAlertsData(); @@ -242,7 +244,12 @@ export const AlertsList: React.FunctionComponent = () => { width: '40px', render(item: AlertTableItem) { return ( - loadAlertsData()} /> + loadAlertsData()} + setAlertsToDelete={setAlertsToDelete} + /> ); }, }, @@ -338,6 +345,7 @@ export const AlertsList: React.FunctionComponent = () => { loadAlertsData(); setIsPerformingAction(false); }} + setAlertsToDelete={setAlertsToDelete} /> @@ -422,6 +430,40 @@ export const AlertsList: React.FunctionComponent = () => { return (
+ { + if (selectedIds.length === 0 || selectedIds.length === deleted.length) { + const updatedAlerts = alertsState.data.filter( + alert => alert.id && !alertsToDelete.includes(alert.id) + ); + setAlertsState({ + isLoading: false, + data: updatedAlerts, + totalItemCount: alertsState.totalItemCount - deleted.length, + }); + setSelectedIds([]); + } + setAlertsToDelete([]); + }} + onCancel={async () => { + toastNotifications.addDanger({ + title: i18n.translate( + 'xpack.triggersActionsUI.sections.alertsList.failedToDeleteAlertsMessage', + { defaultMessage: 'Failed to delete alert(s)' } + ), + }); + // Refresh the alerts from the server, some alerts may have beend deleted + await loadAlertsData(); + }} + apiDeleteCall={deleteAlerts} + idsToDelete={alertsToDelete} + singleTitle={i18n.translate('xpack.triggersActionsUI.sections.alertsList.singleTitle', { + defaultMessage: 'alert', + })} + multipleTitle={i18n.translate('xpack.triggersActionsUI.sections.alertsList.multipleTitle', { + defaultMessage: 'alerts', + })} + /> {loadedItems.length || isFilterApplied ? ( table diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/collapsed_item_actions.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/collapsed_item_actions.tsx index 2bac159ed79ed..694f99251d26b 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/collapsed_item_actions.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/collapsed_item_actions.tsx @@ -27,6 +27,7 @@ import { export type ComponentOpts = { item: AlertTableItem; onAlertChanged: () => void; + setAlertsToDelete: React.Dispatch>; } & BulkOperationsComponentOpts; export const CollapsedItemActions: React.FunctionComponent = ({ @@ -36,7 +37,7 @@ export const CollapsedItemActions: React.FunctionComponent = ({ enableAlert, unmuteAlert, muteAlert, - deleteAlert, + setAlertsToDelete, }: ComponentOpts) => { const { capabilities } = useAppDependencies(); @@ -116,10 +117,7 @@ export const CollapsedItemActions: React.FunctionComponent = ({ iconType="trash" color="text" data-test-subj="deleteAlert" - onClick={async () => { - await deleteAlert(item); - onAlertChanged(); - }} + onClick={() => setAlertsToDelete([item.id])} > void; onActionPerformed?: () => void; + setAlertsToDelete: React.Dispatch>; } & BulkOperationsComponentOpts; export const AlertQuickEditButtons: React.FunctionComponent = ({ @@ -30,7 +31,7 @@ export const AlertQuickEditButtons: React.FunctionComponent = ({ unmuteAlerts, enableAlerts, disableAlerts, - deleteAlerts, + setAlertsToDelete, }: ComponentOpts) => { const { toastNotifications } = useAppDependencies(); @@ -129,7 +130,7 @@ export const AlertQuickEditButtons: React.FunctionComponent = ({ onPerformingAction(); setIsDeletingAlerts(true); try { - await deleteAlerts(selectedItems); + setAlertsToDelete(selectedItems.map((selected: any) => selected.id)); } catch (e) { toastNotifications.addDanger({ title: i18n.translate( diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/with_bulk_alert_api_operations.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/with_bulk_alert_api_operations.test.tsx index 30a065479ce33..074e2d5147b5e 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/with_bulk_alert_api_operations.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/with_bulk_alert_api_operations.test.tsx @@ -125,8 +125,8 @@ describe('with_bulk_alert_api_operations', () => { const component = mount(); component.find('button').simulate('click'); - expect(alertApi.deleteAlert).toHaveBeenCalledTimes(1); - expect(alertApi.deleteAlert).toHaveBeenCalledWith({ id: alert.id, http }); + expect(alertApi.deleteAlerts).toHaveBeenCalledTimes(1); + expect(alertApi.deleteAlerts).toHaveBeenCalledWith({ ids: [alert.id], http }); }); // bulk alerts diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/with_bulk_alert_api_operations.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/with_bulk_alert_api_operations.tsx index 4b348b85fe5bc..0ba590ab462a7 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/with_bulk_alert_api_operations.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/with_bulk_alert_api_operations.tsx @@ -14,7 +14,6 @@ import { enableAlerts, muteAlerts, unmuteAlerts, - deleteAlert, disableAlert, enableAlert, muteAlert, @@ -31,14 +30,24 @@ export interface ComponentOpts { unmuteAlerts: (alerts: Alert[]) => Promise; enableAlerts: (alerts: Alert[]) => Promise; disableAlerts: (alerts: Alert[]) => Promise; - deleteAlerts: (alerts: Alert[]) => Promise; + deleteAlerts: ( + alerts: Alert[] + ) => Promise<{ + successes: string[]; + errors: string[]; + }>; muteAlert: (alert: Alert) => Promise; unmuteAlert: (alert: Alert) => Promise; muteAlertInstance: (alert: Alert, alertInstanceId: string) => Promise; unmuteAlertInstance: (alert: Alert, alertInstanceId: string) => Promise; enableAlert: (alert: Alert) => Promise; disableAlert: (alert: Alert) => Promise; - deleteAlert: (alert: Alert) => Promise; + deleteAlert: ( + alert: Alert + ) => Promise<{ + successes: string[]; + errors: string[]; + }>; loadAlert: (id: Alert['id']) => Promise; loadAlertState: (id: Alert['id']) => Promise; loadAlertTypes: () => Promise; @@ -102,7 +111,7 @@ export function withBulkAlertOperations( return disableAlert({ http, id: alert.id }); } }} - deleteAlert={async (alert: Alert) => deleteAlert({ http, id: alert.id })} + deleteAlert={async (alert: Alert) => deleteAlerts({ http, ids: [alert.id] })} loadAlert={async (alertId: Alert['id']) => loadAlert({ http, alertId })} loadAlertState={async (alertId: Alert['id']) => loadAlertState({ http, alertId })} loadAlertTypes={async () => loadAlertTypes({ http })} diff --git a/x-pack/plugins/triggers_actions_ui/public/common/expression_items/of.tsx b/x-pack/plugins/triggers_actions_ui/public/common/expression_items/of.tsx index 954e584d52a87..fdf68cc49572f 100644 --- a/x-pack/plugins/triggers_actions_ui/public/common/expression_items/of.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/common/expression_items/of.tsx @@ -125,7 +125,9 @@ export const OfExpression = ({ onChangeSelectedAggField( selectedOptions.length === 1 ? selectedOptions[0].label : undefined ); - setAggFieldPopoverOpen(false); + if (selectedOptions.length > 0) { + setAggFieldPopoverOpen(false); + } }} /> diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts.ts index b4dd3bb5baa51..7e5825d88ec13 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts.ts @@ -332,6 +332,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); it('should delete single alert', async () => { + await createAlert(); const createdAlert = await createAlert(); await pageObjects.common.navigateToApp('triggersActions'); await pageObjects.triggersActionsUI.searchAlerts(createdAlert.name); @@ -339,8 +340,16 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await testSubjects.click('collapsedItemActions'); await testSubjects.click('deleteAlert'); + await testSubjects.existOrFail('deleteIdsConfirmation'); + await testSubjects.click('deleteIdsConfirmation > confirmModalConfirmButton'); + await testSubjects.missingOrFail('deleteIdsConfirmation'); - expect(await pageObjects.triggersActionsUI.isAnEmptyAlertsListDisplayed()).to.be(true); + const toastTitle = await pageObjects.common.closeToast(); + expect(toastTitle).to.eql('Deleted 1 alert'); + await pageObjects.common.navigateToApp('triggersActions'); + await pageObjects.triggersActionsUI.searchAlerts(createdAlert.name); + const searchResultsAfterDelete = await pageObjects.triggersActionsUI.getAlertsList(); + expect(searchResultsAfterDelete.length).to.eql(0); }); it('should mute all selection', async () => { @@ -449,8 +458,16 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await testSubjects.click('bulkAction'); await testSubjects.click('deleteAll'); + await testSubjects.existOrFail('deleteIdsConfirmation'); + await testSubjects.click('deleteIdsConfirmation > confirmModalConfirmButton'); + await testSubjects.missingOrFail('deleteIdsConfirmation'); - expect(await pageObjects.triggersActionsUI.isAnEmptyAlertsListDisplayed()).to.be(true); + await pageObjects.common.closeToast(); + + await pageObjects.common.navigateToApp('triggersActions'); + await pageObjects.triggersActionsUI.searchAlerts(createdAlert.name); + const searchResultsAfterDelete = await pageObjects.triggersActionsUI.getAlertsList(); + expect(searchResultsAfterDelete.length).to.eql(0); }); }); }; diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts index 9d656b08a3abd..c2013ba3502e2 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts @@ -123,9 +123,9 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { expect(searchResultsBeforeDelete.length).to.eql(1); await testSubjects.click('deleteConnector'); - await testSubjects.existOrFail('deleteConnectorsConfirmation'); - await testSubjects.click('deleteConnectorsConfirmation > confirmModalConfirmButton'); - await testSubjects.missingOrFail('deleteConnectorsConfirmation'); + await testSubjects.existOrFail('deleteIdsConfirmation'); + await testSubjects.click('deleteIdsConfirmation > confirmModalConfirmButton'); + await testSubjects.missingOrFail('deleteIdsConfirmation'); const toastTitle = await pageObjects.common.closeToast(); expect(toastTitle).to.eql('Deleted 1 connector'); @@ -164,9 +164,9 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await find.clickByCssSelector('.euiTableRowCellCheckbox .euiCheckbox__input'); await testSubjects.click('bulkDelete'); - await testSubjects.existOrFail('deleteConnectorsConfirmation'); - await testSubjects.click('deleteConnectorsConfirmation > confirmModalConfirmButton'); - await testSubjects.missingOrFail('deleteConnectorsConfirmation'); + await testSubjects.existOrFail('deleteIdsConfirmation'); + await testSubjects.click('deleteIdsConfirmation > confirmModalConfirmButton'); + await testSubjects.missingOrFail('deleteIdsConfirmation'); const toastTitle = await pageObjects.common.closeToast(); expect(toastTitle).to.eql('Deleted 1 connector'); From 8ccaa2e62fdeafd94dae292eed9622e5658fc3a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loix?= Date: Sat, 21 Mar 2020 17:01:01 +0100 Subject: [PATCH 23/31] [Index management] Re-enable index template tests (#60780) --- .../client_integration/helpers/constants.ts | 32 ++ .../helpers/home.helpers.ts | 173 ++++++ .../helpers/http_requests.ts | 96 ++++ .../client_integration/helpers/index.ts | 21 + .../helpers/setup_environment.tsx | 57 ++ .../helpers/template_clone.helpers.ts | 24 + .../helpers/template_create.helpers.ts | 26 + .../helpers/template_edit.helpers.ts | 24 + .../helpers/template_form.helpers.ts | 241 +++++++++ .../__jest__/client_integration/home.test.ts | 508 ++++++++++++++++++ .../template_clone.test.tsx | 123 +++++ .../template_create.test.tsx | 387 +++++++++++++ .../client_integration/template_edit.test.tsx | 210 ++++++++ 13 files changed, 1922 insertions(+) create mode 100644 x-pack/plugins/index_management/__jest__/client_integration/helpers/constants.ts create mode 100644 x-pack/plugins/index_management/__jest__/client_integration/helpers/home.helpers.ts create mode 100644 x-pack/plugins/index_management/__jest__/client_integration/helpers/http_requests.ts create mode 100644 x-pack/plugins/index_management/__jest__/client_integration/helpers/index.ts create mode 100644 x-pack/plugins/index_management/__jest__/client_integration/helpers/setup_environment.tsx create mode 100644 x-pack/plugins/index_management/__jest__/client_integration/helpers/template_clone.helpers.ts create mode 100644 x-pack/plugins/index_management/__jest__/client_integration/helpers/template_create.helpers.ts create mode 100644 x-pack/plugins/index_management/__jest__/client_integration/helpers/template_edit.helpers.ts create mode 100644 x-pack/plugins/index_management/__jest__/client_integration/helpers/template_form.helpers.ts create mode 100644 x-pack/plugins/index_management/__jest__/client_integration/home.test.ts create mode 100644 x-pack/plugins/index_management/__jest__/client_integration/template_clone.test.tsx create mode 100644 x-pack/plugins/index_management/__jest__/client_integration/template_create.test.tsx create mode 100644 x-pack/plugins/index_management/__jest__/client_integration/template_edit.test.tsx diff --git a/x-pack/plugins/index_management/__jest__/client_integration/helpers/constants.ts b/x-pack/plugins/index_management/__jest__/client_integration/helpers/constants.ts new file mode 100644 index 0000000000000..3f6e5d7d4dab2 --- /dev/null +++ b/x-pack/plugins/index_management/__jest__/client_integration/helpers/constants.ts @@ -0,0 +1,32 @@ +/* + * 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. + */ + +export const TEMPLATE_NAME = 'my_template'; + +export const INDEX_PATTERNS = ['my_index_pattern']; + +export const SETTINGS = { + number_of_shards: 1, + index: { + lifecycle: { + name: 'my_policy', + }, + }, +}; + +export const ALIASES = { + alias: { + filter: { + term: { user: 'my_user' }, + }, + }, +}; + +export const MAPPINGS = { + _source: {}, + _meta: {}, + properties: {}, +}; diff --git a/x-pack/plugins/index_management/__jest__/client_integration/helpers/home.helpers.ts b/x-pack/plugins/index_management/__jest__/client_integration/helpers/home.helpers.ts new file mode 100644 index 0000000000000..7e3e1fba9c44a --- /dev/null +++ b/x-pack/plugins/index_management/__jest__/client_integration/helpers/home.helpers.ts @@ -0,0 +1,173 @@ +/* + * 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. + */ + +import { ReactWrapper } from 'enzyme'; +import { act } from 'react-dom/test-utils'; +import { + registerTestBed, + TestBed, + TestBedConfig, + findTestSubject, + nextTick, +} from '../../../../../test_utils'; +import { IndexManagementHome } from '../../../public/application/sections/home'; // eslint-disable-line @kbn/eslint/no-restricted-paths +import { BASE_PATH } from '../../../common/constants'; +import { indexManagementStore } from '../../../public/application/store'; // eslint-disable-line @kbn/eslint/no-restricted-paths +import { Template } from '../../../common/types'; +import { WithAppDependencies, services } from './setup_environment'; + +const testBedConfig: TestBedConfig = { + store: () => indexManagementStore(services as any), + memoryRouter: { + initialEntries: [`${BASE_PATH}indices`], + componentRoutePath: `${BASE_PATH}:section(indices|templates)`, + }, + doMountAsync: true, +}; + +const initTestBed = registerTestBed(WithAppDependencies(IndexManagementHome), testBedConfig); + +export interface IdxMgmtHomeTestBed extends TestBed { + findAction: (action: 'edit' | 'clone' | 'delete') => ReactWrapper; + actions: { + selectHomeTab: (tab: 'indicesTab' | 'templatesTab') => void; + selectDetailsTab: (tab: 'summary' | 'settings' | 'mappings' | 'aliases') => void; + clickReloadButton: () => void; + clickTemplateAction: (name: Template['name'], action: 'edit' | 'clone' | 'delete') => void; + clickTemplateAt: (index: number) => void; + clickCloseDetailsButton: () => void; + clickActionMenu: (name: Template['name']) => void; + }; +} + +export const setup = async (): Promise => { + const testBed = await initTestBed(); + + /** + * Additional helpers + */ + const findAction = (action: 'edit' | 'clone' | 'delete') => { + const actions = ['edit', 'clone', 'delete']; + const { component } = testBed; + + return component.find('.euiContextMenuItem').at(actions.indexOf(action)); + }; + + /** + * User Actions + */ + + const selectHomeTab = (tab: 'indicesTab' | 'templatesTab') => { + testBed.find(tab).simulate('click'); + }; + + const selectDetailsTab = (tab: 'summary' | 'settings' | 'mappings' | 'aliases') => { + const tabs = ['summary', 'settings', 'mappings', 'aliases']; + + testBed + .find('templateDetails.tab') + .at(tabs.indexOf(tab)) + .simulate('click'); + }; + + const clickReloadButton = () => { + const { find } = testBed; + find('reloadButton').simulate('click'); + }; + + const clickActionMenu = async (templateName: Template['name']) => { + const { component } = testBed; + + // When a table has > 2 actions, EUI displays an overflow menu with an id "-actions" + // The template name may contain a period (.) so we use bracket syntax for selector + component.find(`div[id="${templateName}-actions"] button`).simulate('click'); + }; + + const clickTemplateAction = ( + templateName: Template['name'], + action: 'edit' | 'clone' | 'delete' + ) => { + const actions = ['edit', 'clone', 'delete']; + const { component } = testBed; + + clickActionMenu(templateName); + + component + .find('.euiContextMenuItem') + .at(actions.indexOf(action)) + .simulate('click'); + }; + + const clickTemplateAt = async (index: number) => { + const { component, table, router } = testBed; + const { rows } = table.getMetaData('templateTable'); + const templateLink = findTestSubject(rows[index].reactWrapper, 'templateDetailsLink'); + + await act(async () => { + const { href } = templateLink.props(); + router.navigateTo(href!); + await nextTick(); + component.update(); + }); + }; + + const clickCloseDetailsButton = () => { + const { find } = testBed; + + find('closeDetailsButton').simulate('click'); + }; + + return { + ...testBed, + findAction, + actions: { + selectHomeTab, + selectDetailsTab, + clickReloadButton, + clickTemplateAction, + clickTemplateAt, + clickCloseDetailsButton, + clickActionMenu, + }, + }; +}; + +type IdxMgmtTestSubjects = TestSubjects; + +export type TestSubjects = + | 'aliasesTab' + | 'appTitle' + | 'cell' + | 'closeDetailsButton' + | 'createTemplateButton' + | 'deleteSystemTemplateCallOut' + | 'deleteTemplateButton' + | 'deleteTemplatesConfirmation' + | 'documentationLink' + | 'emptyPrompt' + | 'manageTemplateButton' + | 'mappingsTab' + | 'noAliasesCallout' + | 'noMappingsCallout' + | 'noSettingsCallout' + | 'indicesList' + | 'indicesTab' + | 'reloadButton' + | 'row' + | 'sectionError' + | 'sectionLoading' + | 'settingsTab' + | 'summaryTab' + | 'summaryTitle' + | 'systemTemplatesSwitch' + | 'templateDetails' + | 'templateDetails.manageTemplateButton' + | 'templateDetails.sectionLoading' + | 'templateDetails.tab' + | 'templateDetails.title' + | 'templateList' + | 'templateTable' + | 'templatesTab'; diff --git a/x-pack/plugins/index_management/__jest__/client_integration/helpers/http_requests.ts b/x-pack/plugins/index_management/__jest__/client_integration/helpers/http_requests.ts new file mode 100644 index 0000000000000..e5bce31ee6de1 --- /dev/null +++ b/x-pack/plugins/index_management/__jest__/client_integration/helpers/http_requests.ts @@ -0,0 +1,96 @@ +/* + * 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. + */ + +import sinon, { SinonFakeServer } from 'sinon'; +import { API_BASE_PATH } from '../../../common/constants'; + +type HttpResponse = Record | any[]; + +// Register helpers to mock HTTP Requests +const registerHttpRequestMockHelpers = (server: SinonFakeServer) => { + const setLoadTemplatesResponse = (response: HttpResponse = []) => { + server.respondWith('GET', `${API_BASE_PATH}/templates`, [ + 200, + { 'Content-Type': 'application/json' }, + JSON.stringify(response), + ]); + }; + + const setLoadIndicesResponse = (response: HttpResponse = []) => { + server.respondWith('GET', `${API_BASE_PATH}/indices`, [ + 200, + { 'Content-Type': 'application/json' }, + JSON.stringify(response), + ]); + }; + + const setDeleteTemplateResponse = (response: HttpResponse = []) => { + server.respondWith('DELETE', `${API_BASE_PATH}/templates`, [ + 200, + { 'Content-Type': 'application/json' }, + JSON.stringify(response), + ]); + }; + + const setLoadTemplateResponse = (response?: HttpResponse, error?: any) => { + const status = error ? error.status || 400 : 200; + const body = error ? error.body : response; + + server.respondWith('GET', `${API_BASE_PATH}/templates/:id`, [ + status, + { 'Content-Type': 'application/json' }, + JSON.stringify(body), + ]); + }; + + const setCreateTemplateResponse = (response?: HttpResponse, error?: any) => { + const status = error ? error.body.status || 400 : 200; + const body = error ? JSON.stringify(error.body) : JSON.stringify(response); + + server.respondWith('PUT', `${API_BASE_PATH}/templates`, [ + status, + { 'Content-Type': 'application/json' }, + body, + ]); + }; + + const setUpdateTemplateResponse = (response?: HttpResponse, error?: any) => { + const status = error ? error.status || 400 : 200; + const body = error ? JSON.stringify(error.body) : JSON.stringify(response); + + server.respondWith('PUT', `${API_BASE_PATH}/templates/:name`, [ + status, + { 'Content-Type': 'application/json' }, + body, + ]); + }; + + return { + setLoadTemplatesResponse, + setLoadIndicesResponse, + setDeleteTemplateResponse, + setLoadTemplateResponse, + setCreateTemplateResponse, + setUpdateTemplateResponse, + }; +}; + +export const init = () => { + const server = sinon.fakeServer.create(); + server.respondImmediately = true; + + // Define default response for unhandled requests. + // We make requests to APIs which don't impact the component under test, e.g. UI metric telemetry, + // and we can mock them all with a 200 instead of mocking each one individually. + server.respondWith([200, {}, 'DefaultSinonMockServerResponse']); + + const httpRequestsMockHelpers = registerHttpRequestMockHelpers(server); + + return { + server, + httpRequestsMockHelpers, + }; +}; diff --git a/x-pack/plugins/index_management/__jest__/client_integration/helpers/index.ts b/x-pack/plugins/index_management/__jest__/client_integration/helpers/index.ts new file mode 100644 index 0000000000000..66021b531919a --- /dev/null +++ b/x-pack/plugins/index_management/__jest__/client_integration/helpers/index.ts @@ -0,0 +1,21 @@ +/* + * 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. + */ + +import { setup as homeSetup } from './home.helpers'; +import { setup as templateCreateSetup } from './template_create.helpers'; +import { setup as templateCloneSetup } from './template_clone.helpers'; +import { setup as templateEditSetup } from './template_edit.helpers'; + +export { nextTick, getRandomString, findTestSubject, TestBed } from '../../../../../test_utils'; + +export { setupEnvironment } from './setup_environment'; + +export const pageHelpers = { + home: { setup: homeSetup }, + templateCreate: { setup: templateCreateSetup }, + templateClone: { setup: templateCloneSetup }, + templateEdit: { setup: templateEditSetup }, +}; diff --git a/x-pack/plugins/index_management/__jest__/client_integration/helpers/setup_environment.tsx b/x-pack/plugins/index_management/__jest__/client_integration/helpers/setup_environment.tsx new file mode 100644 index 0000000000000..1eaf7efd17395 --- /dev/null +++ b/x-pack/plugins/index_management/__jest__/client_integration/helpers/setup_environment.tsx @@ -0,0 +1,57 @@ +/* + * 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. + */ +/* eslint-disable @kbn/eslint/no-restricted-paths */ +import React from 'react'; +import axios from 'axios'; +import axiosXhrAdapter from 'axios/lib/adapters/xhr'; + +import { + notificationServiceMock, + docLinksServiceMock, +} from '../../../../../../src/core/public/mocks'; +import { AppContextProvider } from '../../../public/application/app_context'; +import { httpService } from '../../../public/application/services/http'; +import { breadcrumbService } from '../../../public/application/services/breadcrumbs'; +import { documentationService } from '../../../public/application/services/documentation'; +import { notificationService } from '../../../public/application/services/notification'; +import { ExtensionsService } from '../../../public/services'; +import { UiMetricService } from '../../../public/application/services/ui_metric'; +import { setUiMetricService } from '../../../public/application/services/api'; +import { setExtensionsService } from '../../../public/application/store/selectors'; +import { init as initHttpRequests } from './http_requests'; + +const mockHttpClient = axios.create({ adapter: axiosXhrAdapter }); + +export const services = { + extensionsService: new ExtensionsService(), + uiMetricService: new UiMetricService('index_management'), +}; +services.uiMetricService.setup({ reportUiStats() {} } as any); +setExtensionsService(services.extensionsService); +setUiMetricService(services.uiMetricService); +const appDependencies = { services, core: {}, plugins: {} } as any; + +export const setupEnvironment = () => { + // Mock initialization of services + // @ts-ignore + httpService.setup(mockHttpClient); + breadcrumbService.setup(() => undefined); + documentationService.setup(docLinksServiceMock.createStartContract()); + notificationService.setup(notificationServiceMock.createSetupContract()); + + const { server, httpRequestsMockHelpers } = initHttpRequests(); + + return { + server, + httpRequestsMockHelpers, + }; +}; + +export const WithAppDependencies = (Comp: any) => (props: any) => ( + + + +); diff --git a/x-pack/plugins/index_management/__jest__/client_integration/helpers/template_clone.helpers.ts b/x-pack/plugins/index_management/__jest__/client_integration/helpers/template_clone.helpers.ts new file mode 100644 index 0000000000000..36498b99ba143 --- /dev/null +++ b/x-pack/plugins/index_management/__jest__/client_integration/helpers/template_clone.helpers.ts @@ -0,0 +1,24 @@ +/* + * 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. + */ + +import { registerTestBed, TestBedConfig } from '../../../../../test_utils'; +import { BASE_PATH } from '../../../common/constants'; +import { TemplateClone } from '../../../public/application/sections/template_clone'; // eslint-disable-line @kbn/eslint/no-restricted-paths +import { formSetup } from './template_form.helpers'; +import { TEMPLATE_NAME } from './constants'; +import { WithAppDependencies } from './setup_environment'; + +const testBedConfig: TestBedConfig = { + memoryRouter: { + initialEntries: [`${BASE_PATH}clone_template/${TEMPLATE_NAME}`], + componentRoutePath: `${BASE_PATH}clone_template/:name`, + }, + doMountAsync: true, +}; + +const initTestBed = registerTestBed(WithAppDependencies(TemplateClone), testBedConfig); + +export const setup = formSetup.bind(null, initTestBed); diff --git a/x-pack/plugins/index_management/__jest__/client_integration/helpers/template_create.helpers.ts b/x-pack/plugins/index_management/__jest__/client_integration/helpers/template_create.helpers.ts new file mode 100644 index 0000000000000..14a44968a93c3 --- /dev/null +++ b/x-pack/plugins/index_management/__jest__/client_integration/helpers/template_create.helpers.ts @@ -0,0 +1,26 @@ +/* + * 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. + */ + +import { registerTestBed, TestBedConfig } from '../../../../../test_utils'; +import { BASE_PATH } from '../../../common/constants'; +import { TemplateCreate } from '../../../public/application/sections/template_create'; // eslint-disable-line @kbn/eslint/no-restricted-paths +import { formSetup, TestSubjects } from './template_form.helpers'; +import { WithAppDependencies } from './setup_environment'; + +const testBedConfig: TestBedConfig = { + memoryRouter: { + initialEntries: [`${BASE_PATH}create_template`], + componentRoutePath: `${BASE_PATH}create_template`, + }, + doMountAsync: true, +}; + +const initTestBed = registerTestBed( + WithAppDependencies(TemplateCreate), + testBedConfig +); + +export const setup = formSetup.bind(null, initTestBed); diff --git a/x-pack/plugins/index_management/__jest__/client_integration/helpers/template_edit.helpers.ts b/x-pack/plugins/index_management/__jest__/client_integration/helpers/template_edit.helpers.ts new file mode 100644 index 0000000000000..af5fa8b79ecad --- /dev/null +++ b/x-pack/plugins/index_management/__jest__/client_integration/helpers/template_edit.helpers.ts @@ -0,0 +1,24 @@ +/* + * 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. + */ + +import { registerTestBed, TestBedConfig } from '../../../../../test_utils'; +import { BASE_PATH } from '../../../common/constants'; +import { TemplateEdit } from '../../../public/application/sections/template_edit'; // eslint-disable-line @kbn/eslint/no-restricted-paths +import { formSetup, TestSubjects } from './template_form.helpers'; +import { TEMPLATE_NAME } from './constants'; +import { WithAppDependencies } from './setup_environment'; + +const testBedConfig: TestBedConfig = { + memoryRouter: { + initialEntries: [`${BASE_PATH}edit_template/${TEMPLATE_NAME}`], + componentRoutePath: `${BASE_PATH}edit_template/:name`, + }, + doMountAsync: true, +}; + +const initTestBed = registerTestBed(WithAppDependencies(TemplateEdit), testBedConfig); + +export const setup = formSetup.bind(null, initTestBed); diff --git a/x-pack/plugins/index_management/__jest__/client_integration/helpers/template_form.helpers.ts b/x-pack/plugins/index_management/__jest__/client_integration/helpers/template_form.helpers.ts new file mode 100644 index 0000000000000..9d4eb631a1c40 --- /dev/null +++ b/x-pack/plugins/index_management/__jest__/client_integration/helpers/template_form.helpers.ts @@ -0,0 +1,241 @@ +/* + * 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. + */ +import { TestBed, SetupFunc, UnwrapPromise } from '../../../../../test_utils'; +import { Template } from '../../../common/types'; +import { nextTick } from './index'; + +interface MappingField { + name: string; + type: string; +} + +// Look at the return type of formSetup and form a union between that type and the TestBed type. +// This way we an define the formSetup return object and use that to dynamically define our type. +export type TemplateFormTestBed = TestBed & + UnwrapPromise>; + +export const formSetup = async (initTestBed: SetupFunc) => { + const testBed = await initTestBed(); + + // User actions + const clickNextButton = () => { + testBed.find('nextButton').simulate('click'); + }; + + const clickBackButton = () => { + testBed.find('backButton').simulate('click'); + }; + + const clickSubmitButton = () => { + testBed.find('submitButton').simulate('click'); + }; + + const clickEditButtonAtField = (index: number) => { + testBed + .find('editFieldButton') + .at(index) + .simulate('click'); + }; + + const clickEditFieldUpdateButton = () => { + testBed.find('editFieldUpdateButton').simulate('click'); + }; + + const clickRemoveButtonAtField = (index: number) => { + testBed + .find('removeFieldButton') + .at(index) + .simulate('click'); + + testBed.find('confirmModalConfirmButton').simulate('click'); + }; + + const clickCancelCreateFieldButton = () => { + testBed.find('createFieldWrapper.cancelButton').simulate('click'); + }; + + const completeStepOne = async ({ + name, + indexPatterns, + order, + version, + }: Partial