nvoi 0.1.5 → 0.1.6

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 (130) 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/_target.md +79 -0
  15. data/.claude/todo/scaleway.impl.md +644 -0
  16. data/.claude/todo/scaleway.reference.md +520 -0
  17. data/Gemfile +1 -0
  18. data/Gemfile.lock +12 -2
  19. data/doc/config-schema.yaml +44 -11
  20. data/examples/golang/deploy.enc +0 -0
  21. data/examples/golang/main.go +18 -0
  22. data/exe/nvoi +3 -1
  23. data/lib/nvoi/cli/credentials/edit/command.rb +384 -0
  24. data/lib/nvoi/cli/credentials/show/command.rb +35 -0
  25. data/lib/nvoi/cli/db/command.rb +308 -0
  26. data/lib/nvoi/cli/delete/command.rb +75 -0
  27. data/lib/nvoi/cli/delete/steps/detach_volumes.rb +98 -0
  28. data/lib/nvoi/cli/delete/steps/teardown_dns.rb +49 -0
  29. data/lib/nvoi/cli/delete/steps/teardown_firewall.rb +46 -0
  30. data/lib/nvoi/cli/delete/steps/teardown_network.rb +30 -0
  31. data/lib/nvoi/cli/delete/steps/teardown_server.rb +50 -0
  32. data/lib/nvoi/cli/delete/steps/teardown_tunnel.rb +44 -0
  33. data/lib/nvoi/cli/delete/steps/teardown_volume.rb +61 -0
  34. data/lib/nvoi/cli/deploy/command.rb +184 -0
  35. data/lib/nvoi/cli/deploy/steps/build_image.rb +27 -0
  36. data/lib/nvoi/cli/deploy/steps/cleanup_images.rb +42 -0
  37. data/lib/nvoi/cli/deploy/steps/configure_tunnel.rb +100 -0
  38. data/lib/nvoi/cli/deploy/steps/deploy_service.rb +396 -0
  39. data/lib/nvoi/cli/deploy/steps/provision_network.rb +44 -0
  40. data/lib/nvoi/cli/deploy/steps/provision_server.rb +143 -0
  41. data/lib/nvoi/cli/deploy/steps/provision_volume.rb +171 -0
  42. data/lib/nvoi/cli/deploy/steps/setup_k3s.rb +481 -0
  43. data/lib/nvoi/cli/exec/command.rb +173 -0
  44. data/lib/nvoi/cli.rb +83 -142
  45. data/lib/nvoi/config_api/actions/app.rb +53 -0
  46. data/lib/nvoi/config_api/actions/compute_provider.rb +55 -0
  47. data/lib/nvoi/config_api/actions/database.rb +70 -0
  48. data/lib/nvoi/config_api/actions/env.rb +32 -0
  49. data/lib/nvoi/config_api/actions/secret.rb +32 -0
  50. data/lib/nvoi/config_api/actions/server.rb +66 -0
  51. data/lib/nvoi/config_api/actions/volume.rb +40 -0
  52. data/lib/nvoi/config_api/base.rb +44 -0
  53. data/lib/nvoi/config_api/result.rb +26 -0
  54. data/lib/nvoi/config_api.rb +70 -0
  55. data/lib/nvoi/errors.rb +68 -50
  56. data/lib/nvoi/external/cloud/aws.rb +425 -0
  57. data/lib/nvoi/external/cloud/base.rb +99 -0
  58. data/lib/nvoi/external/cloud/factory.rb +48 -0
  59. data/lib/nvoi/external/cloud/hetzner.rb +376 -0
  60. data/lib/nvoi/external/cloud/scaleway.rb +533 -0
  61. data/lib/nvoi/external/cloud.rb +15 -0
  62. data/lib/nvoi/external/containerd.rb +82 -0
  63. data/lib/nvoi/external/database/mysql.rb +84 -0
  64. data/lib/nvoi/external/database/postgres.rb +82 -0
  65. data/lib/nvoi/external/database/provider.rb +65 -0
  66. data/lib/nvoi/external/database/sqlite.rb +72 -0
  67. data/lib/nvoi/external/database.rb +22 -0
  68. data/lib/nvoi/external/dns/cloudflare.rb +292 -0
  69. data/lib/nvoi/external/kubectl.rb +65 -0
  70. data/lib/nvoi/external/ssh.rb +106 -0
  71. data/lib/nvoi/objects/config_override.rb +60 -0
  72. data/lib/nvoi/objects/configuration.rb +463 -0
  73. data/lib/nvoi/objects/database.rb +56 -0
  74. data/lib/nvoi/objects/dns.rb +14 -0
  75. data/lib/nvoi/objects/firewall.rb +11 -0
  76. data/lib/nvoi/objects/network.rb +11 -0
  77. data/lib/nvoi/objects/server.rb +14 -0
  78. data/lib/nvoi/objects/service_spec.rb +26 -0
  79. data/lib/nvoi/objects/tunnel.rb +14 -0
  80. data/lib/nvoi/objects/volume.rb +17 -0
  81. data/lib/nvoi/utils/config_loader.rb +172 -0
  82. data/lib/nvoi/utils/constants.rb +61 -0
  83. data/lib/nvoi/{credentials/manager.rb → utils/credential_store.rb} +16 -16
  84. data/lib/nvoi/{credentials → utils}/crypto.rb +8 -5
  85. data/lib/nvoi/{config → utils}/env_resolver.rb +10 -2
  86. data/lib/nvoi/utils/logger.rb +84 -0
  87. data/lib/nvoi/{config/naming.rb → utils/namer.rb} +28 -25
  88. data/lib/nvoi/{deployer → utils}/retry.rb +23 -3
  89. data/lib/nvoi/utils/templates.rb +62 -0
  90. data/lib/nvoi/version.rb +1 -1
  91. data/lib/nvoi.rb +10 -54
  92. data/templates/error-backend.yaml.erb +134 -0
  93. metadata +97 -44
  94. data/examples/golang/deploy.yml +0 -54
  95. data/lib/nvoi/cloudflare/client.rb +0 -287
  96. data/lib/nvoi/config/config.rb +0 -248
  97. data/lib/nvoi/config/loader.rb +0 -102
  98. data/lib/nvoi/config/ssh_keys.rb +0 -82
  99. data/lib/nvoi/config/types.rb +0 -274
  100. data/lib/nvoi/constants.rb +0 -59
  101. data/lib/nvoi/credentials/editor.rb +0 -272
  102. data/lib/nvoi/deployer/cleaner.rb +0 -36
  103. data/lib/nvoi/deployer/image_builder.rb +0 -23
  104. data/lib/nvoi/deployer/infrastructure.rb +0 -126
  105. data/lib/nvoi/deployer/orchestrator.rb +0 -146
  106. data/lib/nvoi/deployer/service_deployer.rb +0 -311
  107. data/lib/nvoi/deployer/tunnel_manager.rb +0 -57
  108. data/lib/nvoi/deployer/types.rb +0 -8
  109. data/lib/nvoi/k8s/renderer.rb +0 -44
  110. data/lib/nvoi/k8s/templates.rb +0 -29
  111. data/lib/nvoi/logger.rb +0 -72
  112. data/lib/nvoi/providers/aws.rb +0 -403
  113. data/lib/nvoi/providers/base.rb +0 -111
  114. data/lib/nvoi/providers/hetzner.rb +0 -288
  115. data/lib/nvoi/providers/hetzner_client.rb +0 -170
  116. data/lib/nvoi/remote/docker_manager.rb +0 -203
  117. data/lib/nvoi/remote/ssh_executor.rb +0 -72
  118. data/lib/nvoi/remote/volume_manager.rb +0 -103
  119. data/lib/nvoi/service/delete.rb +0 -234
  120. data/lib/nvoi/service/deploy.rb +0 -80
  121. data/lib/nvoi/service/exec.rb +0 -144
  122. data/lib/nvoi/service/provider.rb +0 -36
  123. data/lib/nvoi/steps/application_deployer.rb +0 -26
  124. data/lib/nvoi/steps/database_provisioner.rb +0 -60
  125. data/lib/nvoi/steps/k3s_cluster_setup.rb +0 -105
  126. data/lib/nvoi/steps/k3s_provisioner.rb +0 -351
  127. data/lib/nvoi/steps/server_provisioner.rb +0 -43
  128. data/lib/nvoi/steps/services_provisioner.rb +0 -29
  129. data/lib/nvoi/steps/tunnel_configurator.rb +0 -66
  130. data/lib/nvoi/steps/volume_provisioner.rb +0 -154
