elasticgraph-local 0.17.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|