nvoi 0.1.5 → 0.1.7

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.
Files changed (156) hide show
  1. checksums.yaml +4 -4
  2. data/.claude/todo/refactor/00-overview.md +171 -0
  3. data/.claude/todo/refactor/01-objects.md +96 -0
  4. data/.claude/todo/refactor/02-utils.md +143 -0
  5. data/.claude/todo/refactor/03-external-cloud.md +164 -0
  6. data/.claude/todo/refactor/04-external-dns.md +104 -0
  7. data/.claude/todo/refactor/05-external.md +133 -0
  8. data/.claude/todo/refactor/06-cli.md +123 -0
  9. data/.claude/todo/refactor/07-cli-deploy-command.md +177 -0
  10. data/.claude/todo/refactor/08-cli-deploy-steps.md +201 -0
  11. data/.claude/todo/refactor/09-cli-delete-command.md +169 -0
  12. data/.claude/todo/refactor/10-cli-exec-command.md +157 -0
  13. data/.claude/todo/refactor/11-cli-credentials-command.md +190 -0
  14. data/.claude/todo/refactor/12-cli-db-command.md +128 -0
  15. data/.claude/todo/refactor/_target.md +79 -0
  16. data/.claude/todo/refactor-execution/00-entrypoint.md +49 -0
  17. data/.claude/todo/refactor-execution/01-objects.md +42 -0
  18. data/.claude/todo/refactor-execution/02-utils.md +41 -0
  19. data/.claude/todo/refactor-execution/03-external-cloud.md +38 -0
  20. data/.claude/todo/refactor-execution/04-external-dns.md +35 -0
  21. data/.claude/todo/refactor-execution/05-external-other.md +46 -0
  22. data/.claude/todo/refactor-execution/06-cli-deploy.md +45 -0
  23. data/.claude/todo/refactor-execution/07-cli-delete.md +43 -0
  24. data/.claude/todo/refactor-execution/08-cli-exec.md +30 -0
  25. data/.claude/todo/refactor-execution/09-cli-credentials.md +34 -0
  26. data/.claude/todo/refactor-execution/10-cli-db.md +31 -0
  27. data/.claude/todo/refactor-execution/11-cli-router.md +44 -0
  28. data/.claude/todo/refactor-execution/12-cleanup.md +120 -0
  29. data/.claude/todo/refactor-execution/_monitoring-strategy.md +126 -0
  30. data/.claude/todo/scaleway.impl.md +644 -0
  31. data/.claude/todo/scaleway.reference.md +520 -0
  32. data/.claude/todos.md +550 -0
  33. data/Gemfile +6 -0
  34. data/Gemfile.lock +46 -5
  35. data/Rakefile +1 -1
  36. data/doc/config-schema.yaml +44 -11
  37. data/examples/golang/deploy.enc +0 -0
  38. data/examples/golang/main.go +18 -0
  39. data/exe/nvoi +3 -1
  40. data/ingest +0 -0
  41. data/lib/nvoi/cli/config/command.rb +219 -0
  42. data/lib/nvoi/cli/credentials/edit/command.rb +384 -0
  43. data/lib/nvoi/cli/credentials/show/command.rb +35 -0
  44. data/lib/nvoi/cli/db/command.rb +308 -0
  45. data/lib/nvoi/cli/delete/command.rb +75 -0
  46. data/lib/nvoi/cli/delete/steps/detach_volumes.rb +98 -0
  47. data/lib/nvoi/cli/delete/steps/teardown_dns.rb +50 -0
  48. data/lib/nvoi/cli/delete/steps/teardown_firewall.rb +46 -0
  49. data/lib/nvoi/cli/delete/steps/teardown_network.rb +30 -0
  50. data/lib/nvoi/cli/delete/steps/teardown_server.rb +50 -0
  51. data/lib/nvoi/cli/delete/steps/teardown_tunnel.rb +44 -0
  52. data/lib/nvoi/cli/delete/steps/teardown_volume.rb +61 -0
  53. data/lib/nvoi/cli/deploy/command.rb +184 -0
  54. data/lib/nvoi/cli/deploy/steps/build_image.rb +27 -0
  55. data/lib/nvoi/cli/deploy/steps/cleanup_images.rb +42 -0
  56. data/lib/nvoi/cli/deploy/steps/configure_tunnel.rb +102 -0
  57. data/lib/nvoi/cli/deploy/steps/deploy_service.rb +399 -0
  58. data/lib/nvoi/cli/deploy/steps/provision_network.rb +44 -0
  59. data/lib/nvoi/cli/deploy/steps/provision_server.rb +143 -0
  60. data/lib/nvoi/cli/deploy/steps/provision_volume.rb +171 -0
  61. data/lib/nvoi/cli/deploy/steps/setup_k3s.rb +490 -0
  62. data/lib/nvoi/cli/exec/command.rb +173 -0
  63. data/lib/nvoi/cli/logs/command.rb +66 -0
  64. data/lib/nvoi/cli/onboard/command.rb +761 -0
  65. data/lib/nvoi/cli/unlock/command.rb +72 -0
  66. data/lib/nvoi/cli.rb +339 -141
  67. data/lib/nvoi/config_api/actions/app.rb +53 -0
  68. data/lib/nvoi/config_api/actions/compute_provider.rb +55 -0
  69. data/lib/nvoi/config_api/actions/database.rb +70 -0
  70. data/lib/nvoi/config_api/actions/domain_provider.rb +40 -0
  71. data/lib/nvoi/config_api/actions/env.rb +32 -0
  72. data/lib/nvoi/config_api/actions/init.rb +67 -0
  73. data/lib/nvoi/config_api/actions/secret.rb +32 -0
  74. data/lib/nvoi/config_api/actions/server.rb +66 -0
  75. data/lib/nvoi/config_api/actions/service.rb +52 -0
  76. data/lib/nvoi/config_api/actions/volume.rb +40 -0
  77. data/lib/nvoi/config_api/base.rb +38 -0
  78. data/lib/nvoi/config_api/result.rb +26 -0
  79. data/lib/nvoi/config_api.rb +93 -0
  80. data/lib/nvoi/errors.rb +68 -50
  81. data/lib/nvoi/external/cloud/aws.rb +450 -0
  82. data/lib/nvoi/external/cloud/base.rb +99 -0
  83. data/lib/nvoi/external/cloud/factory.rb +48 -0
  84. data/lib/nvoi/external/cloud/hetzner.rb +402 -0
  85. data/lib/nvoi/external/cloud/scaleway.rb +559 -0
  86. data/lib/nvoi/external/cloud.rb +15 -0
  87. data/lib/nvoi/external/containerd.rb +86 -0
  88. data/lib/nvoi/external/database/mysql.rb +84 -0
  89. data/lib/nvoi/external/database/postgres.rb +82 -0
  90. data/lib/nvoi/external/database/provider.rb +65 -0
  91. data/lib/nvoi/external/database/sqlite.rb +72 -0
  92. data/lib/nvoi/external/database.rb +22 -0
  93. data/lib/nvoi/external/dns/cloudflare.rb +310 -0
  94. data/lib/nvoi/external/kubectl.rb +65 -0
  95. data/lib/nvoi/external/ssh.rb +106 -0
  96. data/lib/nvoi/objects/config_override.rb +60 -0
  97. data/lib/nvoi/objects/configuration.rb +483 -0
  98. data/lib/nvoi/objects/database.rb +56 -0
  99. data/lib/nvoi/objects/dns.rb +14 -0
  100. data/lib/nvoi/objects/firewall.rb +11 -0
  101. data/lib/nvoi/objects/network.rb +11 -0
  102. data/lib/nvoi/objects/server.rb +14 -0
  103. data/lib/nvoi/objects/service_spec.rb +26 -0
  104. data/lib/nvoi/objects/tunnel.rb +14 -0
  105. data/lib/nvoi/objects/volume.rb +17 -0
  106. data/lib/nvoi/utils/config_loader.rb +172 -0
  107. data/lib/nvoi/utils/constants.rb +61 -0
  108. data/lib/nvoi/{credentials/manager.rb → utils/credential_store.rb} +16 -16
  109. data/lib/nvoi/{credentials → utils}/crypto.rb +8 -5
  110. data/lib/nvoi/{config → utils}/env_resolver.rb +10 -2
  111. data/lib/nvoi/utils/logger.rb +84 -0
  112. data/lib/nvoi/{config/naming.rb → utils/namer.rb} +37 -25
  113. data/lib/nvoi/{deployer → utils}/retry.rb +23 -3
  114. data/lib/nvoi/utils/templates.rb +62 -0
  115. data/lib/nvoi/version.rb +1 -1
  116. data/lib/nvoi.rb +27 -55
  117. data/templates/app-ingress.yaml.erb +3 -1
  118. data/templates/error-backend.yaml.erb +134 -0
  119. metadata +121 -44
  120. data/examples/golang/deploy.yml +0 -54
  121. data/lib/nvoi/cloudflare/client.rb +0 -287
  122. data/lib/nvoi/config/config.rb +0 -248
  123. data/lib/nvoi/config/loader.rb +0 -102
  124. data/lib/nvoi/config/ssh_keys.rb +0 -82
  125. data/lib/nvoi/config/types.rb +0 -274
  126. data/lib/nvoi/constants.rb +0 -59
  127. data/lib/nvoi/credentials/editor.rb +0 -272
  128. data/lib/nvoi/deployer/cleaner.rb +0 -36
  129. data/lib/nvoi/deployer/image_builder.rb +0 -23
  130. data/lib/nvoi/deployer/infrastructure.rb +0 -126
  131. data/lib/nvoi/deployer/orchestrator.rb +0 -146
  132. data/lib/nvoi/deployer/service_deployer.rb +0 -311
  133. data/lib/nvoi/deployer/tunnel_manager.rb +0 -57
  134. data/lib/nvoi/deployer/types.rb +0 -8
  135. data/lib/nvoi/k8s/renderer.rb +0 -44
  136. data/lib/nvoi/k8s/templates.rb +0 -29
  137. data/lib/nvoi/logger.rb +0 -72
  138. data/lib/nvoi/providers/aws.rb +0 -403
  139. data/lib/nvoi/providers/base.rb +0 -111
  140. data/lib/nvoi/providers/hetzner.rb +0 -288
  141. data/lib/nvoi/providers/hetzner_client.rb +0 -170
  142. data/lib/nvoi/remote/docker_manager.rb +0 -203
  143. data/lib/nvoi/remote/ssh_executor.rb +0 -72
  144. data/lib/nvoi/remote/volume_manager.rb +0 -103
  145. data/lib/nvoi/service/delete.rb +0 -234
  146. data/lib/nvoi/service/deploy.rb +0 -80
  147. data/lib/nvoi/service/exec.rb +0 -144
  148. data/lib/nvoi/service/provider.rb +0 -36
  149. data/lib/nvoi/steps/application_deployer.rb +0 -26
  150. data/lib/nvoi/steps/database_provisioner.rb +0 -60
  151. data/lib/nvoi/steps/k3s_cluster_setup.rb +0 -105
  152. data/lib/nvoi/steps/k3s_provisioner.rb +0 -351
  153. data/lib/nvoi/steps/server_provisioner.rb +0 -43
  154. data/lib/nvoi/steps/services_provisioner.rb +0 -29
  155. data/lib/nvoi/steps/tunnel_configurator.rb +0 -66
  156. data/lib/nvoi/steps/volume_provisioner.rb +0 -154
