nvoi 0.1.8 → 0.2.1
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 +4 -4
- data/Gemfile +1 -5
- data/Gemfile.lock +17 -8
- data/Rakefile +1 -1
- data/_TODO-rails-example.md +816 -0
- data/_TODO-rails-optimization.md +433 -0
- data/doc/config-schema.yaml +12 -0
- data/examples/apex-wildcard/deploy.yml +1 -0
- data/examples/golang-postgres-multi/deploy.yml +1 -0
- data/examples/postgres-multi/deploy.yml +1 -0
- data/examples/postgres-single/deploy.yml +1 -0
- data/examples/rails-single/deploy.yml +1 -0
- data/lib/nvoi/cli/config/command.rb +46 -41
- data/lib/nvoi/cli/credentials/edit/command.rb +24 -20
- data/lib/nvoi/cli/credentials/show/command.rb +1 -1
- data/lib/nvoi/cli/db/command.rb +10 -10
- data/lib/nvoi/cli/delete/command.rb +2 -2
- data/lib/nvoi/cli/deploy/command.rb +2 -2
- data/lib/nvoi/cli/deploy/steps/build_image.rb +2 -1
- data/lib/nvoi/cli/deploy/steps/configure_tunnel.rb +2 -2
- data/lib/nvoi/cli/deploy/steps/deploy_service.rb +7 -4
- data/lib/nvoi/cli/deploy/steps/provision_server.rb +1 -1
- data/lib/nvoi/cli/deploy/steps/provision_volume.rb +1 -1
- data/lib/nvoi/cli/exec/command.rb +3 -3
- data/lib/nvoi/cli/logs/command.rb +2 -2
- data/lib/nvoi/cli/onboard/command.rb +176 -622
- data/lib/nvoi/cli/onboard/steps/app.rb +108 -0
- data/lib/nvoi/cli/onboard/steps/app_name.rb +26 -0
- data/lib/nvoi/cli/onboard/steps/compute.rb +186 -0
- data/lib/nvoi/cli/onboard/steps/database.rb +97 -0
- data/lib/nvoi/cli/onboard/steps/domain.rb +48 -0
- data/lib/nvoi/cli/onboard/steps/env.rb +67 -0
- data/lib/nvoi/cli/onboard/ui.rb +84 -0
- data/lib/nvoi/cli/unlock/command.rb +2 -2
- data/lib/nvoi/cli.rb +2 -33
- data/lib/nvoi/configuration/app_service.rb +54 -0
- data/lib/nvoi/configuration/application.rb +44 -0
- data/lib/nvoi/configuration/builder.rb +420 -0
- data/lib/nvoi/configuration/database.rb +56 -0
- data/lib/nvoi/configuration/deploy.rb +15 -0
- data/lib/nvoi/{objects/service_spec.rb → configuration/deployment.rb} +4 -3
- data/lib/nvoi/{objects/config_override.rb → configuration/override.rb} +4 -4
- data/lib/nvoi/configuration/providers.rb +81 -0
- data/lib/nvoi/configuration/result.rb +43 -0
- data/lib/nvoi/configuration/root.rb +252 -0
- data/lib/nvoi/configuration/server.rb +39 -0
- data/lib/nvoi/configuration/service.rb +51 -0
- data/lib/nvoi/configuration/ssh_key.rb +16 -0
- data/lib/nvoi/external/cloud/aws.rb +26 -16
- data/lib/nvoi/external/cloud/hetzner.rb +40 -25
- data/lib/nvoi/external/cloud/scaleway.rb +10 -8
- data/lib/nvoi/external/cloud/types.rb +42 -0
- data/lib/nvoi/external/database/mysql.rb +1 -1
- data/lib/nvoi/external/database/postgres.rb +1 -1
- data/lib/nvoi/external/database/provider.rb +1 -1
- data/lib/nvoi/external/database/sqlite.rb +1 -1
- data/lib/nvoi/external/database/types.rb +55 -0
- data/lib/nvoi/external/dns/cloudflare.rb +11 -11
- data/lib/nvoi/external/dns/types.rb +24 -0
- data/lib/nvoi/utils/config_loader.rb +12 -12
- data/lib/nvoi/utils/credential_store.rb +4 -4
- data/lib/nvoi/utils/env_resolver.rb +3 -3
- data/lib/nvoi/utils/namer.rb +8 -3
- data/lib/nvoi/utils/presence.rb +23 -0
- data/lib/nvoi/version.rb +1 -1
- data/lib/nvoi.rb +2 -17
- metadata +98 -59
- data/.claude/todo/refactor/00-overview.md +0 -171
- data/.claude/todo/refactor/01-objects.md +0 -96
- data/.claude/todo/refactor/02-utils.md +0 -143
- data/.claude/todo/refactor/03-external-cloud.md +0 -164
- data/.claude/todo/refactor/04-external-dns.md +0 -104
- data/.claude/todo/refactor/05-external.md +0 -133
- data/.claude/todo/refactor/06-cli.md +0 -123
- data/.claude/todo/refactor/07-cli-deploy-command.md +0 -177
- data/.claude/todo/refactor/08-cli-deploy-steps.md +0 -201
- data/.claude/todo/refactor/09-cli-delete-command.md +0 -169
- data/.claude/todo/refactor/10-cli-exec-command.md +0 -157
- data/.claude/todo/refactor/11-cli-credentials-command.md +0 -190
- data/.claude/todo/refactor/12-cli-db-command.md +0 -128
- data/.claude/todo/refactor/_target.md +0 -79
- data/.claude/todo/refactor-execution/00-entrypoint.md +0 -49
- data/.claude/todo/refactor-execution/01-objects.md +0 -42
- data/.claude/todo/refactor-execution/02-utils.md +0 -41
- data/.claude/todo/refactor-execution/03-external-cloud.md +0 -38
- data/.claude/todo/refactor-execution/04-external-dns.md +0 -35
- data/.claude/todo/refactor-execution/05-external-other.md +0 -46
- data/.claude/todo/refactor-execution/06-cli-deploy.md +0 -45
- data/.claude/todo/refactor-execution/07-cli-delete.md +0 -43
- data/.claude/todo/refactor-execution/08-cli-exec.md +0 -30
- data/.claude/todo/refactor-execution/09-cli-credentials.md +0 -34
- data/.claude/todo/refactor-execution/10-cli-db.md +0 -31
- data/.claude/todo/refactor-execution/11-cli-router.md +0 -44
- data/.claude/todo/refactor-execution/12-cleanup.md +0 -120
- data/.claude/todo/refactor-execution/_monitoring-strategy.md +0 -126
- data/.claude/todo/scaleway.impl.md +0 -644
- data/.claude/todo/scaleway.reference.md +0 -520
- data/.claude/todos/buckets.md +0 -41
- data/.claude/todos.md +0 -550
- data/Makefile +0 -26
- data/ingest +0 -0
- data/lib/nvoi/config_api/actions/app.rb +0 -53
- data/lib/nvoi/config_api/actions/compute_provider.rb +0 -55
- data/lib/nvoi/config_api/actions/database.rb +0 -70
- data/lib/nvoi/config_api/actions/domain_provider.rb +0 -40
- data/lib/nvoi/config_api/actions/env.rb +0 -32
- data/lib/nvoi/config_api/actions/init.rb +0 -67
- data/lib/nvoi/config_api/actions/secret.rb +0 -32
- data/lib/nvoi/config_api/actions/server.rb +0 -66
- data/lib/nvoi/config_api/actions/service.rb +0 -52
- data/lib/nvoi/config_api/actions/volume.rb +0 -40
- data/lib/nvoi/config_api/base.rb +0 -38
- data/lib/nvoi/config_api/result.rb +0 -26
- data/lib/nvoi/config_api.rb +0 -93
- data/lib/nvoi/objects/configuration.rb +0 -483
- data/lib/nvoi/objects/database.rb +0 -56
- data/lib/nvoi/objects/dns.rb +0 -14
- data/lib/nvoi/objects/firewall.rb +0 -11
- data/lib/nvoi/objects/network.rb +0 -11
- data/lib/nvoi/objects/server.rb +0 -14
- data/lib/nvoi/objects/tunnel.rb +0 -14
- data/lib/nvoi/objects/volume.rb +0 -17
|
@@ -4,7 +4,7 @@ module Nvoi
|
|
|
4
4
|
class Cli
|
|
5
5
|
module Config
|
|
6
6
|
# Command helper for all config operations
|
|
7
|
-
# Uses CredentialStore for crypto,
|
|
7
|
+
# Uses CredentialStore for crypto, Configuration::Builder for transformations
|
|
8
8
|
class Command
|
|
9
9
|
def initialize(options)
|
|
10
10
|
@options = options
|
|
@@ -13,7 +13,7 @@ module Nvoi
|
|
|
13
13
|
|
|
14
14
|
# Initialize new config
|
|
15
15
|
def init(name, environment)
|
|
16
|
-
result =
|
|
16
|
+
result = Configuration::Builder.init(name:, environment:)
|
|
17
17
|
|
|
18
18
|
if result.failure?
|
|
19
19
|
error("Failed to initialize: #{result.error_message}")
|
|
@@ -40,118 +40,118 @@ module Nvoi
|
|
|
40
40
|
|
|
41
41
|
# Domain provider
|
|
42
42
|
def domain_set(provider, api_token:, account_id:)
|
|
43
|
-
with_config do |
|
|
44
|
-
|
|
43
|
+
with_config do |builder|
|
|
44
|
+
builder.domain_provider(provider, api_token:, account_id:)
|
|
45
45
|
end
|
|
46
46
|
end
|
|
47
47
|
|
|
48
48
|
def domain_rm
|
|
49
|
-
with_config do |
|
|
50
|
-
|
|
49
|
+
with_config do |builder|
|
|
50
|
+
builder.remove_domain_provider
|
|
51
51
|
end
|
|
52
52
|
end
|
|
53
53
|
|
|
54
54
|
# Compute provider
|
|
55
55
|
def provider_set(provider, **opts)
|
|
56
|
-
with_config do |
|
|
57
|
-
|
|
56
|
+
with_config do |builder|
|
|
57
|
+
builder.compute_provider(provider, **opts)
|
|
58
58
|
end
|
|
59
59
|
end
|
|
60
60
|
|
|
61
61
|
def provider_rm
|
|
62
|
-
with_config do |
|
|
63
|
-
|
|
62
|
+
with_config do |builder|
|
|
63
|
+
builder.remove_compute_provider
|
|
64
64
|
end
|
|
65
65
|
end
|
|
66
66
|
|
|
67
67
|
# Server
|
|
68
68
|
def server_set(name, master: false, type: nil, location: nil, count: 1)
|
|
69
|
-
with_config do |
|
|
70
|
-
|
|
69
|
+
with_config do |builder|
|
|
70
|
+
builder.server(name, master:, type:, location:, count:)
|
|
71
71
|
end
|
|
72
72
|
end
|
|
73
73
|
|
|
74
74
|
def server_rm(name)
|
|
75
|
-
with_config do |
|
|
76
|
-
|
|
75
|
+
with_config do |builder|
|
|
76
|
+
builder.remove_server(name)
|
|
77
77
|
end
|
|
78
78
|
end
|
|
79
79
|
|
|
80
80
|
# Volume
|
|
81
81
|
def volume_set(server, name, size: 10)
|
|
82
|
-
with_config do |
|
|
83
|
-
|
|
82
|
+
with_config do |builder|
|
|
83
|
+
builder.volume(server, name, size:)
|
|
84
84
|
end
|
|
85
85
|
end
|
|
86
86
|
|
|
87
87
|
def volume_rm(server, name)
|
|
88
|
-
with_config do |
|
|
89
|
-
|
|
88
|
+
with_config do |builder|
|
|
89
|
+
builder.remove_volume(server, name)
|
|
90
90
|
end
|
|
91
91
|
end
|
|
92
92
|
|
|
93
93
|
# App
|
|
94
94
|
def app_set(name, servers:, **opts)
|
|
95
|
-
with_config do |
|
|
96
|
-
|
|
95
|
+
with_config do |builder|
|
|
96
|
+
builder.app_entry(name, servers:, **opts)
|
|
97
97
|
end
|
|
98
98
|
end
|
|
99
99
|
|
|
100
100
|
def app_rm(name)
|
|
101
|
-
with_config do |
|
|
102
|
-
|
|
101
|
+
with_config do |builder|
|
|
102
|
+
builder.remove_app(name)
|
|
103
103
|
end
|
|
104
104
|
end
|
|
105
105
|
|
|
106
106
|
# Database
|
|
107
107
|
def database_set(servers:, adapter:, **opts)
|
|
108
|
-
with_config do |
|
|
109
|
-
|
|
108
|
+
with_config do |builder|
|
|
109
|
+
builder.database(servers:, adapter:, **opts)
|
|
110
110
|
end
|
|
111
111
|
end
|
|
112
112
|
|
|
113
113
|
def database_rm
|
|
114
|
-
with_config do |
|
|
115
|
-
|
|
114
|
+
with_config do |builder|
|
|
115
|
+
builder.remove_database
|
|
116
116
|
end
|
|
117
117
|
end
|
|
118
118
|
|
|
119
119
|
# Service
|
|
120
120
|
def service_set(name, servers:, image:, **opts)
|
|
121
|
-
with_config do |
|
|
122
|
-
|
|
121
|
+
with_config do |builder|
|
|
122
|
+
builder.service(name, servers:, image:, **opts)
|
|
123
123
|
end
|
|
124
124
|
end
|
|
125
125
|
|
|
126
126
|
def service_rm(name)
|
|
127
|
-
with_config do |
|
|
128
|
-
|
|
127
|
+
with_config do |builder|
|
|
128
|
+
builder.remove_service(name)
|
|
129
129
|
end
|
|
130
130
|
end
|
|
131
131
|
|
|
132
132
|
# Secret
|
|
133
133
|
def secret_set(key_name, value)
|
|
134
|
-
with_config do |
|
|
135
|
-
|
|
134
|
+
with_config do |builder|
|
|
135
|
+
builder.secret(key_name, value)
|
|
136
136
|
end
|
|
137
137
|
end
|
|
138
138
|
|
|
139
139
|
def secret_rm(key_name)
|
|
140
|
-
with_config do |
|
|
141
|
-
|
|
140
|
+
with_config do |builder|
|
|
141
|
+
builder.remove_secret(key_name)
|
|
142
142
|
end
|
|
143
143
|
end
|
|
144
144
|
|
|
145
145
|
# Env
|
|
146
146
|
def env_set(key_name, value)
|
|
147
|
-
with_config do |
|
|
148
|
-
|
|
147
|
+
with_config do |builder|
|
|
148
|
+
builder.env(key_name, value)
|
|
149
149
|
end
|
|
150
150
|
end
|
|
151
151
|
|
|
152
152
|
def env_rm(key_name)
|
|
153
|
-
with_config do |
|
|
154
|
-
|
|
153
|
+
with_config do |builder|
|
|
154
|
+
builder.remove_env(key_name)
|
|
155
155
|
end
|
|
156
156
|
end
|
|
157
157
|
|
|
@@ -174,20 +174,25 @@ module Nvoi
|
|
|
174
174
|
yaml = store.read
|
|
175
175
|
data = YAML.safe_load(yaml, permitted_classes: [Symbol])
|
|
176
176
|
|
|
177
|
-
# Transform
|
|
178
|
-
|
|
177
|
+
# Transform using Builder
|
|
178
|
+
builder = Configuration::Builder.from_hash(data)
|
|
179
|
+
result = yield(builder)
|
|
179
180
|
|
|
180
181
|
if result.failure?
|
|
181
182
|
error("#{result.error_type}: #{result.error_message}")
|
|
182
183
|
else
|
|
183
184
|
# Serialize and write
|
|
184
|
-
store.write(
|
|
185
|
+
store.write(builder.to_yaml)
|
|
185
186
|
success("Config updated")
|
|
186
187
|
end
|
|
187
188
|
rescue Errors::CredentialError => e
|
|
188
189
|
error(e.message)
|
|
189
190
|
rescue Errors::DecryptionError => e
|
|
190
191
|
error("Decryption failed: #{e.message}")
|
|
192
|
+
rescue ArgumentError => e
|
|
193
|
+
error("invalid_args: #{e.message}")
|
|
194
|
+
rescue Errors::ConfigValidationError => e
|
|
195
|
+
error("validation_error: #{e.message}")
|
|
191
196
|
end
|
|
192
197
|
|
|
193
198
|
def update_gitignore
|
|
@@ -151,7 +151,7 @@ module Nvoi
|
|
|
151
151
|
|
|
152
152
|
def resolve_working_dir
|
|
153
153
|
wd = @options[:dir]
|
|
154
|
-
if wd.
|
|
154
|
+
if wd.blank? || wd == "."
|
|
155
155
|
Dir.pwd
|
|
156
156
|
else
|
|
157
157
|
File.expand_path(wd)
|
|
@@ -160,7 +160,7 @@ module Nvoi
|
|
|
160
160
|
|
|
161
161
|
def resolve_enc_path(working_dir)
|
|
162
162
|
enc_path = @options[:credentials]
|
|
163
|
-
return File.join(working_dir, DEFAULT_ENCRYPTED_FILE) if enc_path.
|
|
163
|
+
return File.join(working_dir, DEFAULT_ENCRYPTED_FILE) if enc_path.blank?
|
|
164
164
|
|
|
165
165
|
enc_path
|
|
166
166
|
end
|
|
@@ -184,18 +184,18 @@ module Nvoi
|
|
|
184
184
|
return "application section is required" unless app.is_a?(Hash)
|
|
185
185
|
|
|
186
186
|
# Application name
|
|
187
|
-
return "application.name is required" if app["name"].
|
|
187
|
+
return "application.name is required" if app["name"].blank?
|
|
188
188
|
|
|
189
189
|
# Environment
|
|
190
|
-
return "application.environment is required" if app["environment"].
|
|
190
|
+
return "application.environment is required" if app["environment"].blank?
|
|
191
191
|
|
|
192
192
|
# Domain provider
|
|
193
193
|
domain_provider = app["domain_provider"]
|
|
194
194
|
return "application.domain_provider.cloudflare is required" unless domain_provider&.dig("cloudflare")
|
|
195
195
|
|
|
196
196
|
cf = domain_provider["cloudflare"]
|
|
197
|
-
return "application.domain_provider.cloudflare.api_token is required" if cf["api_token"].
|
|
198
|
-
return "application.domain_provider.cloudflare.account_id is required" if cf["account_id"].
|
|
197
|
+
return "application.domain_provider.cloudflare.api_token is required" if cf["api_token"].blank?
|
|
198
|
+
return "application.domain_provider.cloudflare.account_id is required" if cf["account_id"].blank?
|
|
199
199
|
|
|
200
200
|
# Compute provider
|
|
201
201
|
compute_provider = app["compute_provider"]
|
|
@@ -203,22 +203,25 @@ module Nvoi
|
|
|
203
203
|
return "compute_provider (hetzner, aws, or scaleway) is required" unless has_compute
|
|
204
204
|
|
|
205
205
|
if (h = compute_provider&.dig("hetzner"))
|
|
206
|
-
return "application.compute_provider.hetzner.api_token is required" if h["api_token"].
|
|
207
|
-
return "application.compute_provider.hetzner.server_type is required" if h["server_type"].
|
|
208
|
-
return "application.compute_provider.hetzner.server_location is required" if h["server_location"].
|
|
206
|
+
return "application.compute_provider.hetzner.api_token is required" if h["api_token"].blank?
|
|
207
|
+
return "application.compute_provider.hetzner.server_type is required" if h["server_type"].blank?
|
|
208
|
+
return "application.compute_provider.hetzner.server_location is required" if h["server_location"].blank?
|
|
209
|
+
return "application.compute_provider.hetzner.architecture is required" if h["architecture"].blank?
|
|
209
210
|
end
|
|
210
211
|
|
|
211
212
|
if (a = compute_provider&.dig("aws"))
|
|
212
|
-
return "application.compute_provider.aws.access_key_id is required" if a["access_key_id"].
|
|
213
|
-
return "application.compute_provider.aws.secret_access_key is required" if a["secret_access_key"].
|
|
214
|
-
return "application.compute_provider.aws.region is required" if a["region"].
|
|
215
|
-
return "application.compute_provider.aws.instance_type is required" if a["instance_type"].
|
|
213
|
+
return "application.compute_provider.aws.access_key_id is required" if a["access_key_id"].blank?
|
|
214
|
+
return "application.compute_provider.aws.secret_access_key is required" if a["secret_access_key"].blank?
|
|
215
|
+
return "application.compute_provider.aws.region is required" if a["region"].blank?
|
|
216
|
+
return "application.compute_provider.aws.instance_type is required" if a["instance_type"].blank?
|
|
217
|
+
return "application.compute_provider.aws.architecture is required" if a["architecture"].blank?
|
|
216
218
|
end
|
|
217
219
|
|
|
218
220
|
if (s = compute_provider&.dig("scaleway"))
|
|
219
|
-
return "application.compute_provider.scaleway.secret_key is required" if s["secret_key"].
|
|
220
|
-
return "application.compute_provider.scaleway.project_id is required" if s["project_id"].
|
|
221
|
-
return "application.compute_provider.scaleway.server_type is required" if s["server_type"].
|
|
221
|
+
return "application.compute_provider.scaleway.secret_key is required" if s["secret_key"].blank?
|
|
222
|
+
return "application.compute_provider.scaleway.project_id is required" if s["project_id"].blank?
|
|
223
|
+
return "application.compute_provider.scaleway.server_type is required" if s["server_type"].blank?
|
|
224
|
+
return "application.compute_provider.scaleway.architecture is required" if s["architecture"].blank?
|
|
222
225
|
end
|
|
223
226
|
|
|
224
227
|
# Servers (if any services defined)
|
|
@@ -236,7 +239,7 @@ module Nvoi
|
|
|
236
239
|
app_services.each do |service_name, svc|
|
|
237
240
|
next unless svc
|
|
238
241
|
|
|
239
|
-
return "app.#{service_name}.servers is required" if svc["servers"].
|
|
242
|
+
return "app.#{service_name}.servers is required" if svc["servers"].to_a.empty?
|
|
240
243
|
|
|
241
244
|
svc["servers"].each do |ref|
|
|
242
245
|
return "app.#{service_name} references undefined server: #{ref}" unless defined_servers.include?(ref)
|
|
@@ -245,7 +248,7 @@ module Nvoi
|
|
|
245
248
|
|
|
246
249
|
# Validate database
|
|
247
250
|
if database
|
|
248
|
-
return "database.servers is required" if database["servers"].
|
|
251
|
+
return "database.servers is required" if database["servers"].to_a.empty?
|
|
249
252
|
|
|
250
253
|
database["servers"].each do |ref|
|
|
251
254
|
return "database references undefined server: #{ref}" unless defined_servers.include?(ref)
|
|
@@ -268,10 +271,10 @@ module Nvoi
|
|
|
268
271
|
adapter = db["adapter"]&.downcase
|
|
269
272
|
url = db["url"]
|
|
270
273
|
|
|
271
|
-
return "database.adapter is required" if adapter.
|
|
274
|
+
return "database.adapter is required" if adapter.blank?
|
|
272
275
|
|
|
273
276
|
# URL takes precedence - if provided, no secrets needed
|
|
274
|
-
has_url =
|
|
277
|
+
has_url = !url.blank?
|
|
275
278
|
|
|
276
279
|
case adapter
|
|
277
280
|
when "postgres", "postgresql"
|
|
@@ -317,6 +320,7 @@ module Nvoi
|
|
|
317
320
|
api_token: YOUR_HETZNER_API_TOKEN
|
|
318
321
|
server_type: cx22
|
|
319
322
|
server_location: fsn1
|
|
323
|
+
architecture: x86
|
|
320
324
|
|
|
321
325
|
servers:
|
|
322
326
|
master:
|
data/lib/nvoi/cli/db/command.rb
CHANGED
|
@@ -60,7 +60,7 @@ module Nvoi
|
|
|
60
60
|
result = ssh.execute("test -f #{metadata_file} && cat #{metadata_file} || echo '{}'")
|
|
61
61
|
|
|
62
62
|
begin
|
|
63
|
-
metadata =
|
|
63
|
+
metadata = External::Database::Types::BranchMetadata.from_json(result)
|
|
64
64
|
branches = metadata.branches
|
|
65
65
|
rescue JSON::ParserError
|
|
66
66
|
branches = []
|
|
@@ -185,9 +185,9 @@ module Nvoi
|
|
|
185
185
|
|
|
186
186
|
def apply_branch_override
|
|
187
187
|
branch = @options[:branch]
|
|
188
|
-
return if branch.
|
|
188
|
+
return if branch.blank?
|
|
189
189
|
|
|
190
|
-
override =
|
|
190
|
+
override = Configuration::Override.new(branch:)
|
|
191
191
|
override.apply(@config)
|
|
192
192
|
end
|
|
193
193
|
|
|
@@ -204,12 +204,12 @@ module Nvoi
|
|
|
204
204
|
|
|
205
205
|
def build_dump_options
|
|
206
206
|
if @db_provider.is_a?(External::Database::Sqlite)
|
|
207
|
-
|
|
207
|
+
External::Database::Types::DumpOptions.new(
|
|
208
208
|
host_path: @creds.host_path,
|
|
209
209
|
database: @creds.database
|
|
210
210
|
)
|
|
211
211
|
else
|
|
212
|
-
|
|
212
|
+
External::Database::Types::DumpOptions.new(
|
|
213
213
|
pod_name: @config.namer.database_pod_name,
|
|
214
214
|
database: @creds.database,
|
|
215
215
|
user: @creds.user,
|
|
@@ -222,12 +222,12 @@ module Nvoi
|
|
|
222
222
|
sanitized_name = sanitize_db_name(new_db_name)
|
|
223
223
|
|
|
224
224
|
if @db_provider.is_a?(External::Database::Sqlite)
|
|
225
|
-
|
|
225
|
+
External::Database::Types::RestoreOptions.new(
|
|
226
226
|
host_path: @creds.host_path,
|
|
227
227
|
database: sanitized_name
|
|
228
228
|
)
|
|
229
229
|
else
|
|
230
|
-
|
|
230
|
+
External::Database::Types::RestoreOptions.new(
|
|
231
231
|
pod_name: @config.namer.database_pod_name,
|
|
232
232
|
database: sanitized_name,
|
|
233
233
|
user: @creds.user,
|
|
@@ -255,12 +255,12 @@ module Nvoi
|
|
|
255
255
|
result = ssh.execute("test -f #{metadata_file} && cat #{metadata_file} || echo '{}'")
|
|
256
256
|
|
|
257
257
|
metadata = begin
|
|
258
|
-
|
|
258
|
+
External::Database::Types::BranchMetadata.from_json(result)
|
|
259
259
|
rescue JSON::ParserError
|
|
260
|
-
|
|
260
|
+
External::Database::Types::BranchMetadata.new
|
|
261
261
|
end
|
|
262
262
|
|
|
263
|
-
metadata.branches <<
|
|
263
|
+
metadata.branches << External::Database::Types::Branch.new(
|
|
264
264
|
id: branch_id,
|
|
265
265
|
created_at: Time.now.iso8601,
|
|
266
266
|
size:,
|
|
@@ -64,9 +64,9 @@ module Nvoi
|
|
|
64
64
|
|
|
65
65
|
def apply_branch_override
|
|
66
66
|
branch = @options[:branch]
|
|
67
|
-
return if branch.
|
|
67
|
+
return if branch.blank?
|
|
68
68
|
|
|
69
|
-
override =
|
|
69
|
+
override = Configuration::Override.new(branch:)
|
|
70
70
|
override.apply(@config)
|
|
71
71
|
end
|
|
72
72
|
end
|
|
@@ -65,9 +65,9 @@ module Nvoi
|
|
|
65
65
|
|
|
66
66
|
def apply_branch_override
|
|
67
67
|
branch = @options[:branch]
|
|
68
|
-
return if branch.
|
|
68
|
+
return if branch.blank?
|
|
69
69
|
|
|
70
|
-
override =
|
|
70
|
+
override = Configuration::Override.new(branch:)
|
|
71
71
|
override.apply(@config)
|
|
72
72
|
end
|
|
73
73
|
|
|
@@ -28,11 +28,12 @@ module Nvoi
|
|
|
28
28
|
def build_image(working_dir, tag)
|
|
29
29
|
cache_from = @config.namer.latest_image_tag
|
|
30
30
|
cache_args = "--cache-from #{cache_from}"
|
|
31
|
+
platform = @config.docker_platform
|
|
31
32
|
|
|
32
33
|
build_cmd = [
|
|
33
34
|
"cd #{working_dir} &&",
|
|
34
35
|
"DOCKER_BUILDKIT=1 docker build",
|
|
35
|
-
"--platform
|
|
36
|
+
"--platform #{platform}",
|
|
36
37
|
cache_args,
|
|
37
38
|
"--build-arg BUILDKIT_INLINE_CACHE=1",
|
|
38
39
|
"-t #{tag} ."
|
|
@@ -43,7 +43,7 @@ module Nvoi
|
|
|
43
43
|
|
|
44
44
|
tunnel = setup_tunnel(tunnel_name, hostnames, service_url, service_config.domain)
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
External::Dns::Types::Tunnel::Info.new(
|
|
47
47
|
service_name:,
|
|
48
48
|
hostname: primary_hostname,
|
|
49
49
|
tunnel_id: tunnel.tunnel_id,
|
|
@@ -90,7 +90,7 @@ module Nvoi
|
|
|
90
90
|
|
|
91
91
|
@log.success "Tunnel configured: %s", tunnel_name
|
|
92
92
|
|
|
93
|
-
|
|
93
|
+
External::Dns::Types::Tunnel::Info.new(
|
|
94
94
|
tunnel_id: tunnel.id,
|
|
95
95
|
tunnel_token: token
|
|
96
96
|
)
|
|
@@ -345,18 +345,21 @@ module Nvoi
|
|
|
345
345
|
end
|
|
346
346
|
|
|
347
347
|
def check_public_url(url)
|
|
348
|
-
|
|
348
|
+
# -L follows redirects, -s silent, -i include headers, -m timeout
|
|
349
|
+
curl_cmd = "curl -Lsi -m 10 '#{url}' 2>/dev/null"
|
|
349
350
|
output = @ssh.execute(curl_cmd).strip
|
|
350
351
|
|
|
351
|
-
|
|
352
|
+
# With -L, last HTTP line is the final response after redirects
|
|
353
|
+
http_lines = output.lines.select { |l| l.match?(/^HTTP\/[\d.]+\s+\d+/) }
|
|
354
|
+
http_code = http_lines.last&.match(/HTTP\/[\d.]+ (\d+)/)&.captures&.first || "000"
|
|
352
355
|
has_error_header = output.lines.any? { |line| line.downcase.start_with?("x-nvoi-error:") }
|
|
353
356
|
|
|
354
|
-
if http_code
|
|
357
|
+
if http_code.start_with?("2") && !has_error_header
|
|
355
358
|
{ success: true, http_code:, message: "OK" }
|
|
356
359
|
elsif has_error_header
|
|
357
360
|
{ success: false, http_code:, message: "Error backend responding (X-Nvoi-Error header present) - app is down" }
|
|
358
361
|
else
|
|
359
|
-
{ success: false, http_code:, message: "HTTP #{http_code} (expected:
|
|
362
|
+
{ success: false, http_code:, message: "HTTP #{http_code} (expected: 2xx)" }
|
|
360
363
|
end
|
|
361
364
|
end
|
|
362
365
|
|
|
@@ -66,7 +66,7 @@ module Nvoi
|
|
|
66
66
|
raise Errors::VolumeError, "server not found: #{vol_config[:server_name]}" unless server
|
|
67
67
|
|
|
68
68
|
# Create volume
|
|
69
|
-
opts =
|
|
69
|
+
opts = External::Cloud::Types::Volume::CreateOptions.new(
|
|
70
70
|
name: vol_config[:name],
|
|
71
71
|
size: vol_config[:size],
|
|
72
72
|
server_id: server.id
|
|
@@ -55,9 +55,9 @@ module Nvoi
|
|
|
55
55
|
|
|
56
56
|
def apply_branch_override
|
|
57
57
|
branch = @options[:branch]
|
|
58
|
-
return if branch.
|
|
58
|
+
return if branch.blank?
|
|
59
59
|
|
|
60
|
-
override =
|
|
60
|
+
override = Configuration::Override.new(branch:)
|
|
61
61
|
override.apply(@config)
|
|
62
62
|
end
|
|
63
63
|
|
|
@@ -132,7 +132,7 @@ module Nvoi
|
|
|
132
132
|
end
|
|
133
133
|
|
|
134
134
|
def resolve_server_name(name)
|
|
135
|
-
return @config.server_name if name.
|
|
135
|
+
return @config.server_name if name.blank? || name == "main"
|
|
136
136
|
|
|
137
137
|
parts = name.split("-")
|
|
138
138
|
if parts.length >= 2
|
|
@@ -55,9 +55,9 @@ module Nvoi
|
|
|
55
55
|
|
|
56
56
|
def apply_branch_override
|
|
57
57
|
branch = @options[:branch]
|
|
58
|
-
return if branch.
|
|
58
|
+
return if branch.blank?
|
|
59
59
|
|
|
60
|
-
override =
|
|
60
|
+
override = Configuration::Override.new(branch:)
|
|
61
61
|
override.apply(@config)
|
|
62
62
|
end
|
|
63
63
|
end
|