polyn-cli 0.1.1 → 0.1.2
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/lib/polyn/cli/configuration.rb +4 -3
- data/lib/polyn/cli/schema_generator.rb +16 -5
- data/lib/polyn/cli/schema_loader.rb +28 -1
- data/lib/polyn/cli/version.rb +1 -1
- data/lib/polyn/cli.rb +53 -7
- data/lib/polyn/templates/.dockerignore +6 -0
- data/lib/polyn/templates/.gitignore +5 -0
- data/lib/polyn/templates/Dockerfile +20 -0
- data/lib/polyn/templates/Gemfile +3 -0
- data/lib/polyn/templates/README.md +35 -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 +11 -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: 4ae34f6e95adeb45fa4c421f9eb70960bf599e570a2934365efff5218948d954
|
4
|
+
data.tar.gz: f72f8e51082c3d68956bd28a78667d6e484e89c7e90aa87dc212ad6c1d7a59e5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cf5e0ff4dae1a5769da3f041f32a579a159c7fe00281d8a8f563e0c0642d55a3632010f47d7351b6e72592cfd781e6eea1d88091a3a51dd12c8e9045809ca040
|
7
|
+
data.tar.gz: 9a91d45f22c7c2ec3d3dce6e32776607d9da6d17d6c93a811c5219e4ae11cf0b47aa60bd0615fb705d857fe1fcd60df3e20243a92c4cfeb98e8170dfa892c0d6
|
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
|
@@ -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
|
@@ -41,7 +41,10 @@ module Polyn
|
|
41
41
|
attr_reader :thor, :events, :client, :bucket, :cloud_event_schema, :events_dir
|
42
42
|
|
43
43
|
def read_events
|
44
|
-
Dir.glob(File.join(events_dir, "
|
44
|
+
event_files = Dir.glob(File.join(events_dir, "/**/*.json"))
|
45
|
+
validate_unique_event_types!(event_files)
|
46
|
+
|
47
|
+
event_files.each do |event_file|
|
45
48
|
thor.say "Loading 'event #{event_file}'"
|
46
49
|
data_schema = JSON.parse(File.read(event_file))
|
47
50
|
event_type = File.basename(event_file, ".json")
|
@@ -53,6 +56,30 @@ module Polyn
|
|
53
56
|
end
|
54
57
|
end
|
55
58
|
|
59
|
+
def validate_unique_event_types!(event_files)
|
60
|
+
duplicates = find_duplicates(event_files)
|
61
|
+
unless duplicates.empty?
|
62
|
+
messages = duplicates.reduce([]) do |memo, (event_type, files)|
|
63
|
+
memo << [event_type, *files].join("\n")
|
64
|
+
end
|
65
|
+
message = [
|
66
|
+
"There can only be one of each event type. The following events were duplicated:",
|
67
|
+
*messages,
|
68
|
+
].join("\n")
|
69
|
+
raise Polyn::Cli::ValidationError, message
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def find_duplicates(event_files)
|
74
|
+
event_types = event_files.group_by do |event_file|
|
75
|
+
File.basename(event_file, ".json")
|
76
|
+
end
|
77
|
+
event_types.each_with_object({}) do |(event_type, files), hash|
|
78
|
+
hash[event_type] = files if files.length > 1
|
79
|
+
hash
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
56
83
|
def validate_schema!(event_type, schema)
|
57
84
|
JSONSchemer.schema(schema)
|
58
85
|
rescue StandardError => e
|
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
|
@@ -67,22 +70,44 @@ module Polyn
|
|
67
70
|
method_option :dir, default: Dir.getwd
|
68
71
|
desc "tf_init", "Initializes Terraform for configuration"
|
69
72
|
def tf_init
|
73
|
+
terraform_root = File.join(options.dir, "tf")
|
70
74
|
say "Initializing Terraform"
|
71
|
-
inside
|
72
|
-
|
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
|
73
91
|
end
|
74
92
|
end
|
75
93
|
|
76
94
|
desc "up", "updates the JetStream streams and consumers, as well the Polyn event registry"
|
77
95
|
def up
|
78
|
-
|
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?
|
79
100
|
say "Starting NATS"
|
80
101
|
run "docker compose up --detach"
|
81
102
|
end
|
82
103
|
|
83
104
|
say "Updating JetStream configuration"
|
84
105
|
inside "tf" do
|
85
|
-
|
106
|
+
if polyn_env == "production"
|
107
|
+
add_remote_backend(terraform_root) { run tf_apply }
|
108
|
+
else
|
109
|
+
run tf_apply
|
110
|
+
end
|
86
111
|
end
|
87
112
|
|
88
113
|
say "Updating Polyn event registry"
|
@@ -99,14 +124,35 @@ module Polyn
|
|
99
124
|
Polyn::Cli.configuration.nats_servers
|
100
125
|
end
|
101
126
|
|
127
|
+
def nats_credentials
|
128
|
+
Polyn::Cli.configuration.nats_credentials
|
129
|
+
end
|
130
|
+
|
102
131
|
def tf_apply
|
103
132
|
if polyn_env == "development"
|
104
|
-
%(terraform apply -var "jetstream_servers=#{nats_servers}" -auto-approve)
|
105
|
-
else
|
106
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\""
|
107
139
|
end
|
108
140
|
end
|
109
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
|
+
|
110
156
|
register(Polyn::Cli::SchemaGenerator, "gen:schema", "gen:schema EVENT_TYPE",
|
111
157
|
"Generates a new JSON Schema file for an event")
|
112
158
|
register(Polyn::Cli::StreamGenerator, "gen:stream", "gen:stream NAME",
|
@@ -0,0 +1,20 @@
|
|
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
|
+
RUN bundle exec polyn tf_init
|
15
|
+
CMD bundle exec polyn up
|
16
|
+
|
17
|
+
FROM app as prod
|
18
|
+
ENV POLYN_ENV='production'
|
19
|
+
RUN bundle exec polyn tf_init
|
20
|
+
CMD bundle exec polyn up
|
@@ -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,21 @@ 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 that will configure terraform and your infrastucture with the latest changes when you execute `docker run`. 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.2
|
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-22 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: dotenv
|
@@ -102,15 +102,21 @@ files:
|
|
102
102
|
- lib/polyn/cli/stream_generator.rb
|
103
103
|
- lib/polyn/cli/version.rb
|
104
104
|
- lib/polyn/cloud-event-schema.json
|
105
|
+
- lib/polyn/templates/.dockerignore
|
106
|
+
- lib/polyn/templates/.gitignore
|
107
|
+
- lib/polyn/templates/Dockerfile
|
108
|
+
- lib/polyn/templates/Gemfile
|
105
109
|
- lib/polyn/templates/README.md
|
106
110
|
- lib/polyn/templates/docker-compose.yml
|
107
111
|
- lib/polyn/templates/events/.gitkeep
|
108
112
|
- lib/polyn/templates/events/widgets.created.v1.json
|
109
113
|
- lib/polyn/templates/generators/schema.json
|
110
114
|
- lib/polyn/templates/generators/stream.tf
|
111
|
-
- lib/polyn/templates/
|
112
|
-
- lib/polyn/templates/tf/
|
113
|
-
- lib/polyn/templates/tf/
|
115
|
+
- lib/polyn/templates/tf/kv_buckets.tf
|
116
|
+
- lib/polyn/templates/tf/provider.tf
|
117
|
+
- lib/polyn/templates/tf/remote_state_config/backend.tf
|
118
|
+
- lib/polyn/templates/tf/variables.tf
|
119
|
+
- lib/polyn/templates/tf/versions.tf
|
114
120
|
- lib/polyn/templates/tf/widgets.tf
|
115
121
|
- polyn-cli.gemspec
|
116
122
|
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
|
-
}
|