@@ -3,9 +3,9 @@
3
3
  require "digest"
4
4
 
5
5
  module Nvoi
6
- module Config
7
- # ResourceNamer handles resource naming and inference
8
- class ResourceNamer
6
+ module Utils
7
+ # Namer handles resource naming and inference
8
+ class Namer
9
9
  def initialize(config)
10
10
  @config = config
11
11
  end
@@ -72,6 +72,10 @@ module Nvoi
72
72
  "app=db-#{@config.deploy.application.name}"
73
73
  end
74
74
 
75
+ def database_pod_name
76
+ "db-#{@config.deploy.application.name}-0"
77
+ end
78
+
75
79
  # ============================================================================
76
80
  # KUBERNETES APP RESOURCES
77
81
  # ============================================================================
@@ -153,20 +157,41 @@ module Nvoi
153
157
  # VOLUME RESOURCES
154
158
  # ============================================================================
155
159
 
156
- def volume_name(service_type, service_name, volume_key)
157
- "#{@config.deploy.application.name}-#{service_type}-#{service_name}-#{volume_key}"
160
+ # Server-level volume naming: {app}-{server}-{volume}
161
+ def server_volume_name(server_name, volume_name)
162
+ "#{@config.deploy.application.name}-#{server_name}-#{volume_name}"
158
163
  end