@@ -1,154 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Nvoi
4
- module Steps
5
- # VolumeProvisioner handles provisioning of block storage volumes
6
- class VolumeProvisioner
7
- def initialize(config, provider, log)
8
- @config = config
9
- @provider = provider
10
- @log = log
11
- @namer = config.namer
12
- end
13
-
14
- def run
15
- volumes_to_provision = collect_volumes
16
- return if volumes_to_provision.empty?
17
-
18
- @log.info "Provisioning %d volume(s)", volumes_to_provision.size
19
-
20
- volumes_to_provision.each do |vol_config|
21
- provision_volume(vol_config)
22
- end
23
-
24
- @log.success "All volumes provisioned"
25
- end
26
-
27
- private
28
-
29
- def collect_volumes
30
- volumes = []
31
-
32
- # Database volume
33
- db = @config.deploy.application.database
34
- if db&.volume && !db.volume.empty?
35
- server_name = resolve_server_name(db.servers)
36
- volumes << {
37
- name: @namer.database_volume_name,
38
- server_name:,
39
- mount_path: "/opt/nvoi/volumes/#{@namer.database_volume_name}",
40
- size: 10
41
- }
42
- end
43
-
44
- # Service volumes
45
- @config.deploy.application.services.each do |svc_name, svc|
46
- next unless svc&.volume && !svc.volume.empty?
47
-
48
- server_name = resolve_server_name(svc.servers)
49
- vol_name = @namer.service_volume_name(svc_name, "data")
50
- volumes << {
51
- name: vol_name,
52
- server_name:,
53
- mount_path: "/opt/nvoi/volumes/#{vol_name}",
54
- size: 10
55
- }
56
- end
57
-
58
- # App volumes
59
- @config.deploy.application.app.each do |app_name, app|
60
- next unless app&.volumes && !app.volumes.empty?
61
-
62
- server_name = resolve_server_name(app.servers)
63
- app.volumes.each_key do |vol_key|
64
- vol_name = @namer.app_volume_name(app_name, vol_key)
65
- volumes << {
66
- name: vol_name,
67
- server_name:,
68
- mount_path: "/opt/nvoi/volumes/#{vol_name}",
69
- size: 10
70
- }
71
- end
72
- end
73
-
74
- volumes
75
- end
76
-
77
- def resolve_server_name(servers)
78
- return @config.server_name if servers.nil? || servers.empty?
79
-
80
- # Use first server in the list
81
- group_name = servers.first
82
- @namer.server_name(group_name, 1)
83
- end
84
-
85
- def provision_volume(vol_config)
86
- @log.info "Provisioning volume: %s", vol_config[:name]
87
-
88
- # Check if volume already exists
89
- existing = @provider.get_volume_by_name(vol_config[:name])
90
- if existing
91
- @log.info "Volume already exists: %s", vol_config[:name]
92
- ensure_attached_and_mounted(existing, vol_config)
93
- return
94
- end
95
-
96
- # Find server to attach to
97
- server = @provider.find_server(vol_config[:server_name])
98
- raise VolumeError, "server not found: #{vol_config[:server_name]}" unless server
99
-
100
- # Create volume
101
- opts = Providers::VolumeCreateOptions.new(
102
- name: vol_config[:name],
103
- size: vol_config[:size],
104
- server_id: server.id
105
- )
106
- volume = @provider.create_volume(opts)
107
-
108
- # Attach volume
109
- @log.info "Attaching volume to server..."
110
- @provider.attach_volume(volume.id, server.id)
111
-
112
- # Mount volume on server (includes device wait)
113
- mount_volume(server.public_ipv4, volume, vol_config[:mount_path])
114
-
115
- @log.success "Volume provisioned and mounted: %s", vol_config[:name]
116
- end
117
-
118
- def ensure_attached_and_mounted(volume, vol_config)
119
- server = @provider.find_server(vol_config[:server_name])
120
- return unless server
121
-
122
- # Attach if not attached
123
- if volume.server_id.nil? || volume.server_id.empty?
124
- @log.info "Attaching existing volume..."
125
- @provider.attach_volume(volume.id, server.id)
126
- volume = @provider.get_volume(volume.id)
127
- end
128
-
129
- # Mount if not mounted
130
- mount_volume(server.public_ipv4, volume, vol_config[:mount_path])
131
- end
132
-
133
- def mount_volume(server_ip, volume, mount_path)
134
- ssh = Remote::SSHExecutor.new(server_ip, @config.ssh_key_path)
135
- volume_manager = Remote::VolumeManager.new(ssh)
136
-
137
- # Get device path (refreshed from provider)
138
- refreshed = @provider.get_volume(volume.id)
139
- device_path = refreshed&.device_path
140
-
141
- return unless device_path && !device_path.empty?
142
-
143
- @log.info "Mounting volume at %s", mount_path
144
-
145
- opts = Remote::MountOptions.new(
146
- device_path:,
147
- mount_path:,
148
- fs_type: "xfs"
149
- )
150
- volume_manager.mount(opts)
151
- end
152
- end
153
- end
154
- end