polyn-cli 0.1.0 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +1 -0
- data/bin/apply_changes.sh +8 -0
- data/lib/polyn/cli/configuration.rb +4 -3
- data/lib/polyn/cli/schema_generator.rb +16 -5
- data/lib/polyn/cli/schema_loader.rb +68 -3
- data/lib/polyn/cli/version.rb +1 -1
- data/lib/polyn/cli.rb +59 -6
- data/lib/polyn/templates/.dockerignore +6 -0
- data/lib/polyn/templates/.gitignore +5 -0
- data/lib/polyn/templates/Dockerfile +16 -0
- data/lib/polyn/templates/Gemfile +3 -0
- data/lib/polyn/templates/README.md +37 -2
- data/lib/polyn/templates/tf/{event_registry.tf → kv_buckets.tf} +0 -0
- data/lib/polyn/templates/tf/provider.tf +4 -0
- data/lib/polyn/templates/tf/remote_state_config/backend.tf +6 -0
- data/lib/polyn/templates/tf/variables.tf +15 -0
- data/lib/polyn/templates/tf/versions.tf +8 -0
- metadata +12 -5
- data/lib/polyn/templates/gitignore +0 -3
- data/lib/polyn/templates/tf/main.tf +0 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4157c24284768c4e60893c3f3d7aca891e8916752ca85c6c48577ad59b9719bc
|
4
|
+
data.tar.gz: 114bb082e7f42f3db6d0efde45d4f058bb33bab652c42fc316668b6456d0e500
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c349dfca556555beaccbe06d2829378e4fb027a76651d444b3f0b0b8560237ca4f2ab8a8678be12de69eee47ade4837ca8cae405e632fbc2c5e2a5e55cbbae0d
|
7
|
+
data.tar.gz: 1d09e688a62159910697b791de37cebbd0d21f5e7078b84201854b777e0b3d22bcf93b9f034fd4d81f9125ddd32a17d683c0e0d9284a360e0ddb2e23afdd4e99
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -33,6 +33,7 @@ Run `polyn up` to update your NATS server with the latest configuration in your
|
|
33
33
|
## Environment Variables
|
34
34
|
|
35
35
|
* `NATS_SERVERS` - locations of your servers (defaults to localhost)
|
36
|
+
* `NATS_CREDENTIALS` - path to nats credentials file
|
36
37
|
* `POLYN_ENV` - type of environment (defaults to "development")
|
37
38
|
|
38
39
|
## Development
|
@@ -0,0 +1,8 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
# We want to keep these commands out of the Docker image
|
4
|
+
# build and instead defer them till the container is run.
|
5
|
+
# terraform init may require credentials for a remote backend
|
6
|
+
# and we don't want that in the image for security reasons.
|
7
|
+
bundle exec polyn tf_init
|
8
|
+
bundle exec polyn up
|
@@ -5,11 +5,12 @@ module Polyn
|
|
5
5
|
##
|
6
6
|
# Configuration data for Polyn::Cli
|
7
7
|
class Configuration
|
8
|
-
attr_reader :polyn_env, :nats_servers
|
8
|
+
attr_reader :polyn_env, :nats_servers, :nats_credentials
|
9
9
|
|
10
10
|
def initialize
|
11
|
-
@polyn_env
|
12
|
-
@nats_servers
|
11
|
+
@polyn_env = ENV["POLYN_ENV"] || "development"
|
12
|
+
@nats_servers = ENV["NATS_SERVERS"] || "localhost:4222"
|
13
|
+
@nats_credentials = ENV["NATS_CREDENTIALS"] || ""
|
13
14
|
end
|
14
15
|
end
|
15
16
|
end
|
@@ -14,21 +14,32 @@ module Polyn
|
|
14
14
|
|
15
15
|
source_root File.join(File.expand_path(__dir__), "../templates")
|
16
16
|
|
17
|
+
def type
|
18
|
+
@type ||= event_type.split("/").last
|
19
|
+
end
|
20
|
+
|
21
|
+
def subdir
|
22
|
+
@subdir ||= begin
|
23
|
+
split = event_type.split("/") - [type]
|
24
|
+
split.join("/")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
17
28
|
def check_name
|
18
|
-
Polyn::Cli::Naming.validate_event_type!(
|
29
|
+
Polyn::Cli::Naming.validate_event_type!(type)
|
19
30
|
end
|
20
31
|
|
21
32
|
def file_name
|
22
|
-
@file_name ||= "#{
|
33
|
+
@file_name ||= File.join(subdir, "#{type}.json")
|
23
34
|
end
|
24
35
|
|
25
36
|
def schema_id
|
26
|
-
Polyn::Cli::Naming.dot_to_colon(
|
37
|
+
Polyn::Cli::Naming.dot_to_colon(type)
|
27
38
|
end
|
28
39
|
|
29
40
|
def create
|
30
|
-
say "Creating new schema for #{
|
31
|
-
template "generators/schema.json", File.join(options.dir, "events/#{
|
41
|
+
say "Creating new schema for #{file_name}"
|
42
|
+
template "generators/schema.json", File.join(options.dir, "events/#{file_name}")
|
32
43
|
end
|
33
44
|
end
|
34
45
|
end
|
@@ -19,29 +19,44 @@ module Polyn
|
|
19
19
|
def initialize(thor, **opts)
|
20
20
|
@thor = thor
|
21
21
|
@client = NATS.connect(Polyn::Cli.configuration.nats_servers).jetstream
|
22
|
-
@
|
22
|
+
@store_name = opts.fetch(:store_name, STORE_NAME)
|
23
|
+
@bucket = client.key_value(@store_name)
|
23
24
|
@cloud_event_schema = Polyn::Cli::CloudEvent.to_h.freeze
|
24
25
|
@events_dir = opts.fetch(:events_dir, File.join(Dir.pwd, "events"))
|
25
26
|
@events = {}
|
27
|
+
@existing_events = {}
|
26
28
|
end
|
27
29
|
|
28
30
|
def load_events
|
29
31
|
thor.say "Loading events into the Polyn event registry from '#{events_dir}'"
|
30
32
|
read_events
|
33
|
+
load_existing_events
|
31
34
|
|
32
35
|
events.each do |name, event|
|
33
36
|
bucket.put(name, JSON.generate(event))
|
34
37
|
end
|
35
38
|
|
39
|
+
delete_missing_events
|
40
|
+
|
36
41
|
true
|
37
42
|
end
|
38
43
|
|
39
44
|
private
|
40
45
|
|
41
|
-
attr_reader :thor,
|
46
|
+
attr_reader :thor,
|
47
|
+
:events,
|
48
|
+
:client,
|
49
|
+
:bucket,
|
50
|
+
:cloud_event_schema,
|
51
|
+
:events_dir,
|
52
|
+
:store_name,
|
53
|
+
:existing_events
|
42
54
|
|
43
55
|
def read_events
|
44
|
-
Dir.glob(File.join(events_dir, "
|
56
|
+
event_files = Dir.glob(File.join(events_dir, "/**/*.json"))
|
57
|
+
validate_unique_event_types!(event_files)
|
58
|
+
|
59
|
+
event_files.each do |event_file|
|
45
60
|
thor.say "Loading 'event #{event_file}'"
|
46
61
|
data_schema = JSON.parse(File.read(event_file))
|
47
62
|
event_type = File.basename(event_file, ".json")
|
@@ -53,6 +68,30 @@ module Polyn
|
|
53
68
|
end
|
54
69
|
end
|
55
70
|
|
71
|
+
def validate_unique_event_types!(event_files)
|
72
|
+
duplicates = find_duplicates(event_files)
|
73
|
+
unless duplicates.empty?
|
74
|
+
messages = duplicates.reduce([]) do |memo, (event_type, files)|
|
75
|
+
memo << [event_type, *files].join("\n")
|
76
|
+
end
|
77
|
+
message = [
|
78
|
+
"There can only be one of each event type. The following events were duplicated:",
|
79
|
+
*messages,
|
80
|
+
].join("\n")
|
81
|
+
raise Polyn::Cli::ValidationError, message
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def find_duplicates(event_files)
|
86
|
+
event_types = event_files.group_by do |event_file|
|
87
|
+
File.basename(event_file, ".json")
|
88
|
+
end
|
89
|
+
event_types.each_with_object({}) do |(event_type, files), hash|
|
90
|
+
hash[event_type] = files if files.length > 1
|
91
|
+
hash
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
56
95
|
def validate_schema!(event_type, schema)
|
57
96
|
JSONSchemer.schema(schema)
|
58
97
|
rescue StandardError => e
|
@@ -68,6 +107,32 @@ module Polyn
|
|
68
107
|
}),
|
69
108
|
})
|
70
109
|
end
|
110
|
+
|
111
|
+
def load_existing_events
|
112
|
+
sub = client.subscribe("#{key_prefix}.>")
|
113
|
+
|
114
|
+
loop do
|
115
|
+
msg = sub.next_msg
|
116
|
+
existing_events[msg.subject.gsub("#{key_prefix}.", "")] = msg.data
|
117
|
+
# A timeout is the only mechanism given to indicate there are no
|
118
|
+
# more messages
|
119
|
+
rescue NATS::IO::Timeout
|
120
|
+
break
|
121
|
+
end
|
122
|
+
sub.unsubscribe
|
123
|
+
end
|
124
|
+
|
125
|
+
def key_prefix
|
126
|
+
"$KV.#{store_name}"
|
127
|
+
end
|
128
|
+
|
129
|
+
def delete_missing_events
|
130
|
+
missing_events = existing_events.keys - events.keys
|
131
|
+
missing_events.each do |event|
|
132
|
+
thor.say "Deleting event #{event}"
|
133
|
+
bucket.delete(event)
|
134
|
+
end
|
135
|
+
end
|
71
136
|
end
|
72
137
|
end
|
73
138
|
end
|
data/lib/polyn/cli/version.rb
CHANGED
data/lib/polyn/cli.rb
CHANGED
@@ -54,8 +54,11 @@ module Polyn
|
|
54
54
|
directory "tf", File.join(options.dir, "tf")
|
55
55
|
directory "events", File.join(options.dir, "events")
|
56
56
|
template "docker-compose.yml", File.join(options.dir, "docker-compose.yml")
|
57
|
-
template "
|
57
|
+
template "Dockerfile", File.join(options.dir, "Dockerfile")
|
58
|
+
template ".dockerignore", File.join(options.dir, ".dockerignore")
|
59
|
+
template ".gitignore", File.join(options.dir, ".gitignore")
|
58
60
|
template "README.md", File.join(options.dir, "README.md")
|
61
|
+
template "Gemfile", File.join(options.dir, "Gemfile")
|
59
62
|
run tf_init
|
60
63
|
say "Initializing git"
|
61
64
|
inside options.dir do
|
@@ -64,20 +67,49 @@ module Polyn
|
|
64
67
|
say "Repository initialized"
|
65
68
|
end
|
66
69
|
|
70
|
+
method_option :dir, default: Dir.getwd
|
67
71
|
desc "tf_init", "Initializes Terraform for configuration"
|
68
72
|
def tf_init
|
73
|
+
terraform_root = File.join(options.dir, "tf")
|
69
74
|
say "Initializing Terraform"
|
70
|
-
inside
|
71
|
-
|
75
|
+
inside terraform_root do
|
76
|
+
# In a development environment we want developers to work with their own local
|
77
|
+
# .tfstate rather than one configured in a remote `backend` intended for
|
78
|
+
# production use.
|
79
|
+
# https://www.terraform.io/language/settings/backends/configuration
|
80
|
+
#
|
81
|
+
# Terraform assumes only one backend will be configured and there's no path
|
82
|
+
# to switch between local and remote. There's also no way to dynamically load
|
83
|
+
# modules. https://github.com/hashicorp/terraform/issues/1439
|
84
|
+
# Instead we'll copy a backend config to the terraform root if we're in a production
|
85
|
+
# environment
|
86
|
+
if polyn_env == "production"
|
87
|
+
add_remote_backend(terraform_root) { run "terraform init" }
|
88
|
+
else
|
89
|
+
run "terraform init"
|
90
|
+
end
|
72
91
|
end
|
73
92
|
end
|
74
93
|
|
75
94
|
desc "up", "updates the JetStream streams and consumers, as well the Polyn event registry"
|
76
95
|
def up
|
96
|
+
terraform_root = File.join(Dir.getwd, "tf")
|
97
|
+
# We only want to run nats in the docker container if
|
98
|
+
# the developer isn't already running nats themselves locally
|
99
|
+
if polyn_env == "development" && !nats_running?
|
100
|
+
say "Starting NATS"
|
101
|
+
run "docker compose up --detach"
|
102
|
+
end
|
103
|
+
|
77
104
|
say "Updating JetStream configuration"
|
78
105
|
inside "tf" do
|
79
|
-
|
106
|
+
if polyn_env == "production"
|
107
|
+
add_remote_backend(terraform_root) { run tf_apply }
|
108
|
+
else
|
109
|
+
run tf_apply
|
110
|
+
end
|
80
111
|
end
|
112
|
+
|
81
113
|
say "Updating Polyn event registry"
|
82
114
|
Polyn::Cli::SchemaLoader.new(self).load_events
|
83
115
|
end
|
@@ -92,14 +124,35 @@ module Polyn
|
|
92
124
|
Polyn::Cli.configuration.nats_servers
|
93
125
|
end
|
94
126
|
|
127
|
+
def nats_credentials
|
128
|
+
Polyn::Cli.configuration.nats_credentials
|
129
|
+
end
|
130
|
+
|
95
131
|
def tf_apply
|
96
132
|
if polyn_env == "development"
|
97
|
-
%(terraform apply -var "jetstream_servers=#{nats_servers}" -auto-approve)
|
98
|
-
else
|
99
133
|
%(terraform apply -var "jetstream_servers=#{nats_servers}")
|
134
|
+
else
|
135
|
+
"terraform apply -auto-approve -input=false "\
|
136
|
+
"-var \"jetstream_servers=#{nats_servers}\" "\
|
137
|
+
"-var \"nats_credentials=#{nats_credentials}\" " \
|
138
|
+
"-var \"polyn_env=production\""
|
100
139
|
end
|
101
140
|
end
|
102
141
|
|
142
|
+
def nats_running?
|
143
|
+
# Uses lsof command to look up a process id. Will return `true` if it finds one
|
144
|
+
system("lsof -i TCP:4222 -t")
|
145
|
+
end
|
146
|
+
|
147
|
+
def add_remote_backend(tf_root)
|
148
|
+
copy_file File.join(tf_root, "remote_state_config/backend.tf"), "backend.tf"
|
149
|
+
yield
|
150
|
+
# We always want to remove the backend.tf file even if there's an error
|
151
|
+
# this way you don't get into a weird state when testing locally
|
152
|
+
ensure
|
153
|
+
remove_file File.join(tf_root, "backend.tf")
|
154
|
+
end
|
155
|
+
|
103
156
|
register(Polyn::Cli::SchemaGenerator, "gen:schema", "gen:schema EVENT_TYPE",
|
104
157
|
"Generates a new JSON Schema file for an event")
|
105
158
|
register(Polyn::Cli::StreamGenerator, "gen:stream", "gen:stream NAME",
|
@@ -0,0 +1,16 @@
|
|
1
|
+
FROM ruby:3.0.4-alpine3.15 as base
|
2
|
+
RUN apk add terraform
|
3
|
+
ADD Gemfile* ./
|
4
|
+
RUN gem install bundler
|
5
|
+
RUN bundle install
|
6
|
+
|
7
|
+
FROM base as app
|
8
|
+
WORKDIR /events
|
9
|
+
ADD events ./events
|
10
|
+
ADD tf ./tf
|
11
|
+
|
12
|
+
FROM app as dev
|
13
|
+
ENV POLYN_ENV='development'
|
14
|
+
|
15
|
+
FROM app as prod
|
16
|
+
ENV POLYN_ENV='production'
|
@@ -9,10 +9,19 @@ environment.
|
|
9
9
|
2. Install Terraform. For M1 Macs, [download the AMD64 version](https://www.terraform.io/downloads)
|
10
10
|
rather than using Homebrew to install Terraform.
|
11
11
|
3. Ensure Docker & Docker Compose is installed
|
12
|
-
4. [Install the Polyn CLI]()
|
13
|
-
5. Call `polyn
|
12
|
+
4. [Install the Polyn CLI](https://github.com/SpiffInc/polyn-cli)
|
13
|
+
5. Call `polyn tf_init` if this is the first time using terraform in the codebase.
|
14
|
+
6. Call `polyn up`. By default this will run in `development` mode, which will start the NATS
|
14
15
|
server, configure it via Terraform, and update the Polyn Event Registry.
|
15
16
|
|
17
|
+
### Running NATS locally
|
18
|
+
|
19
|
+
`polyn up` will use run a Docker container for you if one is not already running. Alternatively, you can run `nats-server` yourself locally if you prefer.
|
20
|
+
|
21
|
+
## Naming Conventions
|
22
|
+
|
23
|
+
See the Protocol Documentation for [Naming Conventions](https://github.com/SpiffInc/polyn-protocol/blob/main/NAMING_CONVENTIONS.md)
|
24
|
+
|
16
25
|
## Streams
|
17
26
|
|
18
27
|
Each stream should have its own configuration file under `./tf` . Run `polyn gen:stream <stream_name>` to generate a new configuration file for a stream
|
@@ -32,6 +41,12 @@ Every schema should be a valid [JSON Schema](https://json-schema.org/) document.
|
|
32
41
|
The Polyn CLI tool will combine your event schema with the [Cloud Events Schema](https://cloudevents.io/) when it adds it to the Polyn Event Registry.
|
33
42
|
This means you only need to include the JSON Schema for the `data` portion of the Cloud Event and not the entire Cloud Event schema.
|
34
43
|
|
44
|
+
### Subdirectories
|
45
|
+
|
46
|
+
If you'd like to organize your events by team ownership or some other convention, you can use subdirectories to do so. The full event type should still be part of the file name. You should also ensure there are not duplicate event types in different directories as only one schema can be defined per event type.
|
47
|
+
|
48
|
+
You can generate a schema in a subdirectory like this: `polyn gen:schema some/nested/dir/widgets.created.v1`
|
49
|
+
|
35
50
|
## Schema Versioning
|
36
51
|
|
37
52
|
### New Event
|
@@ -49,3 +64,23 @@ Making a change to an event schema that is not backwards-compatible will require
|
|
49
64
|
json file. The new file should have the same name as your old file, but with the version number increased. Your
|
50
65
|
Producers will need to continue producing both events until you are sure there are no more consumers using the
|
51
66
|
old event.
|
67
|
+
|
68
|
+
## Terraform State
|
69
|
+
|
70
|
+
Terraform generates and maintains a [`terraform.tfstate`](https://www.terraform.io/language/state) file that is used to map terraform configuration to real production server instances. Polyn needs to interact with this file differently based on whether we are developing locally or in a production environment.
|
71
|
+
|
72
|
+
### Local Development
|
73
|
+
|
74
|
+
For local development Polyn expects the `terraform.tfstate` file to exist in the local file system. However, it should not be checked in to version control. We don't want experiments and updates made on a local developer machines to end up as the "source of truth" for our production infrastucture.
|
75
|
+
|
76
|
+
### Production
|
77
|
+
|
78
|
+
In production Terraform recommends keeping `terraform.tfstate` in a [remote storage location](https://www.terraform.io/language/state). The remote state file should be the "source of truth" for your infrastucture and shouldn't be getting accessed during development. Depending on the size of your organization and security policies, not all developers will have access to the remote storage source and you don't want that to prohibit them from adding events, streams, or consumers.
|
79
|
+
|
80
|
+
Polyn expects you to keep a `./remote_state_config/backend.tf` file that configures a Terraform [backend](https://www.terraform.io/language/settings/backends/configuration). This will only be used when `POLYN_ENV=production`.
|
81
|
+
|
82
|
+
## Deployment
|
83
|
+
|
84
|
+
The default `Dockerfile` generated by [Install the Polyn CLI](https://github.com/SpiffInc/polyn-cli) can help you create an image with the latest changes and nessary environment to run polyn commands.
|
85
|
+
|
86
|
+
The `bin/apply_changes.sh` script can be used to execute the polyn commands you need to update your production NATS server. You'll need to pass in `env` variables for `NATS_SERVERS` and `NATS_CREDENTIALS`. Also any `env` variables needed to connect to your remote state storage.
|
File without changes
|
@@ -0,0 +1,15 @@
|
|
1
|
+
variable "jetstream_servers" {
|
2
|
+
type = string
|
3
|
+
description = "The JetStream servers to connect to"
|
4
|
+
}
|
5
|
+
|
6
|
+
variable "nats_credentials" {
|
7
|
+
type = string
|
8
|
+
description = "Path to file with NATS credentials"
|
9
|
+
}
|
10
|
+
|
11
|
+
variable "polyn_env" {
|
12
|
+
type = string
|
13
|
+
description = "The environment terraform is running in"
|
14
|
+
default = "development"
|
15
|
+
}
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: polyn-cli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jarod
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date: 2022-08-
|
12
|
+
date: 2022-08-23 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: dotenv
|
@@ -89,6 +89,7 @@ files:
|
|
89
89
|
- LICENSE.txt
|
90
90
|
- README.md
|
91
91
|
- Rakefile
|
92
|
+
- bin/apply_changes.sh
|
92
93
|
- bin/console
|
93
94
|
- bin/setup
|
94
95
|
- exe/polyn
|
@@ -102,15 +103,21 @@ files:
|
|
102
103
|
- lib/polyn/cli/stream_generator.rb
|
103
104
|
- lib/polyn/cli/version.rb
|
104
105
|
- lib/polyn/cloud-event-schema.json
|
106
|
+
- lib/polyn/templates/.dockerignore
|
107
|
+
- lib/polyn/templates/.gitignore
|
108
|
+
- lib/polyn/templates/Dockerfile
|
109
|
+
- lib/polyn/templates/Gemfile
|
105
110
|
- lib/polyn/templates/README.md
|
106
111
|
- lib/polyn/templates/docker-compose.yml
|
107
112
|
- lib/polyn/templates/events/.gitkeep
|
108
113
|
- lib/polyn/templates/events/widgets.created.v1.json
|
109
114
|
- lib/polyn/templates/generators/schema.json
|
110
115
|
- lib/polyn/templates/generators/stream.tf
|
111
|
-
- lib/polyn/templates/
|
112
|
-
- lib/polyn/templates/tf/
|
113
|
-
- lib/polyn/templates/tf/
|
116
|
+
- lib/polyn/templates/tf/kv_buckets.tf
|
117
|
+
- lib/polyn/templates/tf/provider.tf
|
118
|
+
- lib/polyn/templates/tf/remote_state_config/backend.tf
|
119
|
+
- lib/polyn/templates/tf/variables.tf
|
120
|
+
- lib/polyn/templates/tf/versions.tf
|
114
121
|
- lib/polyn/templates/tf/widgets.tf
|
115
122
|
- polyn-cli.gemspec
|
116
123
|
homepage: https://github.com/Spiffinc/polyn-cli
|
@@ -1,17 +0,0 @@
|
|
1
|
-
terraform {
|
2
|
-
required_providers {
|
3
|
-
jetstream = {
|
4
|
-
source = "nats-io/jetstream"
|
5
|
-
}
|
6
|
-
}
|
7
|
-
|
8
|
-
}
|
9
|
-
|
10
|
-
variable "jetstream_servers" {
|
11
|
-
type = string
|
12
|
-
description = "The JetStream servers to connect to"
|
13
|
-
}
|
14
|
-
|
15
|
-
provider "jetstream" {
|
16
|
-
servers = var.jetstream_servers
|
17
|
-
}
|