159
164
 
160
- def database_volume_name
161
- "#{@config.deploy.application.name}-db-data"
165
+ # Host mount path for a server volume
166
+ def server_volume_host_path(server_name, volume_name)
167
+ "/opt/nvoi/volumes/#{server_volume_name(server_name, volume_name)}"
162
168
  end
163
169
 
164
- def service_volume_name(service_name, volume_key)
165
- "#{@config.deploy.application.name}-svc-#{service_name}-#{volume_key}"
170
+ # ============================================================================
171
+ # HOSTNAME HELPER
172
+ # ============================================================================
173
+
174
+ # Build full hostname from subdomain and domain
175
+ def hostname(subdomain, domain)
176
+ self.class.build_hostname(subdomain, domain)
166
177
  end
167
178
 
168
- def app_volume_name(service_name, volume_key)
169
- "#{@config.deploy.application.name}-app-#{service_name}-#{volume_key}"
179
+ # Class method for building hostname without instance
180
+ def self.build_hostname(subdomain, domain)
181
+ if subdomain.nil? || subdomain.empty? || subdomain == "@"
182
+ domain
183
+ else
184
+ "#{subdomain}.#{domain}"
185
+ end
186
+ end
187
+
188
+ # Returns array of hostnames - apex returns [domain, *.domain], subdomain returns [sub.domain]
189
+ def self.build_hostnames(subdomain, domain)
190
+ if subdomain.nil? || subdomain.empty? || subdomain == "@"
191
+ [domain, "*.#{domain}"]
192
+ else
193
+ ["#{subdomain}.#{domain}"]
194
+ end
170
195
  end
171
196
 
172
197
  private
