elasticgraph-local 0.17.1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +80 -0
- data/elasticgraph-local.gemspec +25 -0
- data/lib/elastic_graph/local/config.ru +15 -0
- data/lib/elastic_graph/local/docker_runner.rb +117 -0
- data/lib/elastic_graph/local/elasticsearch/Dockerfile +3 -0
- data/lib/elastic_graph/local/elasticsearch/UI-Dockerfile +2 -0
- data/lib/elastic_graph/local/elasticsearch/docker-compose.yaml +74 -0
- data/lib/elastic_graph/local/indexing_coordinator.rb +58 -0
- data/lib/elastic_graph/local/local_indexer.rb +28 -0
- data/lib/elastic_graph/local/opensearch/Dockerfile +4 -0
- data/lib/elastic_graph/local/opensearch/UI-Dockerfile +2 -0
- data/lib/elastic_graph/local/opensearch/docker-compose.yaml +50 -0
- data/lib/elastic_graph/local/rake_tasks.rb +538 -0
- data/lib/elastic_graph/local/tested_database_versions.yaml +8 -0
- metadata +399 -0
@@ -0,0 +1,538 @@
|
|
1
|
+
# Copyright 2024 Block, Inc.
|
2
|
+
#
|
3
|
+
# Use of this source code is governed by an MIT-style
|
4
|
+
# license that can be found in the LICENSE file or at
|
5
|
+
# https://opensource.org/licenses/MIT.
|
6
|
+
#
|
7
|
+
# frozen_string_literal: true
|
8
|
+
|
9
|
+
require "elastic_graph/admin/rake_tasks"
|
10
|
+
require "elastic_graph/local/docker_runner"
|
11
|
+
require "elastic_graph/schema_definition/rake_tasks"
|
12
|
+
require "rake/tasklib"
|
13
|
+
require "shellwords"
|
14
|
+
|
15
|
+
module ElasticGraph
|
16
|
+
# Provides support for developing and running ElasticGraph applications locally.
|
17
|
+
module Local
|
18
|
+
# Defines tasks for local development. These tasks include:
|
19
|
+
#
|
20
|
+
# - Running OpenSearch and/or Elasticsearch locally (`(elasticsearch|opensearch):[env]:(boot|daemon|halt)`)
|
21
|
+
# - Managing schema artifacts (`schema_artifacts:(check|dump)`)
|
22
|
+
# - Configuring OpenSearch/Elasticsearch locally (`clusters:configure:(dry_run|perform)`)
|
23
|
+
# - Indexing fake data (`index_fake_data:[type]`)
|
24
|
+
# - Booting an ElasticGraph application locally (`boot_locally`)
|
25
|
+
#
|
26
|
+
# @note All tasks (besides the `schema_artifacts` tasks) require `docker` and `docker-compose` to be available on your machine.
|
27
|
+
class RakeTasks < ::Rake::TaskLib
|
28
|
+
# When enabled, ElasticGraph will configure the index mappings so that the datastore indexes a `_size` field in each index document.
|
29
|
+
# ElasticGraph itself does not do anything with this field, but it will be available for your use in any direct queries (e.g. via
|
30
|
+
# Kibana).
|
31
|
+
#
|
32
|
+
# Defaults to `false` since it requires a plugin.
|
33
|
+
#
|
34
|
+
# @note Enabling this requires the [mapper-size plugin](https://www.elastic.co/guide/en/elasticsearch/plugins/8.15/mapper-size.html)
|
35
|
+
# to be installed on your datastore cluster. You are responsible for ensuring that is installed if you enable this feature. If you
|
36
|
+
# enable this and the plugin is not installed, you will get errors!
|
37
|
+
#
|
38
|
+
# @return [Boolean] whether or not the `_size` field should be indexed on each indexed type
|
39
|
+
#
|
40
|
+
# @example Enable indexing document sizes
|
41
|
+
# ElasticGraph::Local::RakeTasks.new(
|
42
|
+
# local_config_yaml: "config/settings/local.yaml",
|
43
|
+
# path_to_schema: "config/schema.rb"
|
44
|
+
# ) do |tasks|
|
45
|
+
# tasks.index_document_sizes = true
|
46
|
+
# end
|
47
|
+
#
|
48
|
+
# @dynamic index_document_sizes, index_document_sizes=
|
49
|
+
attr_accessor :index_document_sizes
|
50
|
+
|
51
|
+
# The form of names for schema elements (fields, arguments, directives) generated by ElasticGraph, either `:snake_case` or
|
52
|
+
# `:camelCase`. For example, if set to `:camelCase`, ElasticGraph will generate a `groupedBy` field, but if set to `:snake_case`,
|
53
|
+
# ElasticGraph will generate a `grouped_by` field.
|
54
|
+
#
|
55
|
+
# Defaults to `:camelCase` since most GraphQL schemas use that casing.
|
56
|
+
#
|
57
|
+
# @return [:camelCase, :snake_case] which form to use
|
58
|
+
#
|
59
|
+
# @example Use `snake_case` names instead of `camelCase`
|
60
|
+
# ElasticGraph::Local::RakeTasks.new(
|
61
|
+
# local_config_yaml: "config/settings/local.yaml",
|
62
|
+
# path_to_schema: "config/schema.rb"
|
63
|
+
# ) do |tasks|
|
64
|
+
# tasks.schema_element_name_form = :snake_case
|
65
|
+
# end
|
66
|
+
#
|
67
|
+
# @dynamic schema_element_name_form, schema_element_name_form=
|
68
|
+
attr_accessor :schema_element_name_form
|
69
|
+
|
70
|
+
# Overrides for specific names of schema elements (fields, arguments, directives) generated by ElasticGraph. For example, to rename
|
71
|
+
# the `gt` filter field to `greaterThan`, set to `{gt: "greaterThan"}`.
|
72
|
+
#
|
73
|
+
# Defaults to an empty hash.
|
74
|
+
#
|
75
|
+
# @return [Hash<Symbol, String>] overrides for specific field, argument, or directive names
|
76
|
+
#
|
77
|
+
# @example Spell out comparison operators instead of using shortened forms
|
78
|
+
# ElasticGraph::Local::RakeTasks.new(
|
79
|
+
# local_config_yaml: "config/settings/local.yaml",
|
80
|
+
# path_to_schema: "config/schema.rb"
|
81
|
+
# ) do |tasks|
|
82
|
+
# tasks.schema_element_name_overrides = {
|
83
|
+
# gt: "greaterThan",
|
84
|
+
# gte: "greaterThanOrEqualTo",
|
85
|
+
# lt: "lessThan",
|
86
|
+
# lte: "lessThanOrEqualTo"
|
87
|
+
# }
|
88
|
+
# end
|
89
|
+
#
|
90
|
+
# @dynamic schema_element_name_overrides, schema_element_name_overrides=
|
91
|
+
attr_accessor :schema_element_name_overrides
|
92
|
+
|
93
|
+
# Overrides for the naming formats used by ElasticGraph for derived GraphQL type names. For example, to use `Metrics` instead of
|
94
|
+
# `AggregatedValues` as the suffix for the generated types supporting getting aggregated metrid values, set to
|
95
|
+
# `{AggregatedValues: "%{base}Metrics"}`. See {SchemaDefinition::SchemaElements::TypeNamer::DEFAULT_FORMATS} for the available
|
96
|
+
# formats.
|
97
|
+
#
|
98
|
+
# Defaults to an empty hash.
|
99
|
+
#
|
100
|
+
# @example Change the `AggregatedValues` type suffix to `Metrics`
|
101
|
+
# ElasticGraph::Local::RakeTasks.new(
|
102
|
+
# local_config_yaml: "config/settings/local.yaml",
|
103
|
+
# path_to_schema: "config/schema.rb"
|
104
|
+
# ) do |tasks|
|
105
|
+
# tasks.derived_type_name_formats = {AggregatedValues: "Metrics"}
|
106
|
+
# end
|
107
|
+
#
|
108
|
+
# @dynamic derived_type_name_formats, derived_type_name_formats=
|
109
|
+
attr_accessor :derived_type_name_formats
|
110
|
+
|
111
|
+
# Overrides for the names of specific GraphQL types. For example, to rename the `JsonSafeLong` scalar to `BigInt`, set to
|
112
|
+
# `{JsonSafeLong: "BigInt}`.
|
113
|
+
#
|
114
|
+
# Defaults to an empty hash.
|
115
|
+
#
|
116
|
+
# @return [Hash<Symbol, String>] overrides for specific type names
|
117
|
+
#
|
118
|
+
# @example Rename `JsonSafeLong` to `BigInt`
|
119
|
+
# ElasticGraph::Local::RakeTasks.new(
|
120
|
+
# local_config_yaml: "config/settings/local.yaml",
|
121
|
+
# path_to_schema: "config/schema.rb"
|
122
|
+
# ) do |tasks|
|
123
|
+
# tasks.type_name_overrides = {JsonSafeLong: "BigInt"}
|
124
|
+
# end
|
125
|
+
#
|
126
|
+
# @dynamic type_name_overrides, type_name_overrides=
|
127
|
+
attr_accessor :type_name_overrides
|
128
|
+
|
129
|
+
# Overrides for the names of specific GraphQL enum values for specific enum types. For example, to rename the `DayOfWeek.MONDAY`
|
130
|
+
# enum to `DayOfWeek.MON`, set to `{DayOfWeek: {MONDAY: "MON"}}`.
|
131
|
+
#
|
132
|
+
# Defaults to an empty hash.
|
133
|
+
#
|
134
|
+
# @return [Hash<Symbol, Hash<Symbol, String>>] overrides for the names of specific enum values for specific enum types
|
135
|
+
#
|
136
|
+
# @example Shorten the names of the `DayOfWeek` enum values
|
137
|
+
# ElasticGraph::Local::RakeTasks.new(
|
138
|
+
# local_config_yaml: "config/settings/local.yaml",
|
139
|
+
# path_to_schema: "config/schema.rb"
|
140
|
+
# ) do |tasks|
|
141
|
+
# tasks.enum_value_overrides_by_type = {
|
142
|
+
# DayOfWeek: {
|
143
|
+
# MONDAY: "MON",
|
144
|
+
# TUESDAY: "TUE",
|
145
|
+
# WEDNESDAY: "WED",
|
146
|
+
# THURSDAY: "THU",
|
147
|
+
# FRIDAY: "FRI",
|
148
|
+
# SATURDAY: "SAT",
|
149
|
+
# SUNDAY: "SUN"
|
150
|
+
# }
|
151
|
+
# }
|
152
|
+
# end
|
153
|
+
#
|
154
|
+
# @dynamic enum_value_overrides_by_type, enum_value_overrides_by_type=
|
155
|
+
attr_accessor :enum_value_overrides_by_type
|
156
|
+
|
157
|
+
# List of Ruby modules to extend onto the {SchemaDefinition::API} instance. Designed to support ElasticGraph extensions (such as
|
158
|
+
# `elasticgraph-apollo`). Defaults to an empty list.
|
159
|
+
#
|
160
|
+
# @return [Array<Module>] list of extension modules
|
161
|
+
#
|
162
|
+
# @example Extension that defines a `@since` directive and offers a `since` API on fields
|
163
|
+
# module SinceExtension
|
164
|
+
# # `self.extended` is a standard Ruby hook that gets called when a module is extended onto an object.
|
165
|
+
# # The argument is the object the module was extended onto (a `SchemaDefinition::API` instance in this case).
|
166
|
+
# def self.extended(api)
|
167
|
+
# # Define our `@since` directive
|
168
|
+
# api.raw_sdl "directive @since(date: Date!) on FIELD_DEFINITION"
|
169
|
+
#
|
170
|
+
# # In order to hook into fields, extend the `SchemaDefinition::Factory` with a module. The factory is used
|
171
|
+
# # for creation of all schema definition objects.
|
172
|
+
# api.factory.extend FactoryExtension
|
173
|
+
# end
|
174
|
+
#
|
175
|
+
# module FactoryExtension
|
176
|
+
# # Hook into the creation of all `SchemaDefinition::Field` objects so that we can extend each field
|
177
|
+
# # instance with our `FieldExtension` module.
|
178
|
+
# def new_field(*args, **options)
|
179
|
+
# super(*args, **options) do |field|
|
180
|
+
# field.extend FieldExtension
|
181
|
+
# yield field if block_given?
|
182
|
+
# end
|
183
|
+
# end
|
184
|
+
# end
|
185
|
+
#
|
186
|
+
# # Offer a `f.since date` API on fields.
|
187
|
+
# module FieldExtension
|
188
|
+
# def since(date)
|
189
|
+
# directive "since", date: date
|
190
|
+
# end
|
191
|
+
# end
|
192
|
+
# end
|
193
|
+
#
|
194
|
+
# ElasticGraph::Local::RakeTasks.new(
|
195
|
+
# local_config_yaml: "config/settings/local.yaml",
|
196
|
+
# path_to_schema: "config/schema.rb"
|
197
|
+
# ) do |tasks|
|
198
|
+
# tasks.schema_definition_extension_modules = [SinceExtension]
|
199
|
+
# end
|
200
|
+
#
|
201
|
+
# @dynamic schema_definition_extension_modules, schema_definition_extension_modules=
|
202
|
+
attr_accessor :schema_definition_extension_modules
|
203
|
+
|
204
|
+
# Whether or not to enforce the requirement that the JSON schema version is incremented every time
|
205
|
+
# dumping the JSON schemas results in a changed artifact. Defaults to `true`.
|
206
|
+
#
|
207
|
+
# @note Generally speaking, you will want this to be `true` for any ElasticGraph application that is in
|
208
|
+
# production as the versioning of JSON schemas is what supports safe schema evolution as it allows
|
209
|
+
# ElasticGraph to identify which version of the JSON schema the publishing system was operating on
|
210
|
+
# when it published an event.
|
211
|
+
#
|
212
|
+
# It can be useful to set it to `false` before your application is in production, as you do not want
|
213
|
+
# to be forced to bump the version after every single schema change while you are building an initial
|
214
|
+
# prototype.
|
215
|
+
#
|
216
|
+
# @return [Boolean] whether to require `json_schema_version` to be incremented on changes that impact `json_schemas.yaml`
|
217
|
+
# @see SchemaDefinition::API#json_schema_version
|
218
|
+
#
|
219
|
+
# @example Disable enforcement during initial prototyping
|
220
|
+
# ElasticGraph::Local::RakeTasks.new(
|
221
|
+
# local_config_yaml: "config/settings/local.yaml",
|
222
|
+
# path_to_schema: "config/schema.rb"
|
223
|
+
# ) do |tasks|
|
224
|
+
# # TODO: remove this once we're past the prototyping stage
|
225
|
+
# tasks.enforce_json_schema_version = false
|
226
|
+
# end
|
227
|
+
#
|
228
|
+
# @dynamic enforce_json_schema_version, enforce_json_schema_version=
|
229
|
+
attr_accessor :enforce_json_schema_version
|
230
|
+
|
231
|
+
# List of Elasticsearch versions you want to be able to boot. Rake tasks will be defined for each version to support booting and
|
232
|
+
# halting Elasticsearch locally. Defaults to the versions of Elasticsearch that are exercised by the ElasticGraph test suite, as
|
233
|
+
# defined by `lib/elastic_graph/local/tested_database_versions.yaml`:
|
234
|
+
#
|
235
|
+
# {include:file:elasticgraph-local/lib/elastic_graph/local/tested_database_versions.yaml}
|
236
|
+
#
|
237
|
+
# @return [Array<String>] list of Elasticsearch versions
|
238
|
+
# @see #opensearch_versions
|
239
|
+
#
|
240
|
+
# @example Disable Elasticsearch tasks for a project that uses OpenSearch
|
241
|
+
# ElasticGraph::Local::RakeTasks.new(
|
242
|
+
# local_config_yaml: "config/settings/local.yaml",
|
243
|
+
# path_to_schema: "config/schema.rb"
|
244
|
+
# ) do |tasks|
|
245
|
+
# tasks.elasticsearch_versions = []
|
246
|
+
# end
|
247
|
+
#
|
248
|
+
# @dynamic elasticsearch_versions, elasticsearch_versions=
|
249
|
+
attr_accessor :elasticsearch_versions
|
250
|
+
|
251
|
+
# List of OpenSearch versions you want to be able to boot. Rake tasks will be defined for each version to support booting and
|
252
|
+
# halting OpenSearch locally. Defaults to the versions of OpenSearch that are exercised by the ElasticGraph test suite, as
|
253
|
+
# defined by `lib/elastic_graph/local/tested_database_versions.yaml`:
|
254
|
+
#
|
255
|
+
# {include:file:elasticgraph-local/lib/elastic_graph/local/tested_database_versions.yaml}
|
256
|
+
#
|
257
|
+
# @return [Array<String>] list of OpenSearch versions
|
258
|
+
# @see #elasticsearch_versions
|
259
|
+
#
|
260
|
+
# @example Disable OpenSearch tasks for a project that uses Elasticsearch
|
261
|
+
# ElasticGraph::Local::RakeTasks.new(
|
262
|
+
# local_config_yaml: "config/settings/local.yaml",
|
263
|
+
# path_to_schema: "config/schema.rb"
|
264
|
+
# ) do |tasks|
|
265
|
+
# tasks.opensearch_versions = []
|
266
|
+
# end
|
267
|
+
#
|
268
|
+
# @dynamic opensearch_versions, opensearch_versions=
|
269
|
+
attr_accessor :opensearch_versions
|
270
|
+
|
271
|
+
# Hash mapping environments (e.g. `:test`, `:dev`, etc) to port numbers for use when booting Elasticsearch or OpenSearch. The hash
|
272
|
+
# automatically includes an entry for the `:local` environment, using a port number extracted from `local_config_yaml`.
|
273
|
+
#
|
274
|
+
# @note When booting Elasticsearch/OpenSearch, Kibana (or its OpenSearch equivalent, "OpenSearch Dashboards") will also get booted,
|
275
|
+
# selecting the port by adding `10000` to the configured port.
|
276
|
+
#
|
277
|
+
# @return [Hash<Symbol, Integer>] mapping from environment name to port number
|
278
|
+
#
|
279
|
+
# @example Define what port to use to boot the datastore for the `:test` environment
|
280
|
+
# ElasticGraph::Local::RakeTasks.new(
|
281
|
+
# local_config_yaml: "config/settings/local.yaml",
|
282
|
+
# path_to_schema: "config/schema.rb"
|
283
|
+
# ) do |tasks|
|
284
|
+
# tasks.env_port_mapping = {test: 9999}
|
285
|
+
# end
|
286
|
+
#
|
287
|
+
# @dynamic env_port_mapping, env_port_mapping=
|
288
|
+
attr_accessor :env_port_mapping
|
289
|
+
|
290
|
+
# IO for printing output (defaults to stdout).
|
291
|
+
#
|
292
|
+
# @return [IO] IO object used for printing output.
|
293
|
+
#
|
294
|
+
# @dynamic output, output=
|
295
|
+
attr_accessor :output
|
296
|
+
|
297
|
+
# Maximum time (in seconds) to wait for the datastore to boot when booting it as a daemon. Defaults to 120.
|
298
|
+
#
|
299
|
+
# @return [Integer] maximum time in seconds to wait when booting Elasticsearch/OpenSearch as a daemon
|
300
|
+
#
|
301
|
+
# @dynamic daemon_timeout, daemon_timeout=
|
302
|
+
attr_accessor :daemon_timeout
|
303
|
+
|
304
|
+
# Offset we add to a port number for the UI (e.g. Kibana or OpenSearch Dashboards).
|
305
|
+
#
|
306
|
+
# Example: if Elasticsearch/OpenSearch is running on port 9876, the UI for it will run on port 19876.
|
307
|
+
UI_PORT_OFFSET = 10_000
|
308
|
+
|
309
|
+
# As per https://en.wikipedia.org/wiki/Registered_port, valid user port numbers are 1024 to 49151, but
|
310
|
+
# with our UI offset we need to truncate the range further.
|
311
|
+
#
|
312
|
+
# @private
|
313
|
+
VALID_PORT_RANGE = 1024..(49151 - UI_PORT_OFFSET)
|
314
|
+
|
315
|
+
# Register a callback for use when indexing a batch fake data. An `index_fake_data:[type]` rake task will be generated for each
|
316
|
+
# registered callback.
|
317
|
+
#
|
318
|
+
# @param type [Symbol] type of data batch. Can be the name of a GraphQL type or any other name you want to give a batch of fake data
|
319
|
+
# @yield [Array<Hash<String, Object>>, Array<Hash<Symbol, Object>>] list the block should append to when generating data
|
320
|
+
# @yieldreturn [void]
|
321
|
+
#
|
322
|
+
# @example Register a callback to generate fake `campaigns` data
|
323
|
+
# ElasticGraph::Local::RakeTasks.new(
|
324
|
+
# local_config_yaml: "config/settings/local.yaml",
|
325
|
+
# path_to_schema: "config/schema.rb"
|
326
|
+
# ) do |tasks|
|
327
|
+
# tasks.define_fake_data_batch_for :campaigns do |batch|
|
328
|
+
# batch.concat(FactoryBot.build_list(:campaigns))
|
329
|
+
# end
|
330
|
+
# end
|
331
|
+
def define_fake_data_batch_for(type, &block)
|
332
|
+
@fake_data_batch_generator_by_type[type] = block
|
333
|
+
end
|
334
|
+
|
335
|
+
# @note This method uses keyword args for all required arguments. Optional task settings are instead specified using the block.
|
336
|
+
# @param local_config_yaml [String, Pathname] path to the settings YAML file for the local/development environment
|
337
|
+
# @param path_to_schema [String, Pathname] path to the Ruby schema definition file--either the only file that defines the schema
|
338
|
+
# (using `ElasticGraph.define_schema`) or the "main" schema definition file, which loads other files which further define parts of
|
339
|
+
# the schema.
|
340
|
+
# @yield [RakeTasks] instance for further configuration
|
341
|
+
# @yieldreturn [void]
|
342
|
+
def initialize(local_config_yaml:, path_to_schema:)
|
343
|
+
@local_config_yaml = local_config_yaml.to_s
|
344
|
+
|
345
|
+
self.index_document_sizes = false
|
346
|
+
self.schema_element_name_form = :camelCase
|
347
|
+
self.schema_element_name_overrides = {}
|
348
|
+
self.derived_type_name_formats = {}
|
349
|
+
self.type_name_overrides = {}
|
350
|
+
self.enum_value_overrides_by_type = {}
|
351
|
+
self.schema_definition_extension_modules = []
|
352
|
+
self.enforce_json_schema_version = true
|
353
|
+
self.env_port_mapping = {}
|
354
|
+
self.output = $stdout
|
355
|
+
self.daemon_timeout = 120
|
356
|
+
|
357
|
+
database_versions = ::YAML.load_file("#{__dir__}/tested_database_versions.yaml")
|
358
|
+
self.elasticsearch_versions = database_versions.fetch("elasticsearch")
|
359
|
+
self.opensearch_versions = database_versions.fetch("opensearch")
|
360
|
+
|
361
|
+
@fake_data_batch_generator_by_type = {}
|
362
|
+
|
363
|
+
yield self if block_given?
|
364
|
+
|
365
|
+
# Default the local port from the local_config_yaml file.
|
366
|
+
self.env_port_mapping = {"local" => local_datastore_port}.merge(env_port_mapping || {})
|
367
|
+
if (invalid_port_mapping = env_port_mapping.reject { |env, port| VALID_PORT_RANGE.cover?(port) }).any?
|
368
|
+
raise "`env_port_mapping` has invalid ports: #{invalid_port_mapping.inspect}. Valid ports must be in the #{VALID_PORT_RANGE} range."
|
369
|
+
end
|
370
|
+
|
371
|
+
# Load admin and schema def rake tasks...
|
372
|
+
Admin::RakeTasks.from_yaml_file(local_config_yaml, output: output)
|
373
|
+
SchemaDefinition::RakeTasks.new(
|
374
|
+
index_document_sizes: index_document_sizes,
|
375
|
+
path_to_schema: path_to_schema,
|
376
|
+
schema_artifacts_directory: local_config.fetch("schema_artifacts").fetch("directory"),
|
377
|
+
schema_element_name_form: schema_element_name_form,
|
378
|
+
schema_element_name_overrides: schema_element_name_overrides,
|
379
|
+
derived_type_name_formats: derived_type_name_formats,
|
380
|
+
type_name_overrides: type_name_overrides,
|
381
|
+
enum_value_overrides_by_type: enum_value_overrides_by_type,
|
382
|
+
extension_modules: schema_definition_extension_modules,
|
383
|
+
enforce_json_schema_version: enforce_json_schema_version,
|
384
|
+
output: output
|
385
|
+
)
|
386
|
+
|
387
|
+
# ...then define a bunch of our own.
|
388
|
+
define_docker_tasks("Elasticsearch", "Kibana", elasticsearch_versions, /license \[[^\]]+\] mode \[[^\]]+\] - valid/)
|
389
|
+
define_docker_tasks("OpenSearch", "OpenSearch Dashboards", opensearch_versions, /o\.o\.n\.Node.+started/)
|
390
|
+
define_other_tasks
|
391
|
+
end
|
392
|
+
|
393
|
+
private
|
394
|
+
|
395
|
+
def define_docker_tasks(description, ui_variant, versions, ready_log_line)
|
396
|
+
variant = description.downcase.to_sym
|
397
|
+
namespace variant do
|
398
|
+
env_port_mapping.each do |env, port|
|
399
|
+
namespace env do
|
400
|
+
versions.each do |version|
|
401
|
+
namespace version do
|
402
|
+
define_docker_tasks_for_version(description, variant, ui_variant, port: port, version: version, env: env, ready_log_line: ready_log_line)
|
403
|
+
end
|
404
|
+
end
|
405
|
+
|
406
|
+
if (max_version = versions.max_by { |v| Gem::Version.create(v) })
|
407
|
+
define_docker_tasks_for_version(description, variant, ui_variant, port: port, version: max_version, env: env, ready_log_line: ready_log_line)
|
408
|
+
end
|
409
|
+
end
|
410
|
+
end
|
411
|
+
end
|
412
|
+
end
|
413
|
+
|
414
|
+
def define_docker_tasks_for_version(description, variant, ui_variant, port:, version:, env:, ready_log_line:)
|
415
|
+
ui_port = port + UI_PORT_OFFSET
|
416
|
+
|
417
|
+
docker_runner = DockerRunner.new(
|
418
|
+
variant,
|
419
|
+
port: port,
|
420
|
+
ui_port: port + UI_PORT_OFFSET,
|
421
|
+
version: version,
|
422
|
+
env: env,
|
423
|
+
ready_log_line: ready_log_line,
|
424
|
+
output: output,
|
425
|
+
daemon_timeout: daemon_timeout
|
426
|
+
)
|
427
|
+
|
428
|
+
desc "Boots #{description} #{version} for the #{env} environment on port #{port} (and #{ui_variant} on port #{ui_port})"
|
429
|
+
task(:boot) { docker_runner.boot }
|
430
|
+
|
431
|
+
desc "Boots #{description} #{version} as a background daemon for the #{env} environment on port #{port} (and #{ui_variant} on port #{ui_port})"
|
432
|
+
task(:daemon) do |t|
|
433
|
+
docker_runner.boot_as_daemon(halt_command: "rake #{t.name.sub(/:\w+\z/, ":halt")}")
|
434
|
+
end
|
435
|
+
|
436
|
+
desc "Halts the #{description} #{version} daemon for the #{env} environment"
|
437
|
+
task(:halt) { docker_runner.halt }
|
438
|
+
end
|
439
|
+
|
440
|
+
def define_other_tasks
|
441
|
+
index_fake_data_tasks = @fake_data_batch_generator_by_type.keys.map do |type|
|
442
|
+
"index_fake_data:#{type}"
|
443
|
+
end
|
444
|
+
|
445
|
+
database_to_boot =
|
446
|
+
if elasticsearch_versions.empty? && opensearch_versions.empty?
|
447
|
+
raise "Both `elasticsearch_versions` and `opensearch_versions` are empty, but we need at least one of them to have a version in order to provide the boot tasks."
|
448
|
+
elsif elasticsearch_versions.empty?
|
449
|
+
"OpenSearch"
|
450
|
+
else
|
451
|
+
"Elasticsearch"
|
452
|
+
end
|
453
|
+
|
454
|
+
desc "Boots ElasticGraph locally from scratch: boots #{database_to_boot}, configures it, indexes fake data, and boots GraphiQL"
|
455
|
+
task :boot_locally, [:port, :rackup_args, :no_open] => ["#{database_to_boot.downcase}:local:daemon", *index_fake_data_tasks, "boot_graphiql"]
|
456
|
+
|
457
|
+
desc "Boots ElasticGraph locally with the GraphiQL UI, and opens it in a browser."
|
458
|
+
task :boot_graphiql, [:port, :rackup_args, :no_open] => :ensure_datastore_ready_for_indexing_and_querying do |task, args|
|
459
|
+
args.with_defaults(port: 9393, rackup_args: "", no_open: false)
|
460
|
+
port = args.fetch(:port)
|
461
|
+
|
462
|
+
# :nocov: -- we can't test `open` behavior through a test, and simplecov can't detect coverage in a subprocess.
|
463
|
+
unless args.fetch(:no_open)
|
464
|
+
fork do
|
465
|
+
sleep 3 # give the app a bit of time to boot before we try to open it.
|
466
|
+
sh "open http://localhost:#{port}/"
|
467
|
+
end
|
468
|
+
end
|
469
|
+
# :nocov:
|
470
|
+
|
471
|
+
sh "ELASTICGRAPH_YAML_FILE=#{@local_config_yaml.shellescape} bundle exec rackup #{::File.join(__dir__.to_s, "config.ru").shellescape} --port #{port} #{args.fetch(:rackup_args)}"
|
472
|
+
end
|
473
|
+
|
474
|
+
namespace :index_fake_data do
|
475
|
+
@fake_data_batch_generator_by_type.each do |type, generator|
|
476
|
+
desc "Indexes num_batches of #{type} fake data into the local datastore"
|
477
|
+
task type, [:num_batches] => :ensure_datastore_ready_for_indexing_and_querying do |task, args|
|
478
|
+
require "elastic_graph/local/local_indexer"
|
479
|
+
args.with_defaults(num_batches: 1)
|
480
|
+
LocalIndexer.new(@local_config_yaml, generator, output: output).index_fake_data(Integer(args[:num_batches]))
|
481
|
+
end
|
482
|
+
end
|
483
|
+
end
|
484
|
+
|
485
|
+
task :ensure_local_datastore_running do
|
486
|
+
unless /200 OK/.match?(`curl -is localhost:#{local_datastore_port}`)
|
487
|
+
if elasticsearch_versions.empty?
|
488
|
+
raise <<~EOS
|
489
|
+
OpenSearch is not running locally. You need to start it in another terminal using this command:
|
490
|
+
|
491
|
+
bundle exec rake opensearch:local:boot
|
492
|
+
EOS
|
493
|
+
elsif opensearch_versions.empty?
|
494
|
+
raise <<~EOS
|
495
|
+
Elasticsearch is not running locally. You need to start it in another terminal using this command:
|
496
|
+
|
497
|
+
bundle exec rake elasticsearch:local:boot
|
498
|
+
EOS
|
499
|
+
else
|
500
|
+
raise <<~EOS
|
501
|
+
Neither Elasticsearch nor OpenSearch are running locally. You need to start one of them in another terminal using one of these commands:
|
502
|
+
|
503
|
+
bundle exec rake elasticsearch:local:boot
|
504
|
+
bundle exec rake opensearch:local:boot
|
505
|
+
EOS
|
506
|
+
end
|
507
|
+
end
|
508
|
+
end
|
509
|
+
|
510
|
+
task ensure_datastore_ready_for_indexing_and_querying: [
|
511
|
+
:ensure_local_datastore_running,
|
512
|
+
"schema_artifacts:dump",
|
513
|
+
"clusters:configure:perform"
|
514
|
+
]
|
515
|
+
|
516
|
+
namespace "clusters:configure" do
|
517
|
+
%i[dry_run perform].each do |subtask|
|
518
|
+
desc "(after first dumping the schema artifacts)"
|
519
|
+
task subtask => [:ensure_local_datastore_running, "schema_artifacts:dump"]
|
520
|
+
end
|
521
|
+
end
|
522
|
+
end
|
523
|
+
|
524
|
+
def local_datastore_port
|
525
|
+
@local_datastore_port ||= local_config
|
526
|
+
.fetch("datastore")
|
527
|
+
.fetch("clusters")
|
528
|
+
.fetch("main")
|
529
|
+
.fetch("url")[/localhost:(\d+)$/, 1]
|
530
|
+
.then { |port_str| Integer(port_str) }
|
531
|
+
end
|
532
|
+
|
533
|
+
def local_config
|
534
|
+
@local_config ||= ::YAML.safe_load_file(@local_config_yaml, aliases: true)
|
535
|
+
end
|
536
|
+
end
|
537
|
+
end
|
538
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
# @markup text
|
2
|
+
# This file determines the versions the ElasticGraph CI build tests against, and is also
|
3
|
+
# used to provide the default versions offered by the `elasticgraph-local` rake tasks.
|
4
|
+
elasticsearch:
|
5
|
+
- 8.14.1 # latest version as of 2024-07-02.
|
6
|
+
opensearch:
|
7
|
+
- 2.15.0 # latest version as of 2024-07-02.
|
8
|
+
- 2.7.0 # lowest version ElasticGraph currently supports
|