@@ -176,20 +201,7 @@ module Nvoi
176
201
  end
177
202
 
178
203
  def infer_base_prefix
179
- output = `git config --get remote.origin.url 2>/dev/null`.strip
180
- return "app" if output.empty?
181
-
182
- # Extract username/repo from: git@github.com:user/repo.git or https://github.com/user/repo.git
183
- repo_url = output.sub(/\.git$/, "")
184
- parts = repo_url.split(%r{[/:]+})
185
-
186
- if parts.length >= 2
187
- username = parts[-2]
188
- repo = parts[-1]
189
- "#{username}-#{repo}"
190
- else
191
- "app"
192
- end
204
+ "nvoi"
193
205
  end
194
206
  end
195
207
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Nvoi
4
- module Deployer
4
+ module Utils
5
5
  # StepExecutor executes deployment steps with automatic retry on transient failures
6
6
  class StepExecutor
7
7
  def initialize(max_retries, log)
@@ -37,7 +37,7 @@ module Nvoi
37
37
  end
38
38
  end
39
39
 
40
- raise DeploymentError.new(step_name, "max retries (#{@max_retries}) exceeded: #{last_error&.message}")
40
+ raise Errors::DeploymentError.new(step_name, "max retries (#{@max_retries}) exceeded: #{last_error&.message}")
41
41
  end
42
42
 
43
43
  private
@@ -56,12 +56,32 @@ module Nvoi
56
56
  end
57
57
  end
58
58
 
59
- # Retry helper module for simple retry scenarios (backwards compatibility)
59
+ # Retry helper module for simple retry scenarios
60
60
  module Retry
61
61
  def self.with_retry(max_attempts: 3, log: nil)
62
62
  executor = StepExecutor.new(max_attempts, log)
63
63
  executor.execute("operation") { yield }
64
64
  end
65
+
66
+ # Poll until condition is met or timeout
67
+ # Returns the result of the block, or nil if timeout
68
+ def self.poll(max_attempts: 30, interval: 2)
69
+ max_attempts.times do
70
+ result = yield
71
+ return result if result
72
+
73
+ sleep(interval)
74
+ end
75
+ nil
76
+ end
77
+
78
+ # Poll with error on timeout
79
+ def self.poll!(max_attempts: 30, interval: 2, error_message: "operation timed out")
80
+ result = poll(max_attempts:, interval:) { yield }
81
+ raise Errors::TimeoutError, error_message unless result
82
+
83
+ result
84
+ end
65
85
  end
66
86
  end
67
87
  end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "erb"
4
+
5
+ module Nvoi
6
+ module Utils
7
+ # Templates handles K8s manifest template loading and rendering
8
+ module Templates
9
+ # TemplateBinding provides a clean binding for ERB templates
10
+ class TemplateBinding
11
+ def initialize(data)
12
+ data.each do |key, value|
13
+ instance_variable_set("@#{key}", value)
14
+ define_singleton_method(key) { instance_variable_get("@#{key}") }
15
+ end
16
+ end
17
+
18
+ def get_binding
19
+ binding
20
+ end
21
+ end
22
+
23
+ class << self
24
+ def template_path(name)
25
+ File.join(Nvoi.templates_path, "#{name}.erb")
26
+ end
27
+
28
+ def load_template(name)
29
+ path = template_path(name)
30
+ raise Errors::TemplateError, "template #{name} not found at #{path}" unless File.exist?(path)
31
+
32
+ ERB.new(File.read(path), trim_mode: "-")
33
+ end
34
+
35
+ def template_names
36
+ Dir.glob(File.join(Nvoi.templates_path, "*.erb")).map do |path|
37
+ File.basename(path, ".erb")
38
+ end
39
+ end
40
+
41
+ # Render a template with the provided data
42
+ def render(name, data)
43
+ template = load_template(name)
44
+ binding_obj = TemplateBinding.new(data)
45
+ template.result(binding_obj.get_binding)
46
+ end
47
+
48
+ # Render a template and apply it via kubectl
49
+ def apply_manifest(ssh, template_name, data)
50
+ manifest = render(template_name, data)
51
+ cmd = "cat <<'EOF' | kubectl apply -f -\n#{manifest}\nEOF"
52
+ ssh.execute(cmd)
53
+ end
54
+
55
+ # Wait for a deployment to be ready
56
+ def wait_for_deployment(ssh, name, namespace: "default", timeout: 300)
57
+ ssh.execute("kubectl rollout status deployment/#{name} -n #{namespace} --timeout=#{timeout}s")
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
data/lib/nvoi/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Nvoi
4
- VERSION = "0.1.5"
4
+ VERSION = "0.1.7"
5
5
  end
data/lib/nvoi.rb CHANGED
@@ -1,5 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ module Nvoi
4
+ class Error < StandardError; end
5
+ end
6
+
7
+ require "zeitwerk"
3
8
  require "yaml"
4
9
  require "json"
5
10
  require "openssl"
@@ -7,60 +12,27 @@ require "securerandom"
7
12
  require "fileutils"
8
13
  require "tempfile"
9
14
  require "open3"
10
-
11
- require_relative "nvoi/version"
12
- require_relative "nvoi/constants"
13
- require_relative "nvoi/errors"
14
- require_relative "nvoi/logger"
15
-
16
- require_relative "nvoi/config/types"
17
- require_relative "nvoi/config/naming"
18
- require_relative "nvoi/config/ssh_keys"
19
- require_relative "nvoi/config/env_resolver"
20
- require_relative "nvoi/config/loader"
21
- require_relative "nvoi/config/config"
22
-
23
- require_relative "nvoi/credentials/crypto"
24
- require_relative "nvoi/credentials/manager"
25
- require_relative "nvoi/credentials/editor"
26
-
27
- require_relative "nvoi/providers/base"
28
- require_relative "nvoi/providers/hetzner"
29
- require_relative "nvoi/providers/aws"
30
-
31
- require_relative "nvoi/cloudflare/client"
32
-
33
- require_relative "nvoi/remote/ssh_executor"
34
- require_relative "nvoi/remote/docker_manager"
35
- require_relative "nvoi/remote/volume_manager"
36
-
37
- require_relative "nvoi/k8s/templates"
38
- require_relative "nvoi/k8s/renderer"
39
-
40
- require_relative "nvoi/deployer/types"
41
- require_relative "nvoi/deployer/retry"
42
- require_relative "nvoi/deployer/tunnel_manager"
43
- require_relative "nvoi/deployer/infrastructure"
44
- require_relative "nvoi/deployer/image_builder"
45
- require_relative "nvoi/deployer/service_deployer"
46
- require_relative "nvoi/deployer/cleaner"
47
- require_relative "nvoi/deployer/orchestrator"
48
-
49
- require_relative "nvoi/steps/server_provisioner"
50
- require_relative "nvoi/steps/volume_provisioner"
51
- require_relative "nvoi/steps/k3s_provisioner"
52
- require_relative "nvoi/steps/k3s_cluster_setup"
53
- require_relative "nvoi/steps/tunnel_configurator"
54
- require_relative "nvoi/steps/database_provisioner"
55
- require_relative "nvoi/steps/services_provisioner"
56
- require_relative "nvoi/steps/application_deployer"
57
-
58
- require_relative "nvoi/service/provider"
59
- require_relative "nvoi/service/deploy"
60
- require_relative "nvoi/service/delete"
61
- require_relative "nvoi/service/exec"
62
-
63
- require_relative "nvoi/cli"
15
+ require "faraday"
16
+
17
+ loader = Zeitwerk::Loader.for_gem
18
+ loader.ignore("#{__dir__}/nvoi/cli") # CLI commands are lazy-loaded
19
+ loader.ignore("#{__dir__}/nvoi/config_api") # ConfigApi uses non-standard naming
20
+ loader.setup
21
+
22
+ # Load ConfigApi manually (uses non-standard naming convention)
23
+ require_relative "nvoi/config_api/result"
24
+ require_relative "nvoi/config_api/base"
25
+ require_relative "nvoi/config_api/actions/init"
26
+ require_relative "nvoi/config_api/actions/domain_provider"
27
+ require_relative "nvoi/config_api/actions/compute_provider"
28
+ require_relative "nvoi/config_api/actions/server"
29
+ require_relative "nvoi/config_api/actions/volume"
30
+ require_relative "nvoi/config_api/actions/app"
31
+ require_relative "nvoi/config_api/actions/database"
32
+ require_relative "nvoi/config_api/actions/secret"
33
+ require_relative "nvoi/config_api/actions/env"
34
+ require_relative "nvoi/config_api/actions/service"
35
+ require_relative "nvoi/config_api"
64
36
 
65
37
  module Nvoi
66
38
  class << self
@@ -75,5 +47,5 @@ module Nvoi
75
47
  end
76
48
  end
77
49
 
78
- self.logger = Logger.new
50
+ self.logger = Utils::Logger.new
79
51
  end
@@ -8,7 +8,8 @@ metadata:
8
8
  spec:
9
9
  ingressClassName: nginx
10
10
  rules:
11
- - host: <%= domain %>
11
+ <% domains.each do |domain| -%>
12
+ - host: "<%= domain %>"
12
13
  http:
13
14
  paths:
14
15
  - path: /
@@ -18,3 +19,4 @@ spec:
18
19
  name: <%= name %>
19
20
  port:
20
21
  number: <%= port %>
22
+ <% end -%>
@@ -0,0 +1,134 @@
1
+ apiVersion: v1
2
+ kind: ConfigMap
3
+ metadata:
4
+ name: nvoi-error-pages
5
+ namespace: ingress-nginx
6
+ data:
7
+ error.html: |
8
+ <!DOCTYPE html>
9
+ <html lang="en">
10
+ <head>
11
+ <meta charset="UTF-8">
12
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
13
+ <title>We'll be right back</title>
14
+ <style>
15
+ * { margin: 0; padding: 0; box-sizing: border-box; }
16
+ body {
17
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
18
+ background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
19
+ color: #fff;
20
+ min-height: 100vh;
21
+ display: flex;
22
+ align-items: center;
23
+ justify-content: center;
24
+ }
25
+ .container {
26
+ text-align: center;
27
+ padding: 2rem;
28
+ }
29
+ .icon {
30
+ font-size: 4rem;
31
+ margin-bottom: 1.5rem;
32
+ }
33
+ h1 {
34
+ font-size: 2rem;
35
+ font-weight: 600;
36
+ margin-bottom: 0.5rem;
37
+ }
38
+ p {
39
+ color: #a0aec0;
40
+ font-size: 1.1rem;
41
+ }
42
+ </style>
43
+ </head>
44
+ <body>
45
+ <div class="container">
46
+ <div class="icon">&#9881;</div>
47
+ <h1>We'll be right back</h1>
48
+ <p>We're performing some maintenance. Please try again shortly.</p>
49
+ </div>
50
+ </body>
51
+ </html>
52
+ nginx.conf: |
53
+ server {
54
+ listen 8080;
55
+ server_name _;
56
+
57
+ location / {
58
+ add_header X-Nvoi-Error "true" always;
59
+ add_header Content-Type "text/html; charset=utf-8" always;
60
+ root /usr/share/nginx/html;
61
+ try_files /error.html =404;
62
+ }
63
+
64
+ location /healthz {
65
+ return 200 "ok";
66
+ add_header Content-Type "text/plain" always;
67
+ }
68
+ }
69
+ ---
70
+ apiVersion: apps/v1
71
+ kind: Deployment
72
+ metadata:
73
+ name: nvoi-error-backend
74
+ namespace: ingress-nginx
75
+ spec:
76
+ replicas: 1
77
+ selector:
78
+ matchLabels:
79
+ app: nvoi-error-backend
80
+ template:
81
+ metadata:
82
+ labels:
83
+ app: nvoi-error-backend
84
+ spec:
85
+ containers:
86
+ - name: nginx
87
+ image: nginx:alpine
88
+ ports:
89
+ - containerPort: 8080
90
+ volumeMounts:
91
+ - name: error-pages
92
+ mountPath: /usr/share/nginx/html/error.html
93
+ subPath: error.html
94
+ - name: nginx-conf
95
+ mountPath: /etc/nginx/conf.d/default.conf
96
+ subPath: nginx.conf
97
+ livenessProbe:
98
+ httpGet:
99
+ path: /healthz
100
+ port: 8080
101
+ initialDelaySeconds: 5
102
+ periodSeconds: 10
103
+ readinessProbe:
104
+ httpGet:
105
+ path: /healthz
106
+ port: 8080
107
+ initialDelaySeconds: 2
108
+ periodSeconds: 5
109
+ resources:
110
+ requests:
111
+ memory: "16Mi"
112
+ cpu: "10m"
113
+ limits:
114
+ memory: "32Mi"
115
+ cpu: "50m"
116
+ volumes:
117
+ - name: error-pages
118
+ configMap:
119
+ name: nvoi-error-pages
120
+ - name: nginx-conf
121
+ configMap:
122
+ name: nvoi-error-pages
123
+ ---
124
+ apiVersion: v1
125
+ kind: Service
126
+ metadata:
127
+ name: nvoi-error-backend
128
+ namespace: ingress-nginx
129
+ spec:
130
+ selector:
131
+ app: nvoi-error-backend
132
+ ports:
133
+ - port: 80
134
+ targetPort: 8080
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nvoi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.1.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - NVOI
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-12-09 00:00:00.000000000 Z
11
+ date: 2025-12-12 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: zeitwerk
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.6'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.6'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: thor
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -159,6 +173,37 @@ executables:
159
173
  extensions: []
160
174
  extra_rdoc_files: []
161
175
  files:
176
+ - ".claude/todo/refactor-execution/00-entrypoint.md"
177
+ - ".claude/todo/refactor-execution/01-objects.md"
178
+ - ".claude/todo/refactor-execution/02-utils.md"
179
+ - ".claude/todo/refactor-execution/03-external-cloud.md"
180
+ - ".claude/todo/refactor-execution/04-external-dns.md"
181
+ - ".claude/todo/refactor-execution/05-external-other.md"
182
+ - ".claude/todo/refactor-execution/06-cli-deploy.md"
183
+ - ".claude/todo/refactor-execution/07-cli-delete.md"
184
+ - ".claude/todo/refactor-execution/08-cli-exec.md"
185
+ - ".claude/todo/refactor-execution/09-cli-credentials.md"
186
+ - ".claude/todo/refactor-execution/10-cli-db.md"
187
+ - ".claude/todo/refactor-execution/11-cli-router.md"
188
+ - ".claude/todo/refactor-execution/12-cleanup.md"
189
+ - ".claude/todo/refactor-execution/_monitoring-strategy.md"
190
+ - ".claude/todo/refactor/00-overview.md"
191
+ - ".claude/todo/refactor/01-objects.md"
192
+ - ".claude/todo/refactor/02-utils.md"
193
+ - ".claude/todo/refactor/03-external-cloud.md"
194
+ - ".claude/todo/refactor/04-external-dns.md"
195
+ - ".claude/todo/refactor/05-external.md"
196
+ - ".claude/todo/refactor/06-cli.md"
197
+ - ".claude/todo/refactor/07-cli-deploy-command.md"
198
+ - ".claude/todo/refactor/08-cli-deploy-steps.md"
199
+ - ".claude/todo/refactor/09-cli-delete-command.md"
200
+ - ".claude/todo/refactor/10-cli-exec-command.md"
201
+ - ".claude/todo/refactor/11-cli-credentials-command.md"
202
+ - ".claude/todo/refactor/12-cli-db-command.md"
203
+ - ".claude/todo/refactor/_target.md"
204
+ - ".claude/todo/scaleway.impl.md"
205
+ - ".claude/todo/scaleway.reference.md"
206
+ - ".claude/todos.md"
162
207
  - ".rubocop.yml"
163
208
  - Gemfile
164
209
  - Gemfile.lock
@@ -178,7 +223,6 @@ files:
178
223
  - examples/golang/Dockerfile
179
224
  - examples/golang/README.md
180
225
  - examples/golang/deploy.enc
181
- - examples/golang/deploy.yml
182
226
  - examples/golang/go.mod
183
227
  - examples/golang/go.sum
184
228
  - examples/golang/main.go
@@ -283,56 +327,89 @@ files:
283
327
  - examples/rails-single/vendor/.keep
284
328
  - examples/rails-single/yarn.lock
285
329
  - exe/nvoi
330
+ - ingest
286
331
  - lib/nvoi.rb
287
332
  - lib/nvoi/cli.rb
288
- - lib/nvoi/cloudflare/client.rb
289
- - lib/nvoi/config/config.rb
290
- - lib/nvoi/config/env_resolver.rb
291
- - lib/nvoi/config/loader.rb
292
- - lib/nvoi/config/naming.rb
293
- - lib/nvoi/config/ssh_keys.rb
294
- - lib/nvoi/config/types.rb
295
- - lib/nvoi/constants.rb
296
- - lib/nvoi/credentials/crypto.rb
297
- - lib/nvoi/credentials/editor.rb
298
- - lib/nvoi/credentials/manager.rb
299
- - lib/nvoi/deployer/cleaner.rb
300
- - lib/nvoi/deployer/image_builder.rb
301
- - lib/nvoi/deployer/infrastructure.rb
302
- - lib/nvoi/deployer/orchestrator.rb
303
- - lib/nvoi/deployer/retry.rb
304
- - lib/nvoi/deployer/service_deployer.rb
305
- - lib/nvoi/deployer/tunnel_manager.rb
306
- - lib/nvoi/deployer/types.rb
333
+ - lib/nvoi/cli/config/command.rb
334
+ - lib/nvoi/cli/credentials/edit/command.rb
335
+ - lib/nvoi/cli/credentials/show/command.rb
336
+ - lib/nvoi/cli/db/command.rb
337
+ - lib/nvoi/cli/delete/command.rb
338
+ - lib/nvoi/cli/delete/steps/detach_volumes.rb
339
+ - lib/nvoi/cli/delete/steps/teardown_dns.rb
340
+ - lib/nvoi/cli/delete/steps/teardown_firewall.rb
341
+ - lib/nvoi/cli/delete/steps/teardown_network.rb
342
+ - lib/nvoi/cli/delete/steps/teardown_server.rb
343
+ - lib/nvoi/cli/delete/steps/teardown_tunnel.rb
344
+ - lib/nvoi/cli/delete/steps/teardown_volume.rb
345
+ - lib/nvoi/cli/deploy/command.rb
346
+ - lib/nvoi/cli/deploy/steps/build_image.rb
347
+ - lib/nvoi/cli/deploy/steps/cleanup_images.rb
348
+ - lib/nvoi/cli/deploy/steps/configure_tunnel.rb
349
+ - lib/nvoi/cli/deploy/steps/deploy_service.rb
350
+ - lib/nvoi/cli/deploy/steps/provision_network.rb
351
+ - lib/nvoi/cli/deploy/steps/provision_server.rb
352
+ - lib/nvoi/cli/deploy/steps/provision_volume.rb
353
+ - lib/nvoi/cli/deploy/steps/setup_k3s.rb
354
+ - lib/nvoi/cli/exec/command.rb
355
+ - lib/nvoi/cli/logs/command.rb
356
+ - lib/nvoi/cli/onboard/command.rb
357
+ - lib/nvoi/cli/unlock/command.rb
358
+ - lib/nvoi/config_api.rb
359
+ - lib/nvoi/config_api/actions/app.rb
360
+ - lib/nvoi/config_api/actions/compute_provider.rb
361
+ - lib/nvoi/config_api/actions/database.rb
362
+ - lib/nvoi/config_api/actions/domain_provider.rb
363
+ - lib/nvoi/config_api/actions/env.rb
364
+ - lib/nvoi/config_api/actions/init.rb
365
+ - lib/nvoi/config_api/actions/secret.rb
366
+ - lib/nvoi/config_api/actions/server.rb
367
+ - lib/nvoi/config_api/actions/service.rb
368
+ - lib/nvoi/config_api/actions/volume.rb
369
+ - lib/nvoi/config_api/base.rb
370
+ - lib/nvoi/config_api/result.rb
307
371
  - lib/nvoi/errors.rb
308
- - lib/nvoi/k8s/renderer.rb
309
- - lib/nvoi/k8s/templates.rb
310
- - lib/nvoi/logger.rb
311
- - lib/nvoi/providers/aws.rb
312
- - lib/nvoi/providers/base.rb
313
- - lib/nvoi/providers/hetzner.rb
314
- - lib/nvoi/providers/hetzner_client.rb
315
- - lib/nvoi/remote/docker_manager.rb
316
- - lib/nvoi/remote/ssh_executor.rb
317
- - lib/nvoi/remote/volume_manager.rb
318
- - lib/nvoi/service/delete.rb
319
- - lib/nvoi/service/deploy.rb
320
- - lib/nvoi/service/exec.rb
321
- - lib/nvoi/service/provider.rb
322
- - lib/nvoi/steps/application_deployer.rb
323
- - lib/nvoi/steps/database_provisioner.rb
324
- - lib/nvoi/steps/k3s_cluster_setup.rb
325
- - lib/nvoi/steps/k3s_provisioner.rb
326
- - lib/nvoi/steps/server_provisioner.rb
327
- - lib/nvoi/steps/services_provisioner.rb
328
- - lib/nvoi/steps/tunnel_configurator.rb
329
- - lib/nvoi/steps/volume_provisioner.rb
372
+ - lib/nvoi/external/cloud.rb
373
+ - lib/nvoi/external/cloud/aws.rb
374
+ - lib/nvoi/external/cloud/base.rb
375
+ - lib/nvoi/external/cloud/factory.rb
376
+ - lib/nvoi/external/cloud/hetzner.rb
377
+ - lib/nvoi/external/cloud/scaleway.rb
378
+ - lib/nvoi/external/containerd.rb
379
+ - lib/nvoi/external/database.rb
380
+ - lib/nvoi/external/database/mysql.rb
381
+ - lib/nvoi/external/database/postgres.rb
382
+ - lib/nvoi/external/database/provider.rb
383
+ - lib/nvoi/external/database/sqlite.rb
384
+ - lib/nvoi/external/dns/cloudflare.rb
385
+ - lib/nvoi/external/kubectl.rb
386
+ - lib/nvoi/external/ssh.rb
387
+ - lib/nvoi/objects/config_override.rb
388
+ - lib/nvoi/objects/configuration.rb
389
+ - lib/nvoi/objects/database.rb
390
+ - lib/nvoi/objects/dns.rb
391
+ - lib/nvoi/objects/firewall.rb
392
+ - lib/nvoi/objects/network.rb
393
+ - lib/nvoi/objects/server.rb
394
+ - lib/nvoi/objects/service_spec.rb
395
+ - lib/nvoi/objects/tunnel.rb
396
+ - lib/nvoi/objects/volume.rb
397
+ - lib/nvoi/utils/config_loader.rb
398
+ - lib/nvoi/utils/constants.rb
399
+ - lib/nvoi/utils/credential_store.rb
400
+ - lib/nvoi/utils/crypto.rb
401
+ - lib/nvoi/utils/env_resolver.rb
402
+ - lib/nvoi/utils/logger.rb
403
+ - lib/nvoi/utils/namer.rb
404
+ - lib/nvoi/utils/retry.rb
405
+ - lib/nvoi/utils/templates.rb
330
406
  - lib/nvoi/version.rb
331
407
  - templates/app-deployment.yaml.erb
332
408
  - templates/app-ingress.yaml.erb
333
409
  - templates/app-secret.yaml.erb
334
410
  - templates/app-service.yaml.erb
335
411
  - templates/db-statefulset.yaml.erb
412
+ - templates/error-backend.yaml.erb
336
413
  - templates/service-deployment.yaml.erb
337
414
  - templates/worker-deployment.yaml.erb
338
415
  homepage: https://github.com/getnvoi/cli