lbhrr 1.0.27 → 2.32.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.DS_Store +0 -0
- data/.ruby-version +1 -0
- data/crane.png +0 -0
- data/exe/lbhrr +400 -274
- data/lib/.kafkr/acknowledged_messages.txt +1 -0
- data/lib/.kafkr/message_queue.txt +5 -0
- data/lib/lbhrr/version.rb +1 -1
- data/templates/lib/panamax.rb.erb +4 -0
- data/templates/lib/rubygems_plugin.rb.erb +41 -0
- data/templates/panamax.gemspec.erb +24 -0
- metadata +11 -5
- data/.gitlab-ci.yml +0 -10
- data/config/manifest.yml +0 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3f63fcc372df8525489ddf02ca8a023112a031ae24b5306614500022e556ccc8
|
4
|
+
data.tar.gz: a94d96eb246401e944fa044950f4e128dbb4cf16bc45e508f274e6879f88d2cc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cec7337f7de060c7b98749195f9b2fe137735ffc88933077f8172c046b1e4867ab3cb76ffa9646de1a14dce3cb3b96469b824eaa94d53d6f35c06dde18921751
|
7
|
+
data.tar.gz: 4f62371636aadfb7d53168e1f4631b028c53e73291040c365b2b16fd459ef0270dc5d123af4445d0ed7487381c21bce79ba1d420f8d10b2d6b85e725736976bb
|
data/.DS_Store
ADDED
Binary file
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
3.2.2
|
data/crane.png
ADDED
Binary file
|
data/exe/lbhrr
CHANGED
@@ -1,175 +1,243 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "fileutils"
|
4
|
+
require "logger"
|
5
|
+
require "erb"
|
6
|
+
require "open3"
|
7
|
+
require "io/console"
|
2
8
|
require_relative "../lib/lbhrr"
|
3
9
|
|
4
10
|
class LbhrrCLI < Thor
|
11
|
+
include Thor::Actions
|
12
|
+
|
13
|
+
# Error handling
|
14
|
+
def self.exit_on_failure?
|
15
|
+
true
|
16
|
+
end
|
17
|
+
|
5
18
|
no_commands do
|
19
|
+
require 'net/http'
|
20
|
+
require 'uri'
|
6
21
|
|
7
|
-
def
|
8
|
-
|
22
|
+
def fibonacci(n)
|
23
|
+
[21,34,55][n]
|
9
24
|
end
|
10
25
|
|
11
|
-
def
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
26
|
+
def ok(url,grace: 0)
|
27
|
+
retries = 2
|
28
|
+
sleep(grace)
|
29
|
+
(0..retries).each do |i|
|
30
|
+
uri = URI(url)
|
31
|
+
response = Net::HTTP.get_response(uri)
|
32
|
+
|
33
|
+
if response.is_a?(Net::HTTPSuccess)
|
34
|
+
yield if block_given?
|
35
|
+
break
|
36
|
+
else
|
37
|
+
puts "Response was not 200, it was #{response.code}., check logs gor website"
|
38
|
+
end
|
24
39
|
|
25
|
-
|
26
|
-
|
27
|
-
FileUtils.rm_rf(vendor_path) if Dir.exist?(vendor_path)
|
28
|
-
`bundle config set --local path 'vendor/bundle'`
|
29
|
-
system "bundle install" or raise "Bundle install failed"
|
30
|
-
# Check if the repository is clean
|
31
|
-
puts "Git repository is dirty, committing changes..."
|
32
|
-
system("git add .") or raise "Failed to add changes to Git"
|
33
|
-
system("git commit -m 'packaged #{version}'") or raise "Failed to commit changes to Git"
|
34
|
-
puts "Packaging completed successfully."
|
40
|
+
delay = fibonacci(i)
|
41
|
+
sleep(delay)
|
35
42
|
|
43
|
+
|
44
|
+
end
|
36
45
|
end
|
37
46
|
|
38
|
-
|
39
|
-
|
40
|
-
|
47
|
+
# Example usage:
|
48
|
+
def with_error_handling
|
49
|
+
# Ensure the ~/.lbhrr directory exists
|
50
|
+
log_dir = File.expand_path("~/.lbhrr")
|
51
|
+
FileUtils.mkdir_p(log_dir) unless Dir.exist?(log_dir)
|
52
|
+
|
53
|
+
# Setup logger
|
54
|
+
logger = Logger.new("#{log_dir}/error.log")
|
55
|
+
|
56
|
+
begin
|
57
|
+
yield
|
58
|
+
rescue Interrupt
|
59
|
+
#logger.error("Operation interrupted by Ctrl+C")
|
60
|
+
rescue => e
|
61
|
+
logger.error("Error occurred: #{e.class}: #{e.message}")
|
62
|
+
raise
|
63
|
+
end
|
64
|
+
end
|
41
65
|
|
42
|
-
|
43
|
-
|
66
|
+
def increment_version(version, focus = :minor)
|
67
|
+
major, minor, patch = version.split(".").map(&:to_i)
|
68
|
+
|
69
|
+
case focus
|
70
|
+
when :major
|
71
|
+
major += 1
|
72
|
+
# Reset minor and patch to 0 when major version increments
|
73
|
+
minor = 0
|
74
|
+
patch = 0
|
75
|
+
when :minor
|
76
|
+
minor += 1
|
77
|
+
# Reset patch to 0 when minor version increments
|
78
|
+
patch = 0
|
79
|
+
when :patch
|
80
|
+
patch += 1
|
81
|
+
else
|
82
|
+
raise ArgumentError, "Invalid focus: #{focus}. Valid options are :major, :minor, :patch."
|
83
|
+
end
|
44
84
|
|
45
|
-
|
46
|
-
rescue => e
|
47
|
-
puts "Error during commit amend: #{e.message}"
|
85
|
+
"#{major}.#{minor}.#{patch}"
|
48
86
|
end
|
49
87
|
|
50
|
-
def
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
File.write(gitignore_path, gitignore_content.strip)
|
74
|
-
puts ".gitignore created for Rack project."
|
75
|
-
rescue => e
|
76
|
-
puts "Error creating .gitignore: #{e.message}"
|
88
|
+
def progressing(name = "Task")
|
89
|
+
# Start the long-running task in a separate thread, yielding to the given block
|
90
|
+
task_thread = Thread.new do
|
91
|
+
yield if block_given? # Execute the block representing the long-running task
|
92
|
+
end
|
93
|
+
|
94
|
+
spinner = Enumerator.new do |e|
|
95
|
+
rectangles = ["[ ]","[=]", "[==]", "[===]", "[===]", "[==","[=]","[ ]"]
|
96
|
+
loop do
|
97
|
+
rectangles.each { |rect| e.yield rect }
|
98
|
+
rectangles.reverse.each { |rect| e.yield rect }
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
until task_thread.join(0.1)
|
103
|
+
print "#{name} is in progress.. \r#{spinner.next}"
|
104
|
+
$stdout.flush
|
105
|
+
sleep(0.1)
|
106
|
+
end
|
107
|
+
|
108
|
+
# Clear the progress line
|
109
|
+
print "#{name} is in progress.. #{spinner.peek}\r"
|
110
|
+
nil
|
77
111
|
end
|
78
112
|
|
79
|
-
def
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
113
|
+
def find_container_ip(container_name)
|
114
|
+
initial_backoff_intervals = [5, 8, 13, 21]
|
115
|
+
ip_backoff_intervals = [1, 2, 3, 5, 8]
|
116
|
+
ip_address = nil
|
117
|
+
|
118
|
+
# First, check if the container is running
|
119
|
+
container_running = false
|
120
|
+
initial_backoff_intervals.each do |interval|
|
121
|
+
output, status = Open3.capture2("lxc list -f csv | grep #{container_name}")
|
122
|
+
if status.success? && !output.empty? && output.split(",")[1].strip == "RUNNING"
|
123
|
+
container_running = true
|
124
|
+
break
|
125
|
+
end
|
126
|
+
sleep(interval)
|
127
|
+
end
|
128
|
+
|
129
|
+
# If container is running, look for the IP address
|
130
|
+
if container_running
|
131
|
+
ip_backoff_intervals.each do |interval|
|
132
|
+
output, status = Open3.capture2("lxc list -f csv | grep #{container_name}")
|
133
|
+
if status.success? && !output.empty?
|
134
|
+
data = output.split(",")
|
135
|
+
ip_address = data[2].split(" ").first
|
136
|
+
if !ip_address.nil? && !ip_address.empty?
|
137
|
+
yield(ip_address) if block_given?
|
138
|
+
break
|
139
|
+
end
|
140
|
+
end
|
141
|
+
sleep(interval)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
ip_address
|
93
146
|
end
|
94
147
|
|
95
|
-
def
|
96
|
-
|
97
|
-
|
98
|
-
"
|
99
|
-
|
100
|
-
|
148
|
+
def clean_up(name = nil)
|
149
|
+
# Remove the build directory
|
150
|
+
if Dir.exist?("build")
|
151
|
+
FileUtils.rm_r("build")
|
152
|
+
end
|
153
|
+
# Remove gems on the container
|
154
|
+
`lxc exec #{name} -- rm -rf /var/gems/*`
|
101
155
|
end
|
102
156
|
|
103
|
-
def
|
157
|
+
def modify_manifest
|
158
|
+
file_path = "config/manifest.yml" # Update the path if necessary
|
159
|
+
|
160
|
+
# Read the YAML file
|
161
|
+
if File.exist?(file_path)
|
162
|
+
yaml_content = YAML.load_file(file_path)
|
104
163
|
|
105
|
-
|
106
|
-
|
107
|
-
require 'bundler/inline'
|
164
|
+
# Yield the hash to the block for modification
|
165
|
+
yield(yaml_content) if block_given?
|
108
166
|
|
109
|
-
|
110
|
-
|
111
|
-
|
167
|
+
# Write the changes back to the YAML file
|
168
|
+
File.write(file_path, yaml_content.to_yaml)
|
169
|
+
else
|
170
|
+
puts "File not found: #{file_path}"
|
112
171
|
end
|
172
|
+
end
|
113
173
|
|
114
|
-
|
174
|
+
def notify_terminal(message, title)
|
175
|
+
`terminal-notifier -message "#{message}" -title "#{title}" -contentImage "crane.png"`
|
176
|
+
end
|
115
177
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
end
|
178
|
+
def containerized?(name)
|
179
|
+
`lxc list -c n -f csv`.include? name
|
180
|
+
end
|
120
181
|
|
121
|
-
|
182
|
+
def create_container(name, image = "panamax")
|
183
|
+
return if containerized? name
|
184
|
+
config = load_configuration
|
122
185
|
|
123
|
-
if
|
124
|
-
|
125
|
-
web_run_file_content = "#!/bin/sh\n HARBR_ENV=$2 bundle exec puma -p $1"
|
126
|
-
exe_directory = File.join(Dir.pwd, "exe")
|
186
|
+
# Set default image if not specified
|
187
|
+
image = config["image"].nil? ? "panamax" : config["image"]
|
127
188
|
|
128
|
-
|
129
|
-
File.write(run_file_path, web_run_file_content)
|
130
|
-
File.chmod(0o755, run_file_path) # Set executable permission
|
131
|
-
puts "Created ./exe/run file."
|
132
|
-
end
|
189
|
+
`lxc launch #{image} #{name}` unless containerized? name
|
133
190
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
puts "Created ./service file."
|
147
|
-
|
191
|
+
find_container_ip(name) do |ip_address|
|
192
|
+
`harbr container add #{name} #{ip_address}`
|
193
|
+
|
194
|
+
if config["host"].nil?
|
195
|
+
`harbr host add #{name} 9292 #{name}.harbr.zero2one.ee`
|
196
|
+
`harbr host add #{name} 9393 next.#{name}.harbr.zero2one.ee`
|
197
|
+
else
|
198
|
+
`harbr host add #{name} 9292 #{config["host"]}`
|
199
|
+
`harbr host add #{name} 9393 next.#{config["host"]}`
|
200
|
+
end
|
201
|
+
|
202
|
+
`harbr commit`
|
148
203
|
end
|
204
|
+
end
|
149
205
|
|
150
|
-
|
206
|
+
# Method to process ERB templates and write to build directory
|
207
|
+
def process_template(template_path, target_path, binding)
|
208
|
+
content = ERB.new(File.read(template_path)).result(binding)
|
209
|
+
File.write(target_path, content)
|
210
|
+
end
|
211
|
+
|
212
|
+
def manifest?
|
213
|
+
File.exist? File.join(Dir.pwd, "config", "manifest.yml")
|
214
|
+
end
|
151
215
|
|
216
|
+
def commit(new_message)
|
217
|
+
# Ensure we are in a git repository
|
218
|
+
system("git rev-parse --git-dir > /dev/null 2>&1") or raise "Not a git repository"
|
219
|
+
# commit changes with the new message
|
220
|
+
`git commit -am '#{new_message}'`
|
152
221
|
rescue => e
|
153
|
-
puts "Error
|
222
|
+
puts "Error during commit amend: #{e.message}"
|
154
223
|
end
|
155
224
|
|
156
|
-
def
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
"host" => "#{File.basename(Dir.pwd)}.harbr.zero2one.ee"
|
163
|
-
}
|
225
|
+
def amend_last_commit(new_message)
|
226
|
+
# Ensure we are in a git repository
|
227
|
+
system("git rev-parse --git-dir > /dev/null 2>&1") or raise "Not a git repository"
|
228
|
+
|
229
|
+
# Amend the last commit with the new message
|
230
|
+
system("git commit --amend -m \"#{new_message}\"") or raise "Failed to amend the last commit"
|
164
231
|
|
165
|
-
|
232
|
+
puts "Successfully amended the last commit."
|
233
|
+
rescue => e
|
234
|
+
puts "Error during commit amend: #{e.message}"
|
166
235
|
end
|
167
236
|
|
168
237
|
def load_configuration
|
169
238
|
global_config_dir = File.expand_path("~/.config/harbr")
|
170
|
-
global_config_path = File.join(global_config_dir, "
|
239
|
+
global_config_path = File.join(global_config_dir, "manifest.yml")
|
171
240
|
local_config_path = File.join(Dir.pwd, "config", "manifest.yml")
|
172
|
-
|
173
241
|
# Ensure global configuration exists
|
174
242
|
unless File.exist?(global_config_path)
|
175
243
|
FileUtils.mkdir_p(global_config_dir) unless Dir.exist?(global_config_dir)
|
@@ -185,195 +253,253 @@ class LbhrrCLI < Thor
|
|
185
253
|
|
186
254
|
if File.exist? local_config_path
|
187
255
|
local_config = YAML.load_file(local_config_path) || {}
|
188
|
-
global_config.merge(local_config)
|
256
|
+
global_config.merge!(local_config)
|
189
257
|
end
|
190
258
|
|
191
259
|
global_config
|
192
260
|
end
|
193
261
|
|
194
|
-
|
195
|
-
|
262
|
+
desc "containerize", "Create a container for an app"
|
263
|
+
def containerize
|
264
|
+
config = load_configuration
|
265
|
+
name = config["name"]
|
266
|
+
image = config["image"]
|
267
|
+
if manifest?
|
268
|
+
create_container(name, image)
|
269
|
+
end
|
270
|
+
end
|
196
271
|
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
272
|
+
desc "rollback", "rollback an application using the configuration from config/manifest.yml"
|
273
|
+
def rollback(name = nil)
|
274
|
+
with_error_handling do
|
275
|
+
progressing("Roll back") do
|
276
|
+
config = load_configuration
|
277
|
+
name = name.nil? ? config["name"] : name
|
278
|
+
rolled_back = config["rolledback"]
|
279
|
+
|
280
|
+
if config["rolledback"] == true
|
281
|
+
puts "No rollback available"
|
282
|
+
else
|
283
|
+
`lxc exec #{name} -- bash -c 'if [ -d /var/www/app/container/live ]; then rm /var/www/app/container/live; fi'`
|
284
|
+
|
285
|
+
`lxc exec #{name} -- mv /var/www/app/container/rollback /var/www/app/container/live`
|
286
|
+
`lxc exec #{name} -- bash -c 'if [ -d /var/www/app/container/rollback ]; then rm /var/www/app/container/rollback; fi'`
|
287
|
+
`lxc exec #{name} -- sv restart live`
|
288
|
+
modify_manifest do |config|
|
289
|
+
config["live"] = config["rollback"]
|
290
|
+
config["rolledback"] = true
|
291
|
+
end
|
292
|
+
end
|
293
|
+
commit("Rolled back #{name} to version #{config["rollback"]} on live")
|
294
|
+
ok("https://#{config['host']}/ok",grace: 15) do
|
295
|
+
notify_terminal("#{name} version #{config['rollback']} is up on live!", "Lbhhr")
|
296
|
+
end
|
297
|
+
end
|
298
|
+
end
|
201
299
|
end
|
202
|
-
end
|
203
300
|
|
204
|
-
desc "init", "Initialize project with .gitignore"
|
205
|
-
method_option :type, type: :string, enum: ['web', 'service'], default: 'web', desc: "Specify the type of process"
|
206
|
-
def init
|
207
|
-
local_config_path = File.join(Dir.pwd, "config", "manifest.yml")
|
208
301
|
|
209
|
-
unless File.exist?(local_config_path)
|
210
|
-
FileUtils.mkdir_p(File.dirname(local_config_path)) unless Dir.exist?(File.dirname(local_config_path))
|
211
|
-
File.write(local_config_path, create_example_local_config(options[:type]))
|
212
|
-
end
|
213
|
-
# Load and merge configurations
|
214
|
-
local_config = YAML.load_file(local_config_path) || {}
|
215
|
-
create_gitignore
|
216
|
-
create_run_file(options[:type])
|
217
302
|
|
218
303
|
|
304
|
+
desc "assemble", "Build an application using the configuration from config/manifest.yml into a ruby gem"
|
305
|
+
def assemble(env = "next", version = nil)
|
306
|
+
config = load_configuration
|
307
|
+
name = config["name"]
|
308
|
+
image = config["image"]
|
309
|
+
|
310
|
+
containerize
|
219
311
|
|
220
|
-
|
221
|
-
|
312
|
+
# Check if we're in the root directory
|
313
|
+
if manifest?
|
314
|
+
# Create the build directory if it doesn't exist
|
315
|
+
if Dir.exist?("build")
|
316
|
+
FileUtils.rm_r("build")
|
317
|
+
end
|
222
318
|
|
223
|
-
|
224
|
-
def containers
|
225
|
-
config = load_configuration
|
226
|
-
host = config["host"]
|
227
|
-
user = config["user"]
|
228
|
-
puts `ssh #{user}@#{host} 'harbr containers'`
|
229
|
-
end
|
319
|
+
FileUtils.mkdir_p("build/src")
|
230
320
|
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
321
|
+
# Copy all files and folders to the build directory
|
322
|
+
Dir.glob("*").each do |item|
|
323
|
+
next if item == "build" # Skip the build directory itself
|
324
|
+
next if item == ".git" # Skip the .git directory
|
325
|
+
next if item == "tmp" # Skip the config directory
|
236
326
|
|
237
|
-
|
327
|
+
FileUtils.cp_r(item, "build/src/#{item}")
|
328
|
+
end
|
238
329
|
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
end
|
330
|
+
# Parameters for gemspec
|
331
|
+
gem_name = config["name"]
|
332
|
+
gem_version = version.nil? ? config["version"] : version
|
243
333
|
|
244
|
-
|
245
|
-
|
334
|
+
# Ensure the build directory exists
|
335
|
+
FileUtils.mkdir_p("build/lib")
|
246
336
|
|
247
|
-
|
248
|
-
|
337
|
+
# Define the template files and their target locations
|
338
|
+
template_dir = File.expand_path(File.join(File.dirname(__FILE__), "../", "templates"))
|
249
339
|
|
250
|
-
|
251
|
-
|
340
|
+
templates = {
|
341
|
+
"#{template_dir}/lib/panamax.rb.erb" => "build/lib/#{gem_name}.rb",
|
342
|
+
"#{template_dir}/lib/rubygems_plugin.rb.erb" => "build/lib/rubygems_plugin.rb",
|
343
|
+
"#{template_dir}/panamax.gemspec.erb" => "build/#{gem_name}.gemspec"
|
344
|
+
}
|
252
345
|
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
package
|
258
|
-
|
346
|
+
# Process each template
|
347
|
+
templates.each do |template, target|
|
348
|
+
process_template(template, target, binding)
|
349
|
+
end
|
259
350
|
|
260
|
-
|
261
|
-
|
262
|
-
user = config["user"]
|
263
|
-
raise "Host configuration missing" unless host
|
264
|
-
|
265
|
-
local_manifest_path = File.join(Dir.pwd, "config", "manifest.yml")
|
266
|
-
raise "Local manifest file not found at #{local_manifest_path}" unless File.exist?(local_manifest_path)
|
267
|
-
|
268
|
-
local_config = YAML.load_file(local_manifest_path) || {}
|
269
|
-
version = local_config["version"].to_i
|
270
|
-
raise "Version not specified in manifest.yml" unless version
|
271
|
-
|
272
|
-
basename = File.basename(Dir.pwd)
|
273
|
-
base_directory = "/var/harbr/containers/#{basename}"
|
274
|
-
versions_directory = "#{base_directory}/versions"
|
275
|
-
data_directory = "/var/dddr/#{basename}/"
|
276
|
-
destination_path = "#{versions_directory}/#{version}"
|
277
|
-
# Prepare the rsync exclude option using .gitignore
|
278
|
-
gitignore_path = File.join(Dir.pwd, ".gitignore")
|
279
|
-
exclude_option = File.exist?(gitignore_path) ? "--exclude='.git' --exclude-from='#{gitignore_path}'" : ""
|
280
|
-
|
281
|
-
|
282
|
-
# Check and create the versions directory on the server
|
283
|
-
`ssh #{user}@#{host} 'mkdir -p #{versions_directory}'`
|
284
|
-
`ssh #{user}@#{host} 'mkdir -p #{data_directory}'`
|
285
|
-
|
286
|
-
# Rsync files to the new version directory, excluding files as per .gitignore
|
287
|
-
rsync_command = "rsync -avz #{exclude_option} ./ #{user}@#{host}:#{destination_path}"
|
288
|
-
|
289
|
-
if `#{rsync_command}`
|
290
|
-
puts "Successfully deployed application version #{version} to #{host}"
|
291
|
-
deployed(local_manifest_path, version)
|
351
|
+
`cd build && gem build #{gem_name}.gemspec`
|
352
|
+
notify_terminal("Assembled #{name}", "Lbhhr")
|
292
353
|
else
|
293
|
-
puts "
|
354
|
+
puts "config/manifest file not found. Please ensure you are in the root directory of your project."
|
294
355
|
end
|
295
|
-
|
296
|
-
else
|
297
|
-
puts "no manifest found!"
|
298
356
|
end
|
299
357
|
|
300
358
|
end
|
301
359
|
|
302
|
-
desc "logs", "Show logs for a container"
|
303
|
-
method_option :live, type: :boolean, aliases: "-l", desc: "Process in live mode"
|
304
|
-
method_option :next, type: :boolean, default: true, aliases: "-n", desc: "Process in next mode"
|
305
|
-
def logs(name=nil)
|
306
|
-
config = load_configuration
|
307
|
-
host = config["host"]
|
308
|
-
user = config["user"]
|
309
|
-
|
310
|
-
if name.nil?
|
311
|
-
unless manifest?
|
312
|
-
puts "no manifest found!"
|
313
|
-
return
|
314
|
-
end
|
315
|
-
|
316
|
-
container_name = config["name"]
|
317
360
|
|
318
|
-
|
319
|
-
|
361
|
+
desc "drop", "Destroy an app and remove all traces"
|
362
|
+
def drop(name = nil)
|
363
|
+
with_error_handling do
|
364
|
+
return unless yes?("Are you sure you want to drop this app? This action cannot be undone. (y/n)")
|
365
|
+
|
366
|
+
# Load configuration and retrieve the name if not provided
|
367
|
+
config = load_configuration unless name
|
368
|
+
name ||= config["name"]
|
369
|
+
|
370
|
+
progressing("Drop") do
|
371
|
+
if manifest?
|
372
|
+
# Check if the LXC container exists
|
373
|
+
if `lxc list`.include?(name)
|
374
|
+
# Commands to run if the container exists
|
375
|
+
`lxc delete #{name} --force`
|
376
|
+
`harbr container delete #{name}`
|
377
|
+
`harbr commit`
|
378
|
+
end
|
379
|
+
end
|
380
|
+
end
|
320
381
|
end
|
382
|
+
end
|
321
383
|
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
384
|
+
desc "logs", "Show logs for the container"
|
385
|
+
method_option :live, type: :boolean, aliases: "-l", desc: "Process in live mode"
|
386
|
+
def logs(name = nil)
|
387
|
+
with_error_handling do
|
388
|
+
config = load_configuration
|
389
|
+
name = config["name"]
|
390
|
+
if options[:live]
|
391
|
+
exec "lxc exec #{name} -- tail -f /var/log/container/live/current"
|
392
|
+
else
|
393
|
+
exec "lxc exec #{name} -- tail -f /var/log/container/next/current"
|
394
|
+
end
|
326
395
|
end
|
327
396
|
end
|
328
397
|
|
398
|
+
desc "hoist", "Deploy an application using the configuration from config/manifest.yml to next"
|
399
|
+
method_option :major, type: :boolean, aliases: "-ma", desc: "Increment major version"
|
400
|
+
method_option :msg, type: :boolean, aliases: "-msg", desc: "set the commit message"
|
401
|
+
method_option :minor, type: :boolean, aliases: "-mi", desc: "Increment minor version"
|
402
|
+
method_option :feature, type: :boolean, aliases: "-fea", desc: "Increment minor version"
|
403
|
+
method_option :fix, type: :boolean, aliases: "-f", desc: "Increment minor version"
|
404
|
+
method_option :release, type: :boolean, aliases: "-rel", desc: "Increment minor version"
|
405
|
+
method_option :patch, type: :boolean, aliases: "-pa", desc: "Increment minor version"
|
406
|
+
def hoist(name = nil)
|
407
|
+
with_error_handling do
|
408
|
+
config = load_configuration
|
329
409
|
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
host = config["host"]
|
335
|
-
user = config["user"]
|
336
|
-
exec "ssh #{user}@#{host} 'harbr logs'"
|
337
|
-
end
|
410
|
+
msg =nil
|
411
|
+
if options[:msg]
|
412
|
+
msg = ask("commit massage: ")
|
413
|
+
end
|
338
414
|
|
415
|
+
focus = nil
|
339
416
|
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
417
|
+
focus = if options[:major] || options[:release]
|
418
|
+
"major"
|
419
|
+
elsif options[:minor] || options[:feature]
|
420
|
+
"minor"
|
421
|
+
elsif options[:patch] || options[:fix]
|
422
|
+
"patch"
|
423
|
+
else
|
424
|
+
"patch"
|
425
|
+
end
|
345
426
|
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
427
|
+
version = increment_version(config["version"], focus.to_sym)
|
428
|
+
|
429
|
+
modify_manifest do |config|
|
430
|
+
config["version"] = version
|
431
|
+
end
|
432
|
+
|
433
|
+
progressing("Hoist") do
|
434
|
+
name = config["name"]
|
435
|
+
gem = "#{name}-#{version}.gem"
|
436
|
+
assemble "next", version
|
437
|
+
`lxc file push -rp build/#{gem} #{name}/var/gems/`
|
438
|
+
`lxc exec #{name} -- /root/.rbenv/shims/gem install /var/gems/#{gem} --no-document`
|
439
|
+
`lxc exec #{name} -- /root/.rbenv/shims/gem install /var/gems/#{gem} --no-document`
|
440
|
+
`lxc exec #{name} -- sv restart next`
|
441
|
+
`lxc exec #{name} -- sv restart next.ws`
|
442
|
+
|
443
|
+
modify_manifest do |config|
|
444
|
+
config["next"] = version
|
445
|
+
end
|
446
|
+
|
447
|
+
clean_up(name)
|
448
|
+
|
449
|
+
change = "RELEASE #{version}"
|
450
|
+
commit("#{change}\n\n#{msg}\n\n Hoisted #{name} version #{version}")
|
451
|
+
|
452
|
+
ok("https://next.#{config['host']}/ok",grace: 25) do
|
453
|
+
notify_terminal(" #{name} version #{version} is up on next!", "Lbhhr")
|
454
|
+
end
|
350
455
|
end
|
351
|
-
name = config["name"]
|
352
456
|
end
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
457
|
+
end
|
458
|
+
|
459
|
+
desc "deploy", "Deploy an application using the configuration from config/manifest.yml to live"
|
460
|
+
def deploy(name = nil)
|
461
|
+
with_error_handling do
|
462
|
+
progressing("Deploy") do
|
463
|
+
config = load_configuration
|
464
|
+
name = name.nil? ? config["name"] : name
|
465
|
+
if config["next"].nil?
|
466
|
+
puts "No deploymnt available"
|
467
|
+
else
|
468
|
+
`lxc exec #{name} -- bash -c 'if [ -d /var/www/app/container/rollback ]; then rm -rf /var/www/app/container/rollback; fi'`
|
469
|
+
`lxc exec #{name} -- mv /var/www/app/container/live /var/www/app/container/rollback`
|
470
|
+
`lxc exec #{name} -- cp -r /var/www/app/container/next /var/www/app/container/live`
|
471
|
+
`lxc exec #{name} -- sv restart live`
|
472
|
+
`lxc exec #{name} -- sv restart ws`
|
473
|
+
modify_manifest do |config|
|
474
|
+
config["rollback"] = config["live"]
|
475
|
+
config["live"] = config["next"]
|
476
|
+
config["rolledback"] = false
|
477
|
+
end
|
478
|
+
end
|
479
|
+
commit("Deployed #{name} version #{config["live"]} to live")
|
480
|
+
|
481
|
+
ok("https://#{config['host']}/ok",grace: 15) do
|
482
|
+
notify_terminal(" #{name} version #{version} is up on live!", "Lbhhr")
|
483
|
+
end
|
484
|
+
|
367
485
|
end
|
368
|
-
name = config["name"]
|
369
486
|
end
|
370
|
-
|
371
|
-
end
|
487
|
+
end
|
372
488
|
|
489
|
+
desc "version", "Display the version of Lbhrr"
|
490
|
+
def version
|
491
|
+
with_error_handling do
|
492
|
+
puts "lbhrr version #{Lbhrr::VERSION}"
|
493
|
+
end
|
494
|
+
end
|
373
495
|
|
374
|
-
|
375
|
-
|
496
|
+
desc "update", "Display the version of Lbhrr"
|
497
|
+
def update
|
498
|
+
with_error_handling do
|
499
|
+
`gem update lbhrr --conservative`
|
500
|
+
end
|
376
501
|
end
|
502
|
+
|
377
503
|
end
|
378
504
|
|
379
505
|
LbhrrCLI.start(ARGV)
|
@@ -0,0 +1 @@
|
|
1
|
+
d2914e65-5f28-492f-9615-4f00fb29e437
|
@@ -0,0 +1,5 @@
|
|
1
|
+
L9l8YThIoCo83pL/5hZ5mrNTzRRCdUBuxXFYZxe5ZUSC0yeKn3tq11znnEaWXrWFiqaV62V8xhpHWBJo1B9gLA==
|
2
|
+
5cmFh3rph/f/5dJr8MK8do6VyW44B5naEQg8iTHMaE1eXbLaS5lrZ9Co+VuybfQPkocGkPeYT4b55Ii7jzvDtw==
|
3
|
+
vk/l4x1F9rcoJXdZoF3XIod68atgQZ9LeS3VRkZOmgQkA77FhqtZqXjPEo9/dVlz7CiS1P50jhg1SkdeFO5e5A==
|
4
|
+
S7phDwdvAtXd4h6sjr/W+9uhGakSwObf3kAdyA30wQeajXY2d1oAygDXtr6bMEv5F5WfgbD0nz4vlPyO+e4Tuw==
|
5
|
+
XanoLNMHjZM9LirLNYxnmFRZNDcWB7FqP1/MvE7Wxwa362mQi3wTwsvFsIE6c3yOv7WcokzgSMlmseD/BBX/Yg==
|
data/lib/lbhrr/version.rb
CHANGED
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'prettyprint'
|
2
|
+
|
3
|
+
Gem.pre_install do |installer|
|
4
|
+
if installer.spec.metadata.dig("container") == "panamax"
|
5
|
+
env = installer.spec.metadata.dig("env")
|
6
|
+
destination = File.join(installer.spec.metadata.dig("destination"), env)
|
7
|
+
src = File.expand_path(File.join(File.dirname(__FILE__), '..', 'src'))
|
8
|
+
system("rm -rf #{destination}")
|
9
|
+
puts "deploying #{installer.spec.name} to #{destination}"
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
|
14
|
+
Gem.post_install do |installer|
|
15
|
+
if installer.spec.metadata.dig("container") == "panamax"
|
16
|
+
env = installer.spec.metadata.dig("env")
|
17
|
+
destination = File.join(installer.spec.metadata.dig("destination"), env)
|
18
|
+
src = File.expand_path(File.join(File.dirname(__FILE__), '..', 'src'))
|
19
|
+
|
20
|
+
|
21
|
+
if env == "live"
|
22
|
+
puts "symlink files to #{destination}"
|
23
|
+
system("ln -sf #{src} #{destination}")
|
24
|
+
else
|
25
|
+
puts "copy files #{destination}"
|
26
|
+
system("cp -rf #{src} #{destination}")
|
27
|
+
puts "copy uploads"
|
28
|
+
live = File.join(installer.spec.metadata.dig("destination"), "live")
|
29
|
+
system("cp -rf #{live}/public/uploads/ #{destination}/public/uploads/")
|
30
|
+
puts "uploads synced"
|
31
|
+
end
|
32
|
+
|
33
|
+
if File.exist?("#{destination}/bin/hoisted")
|
34
|
+
system("chmod +x #{destination}/bin/hoisted")
|
35
|
+
system("cd #{destination} && ./bin/hoisted")
|
36
|
+
end
|
37
|
+
|
38
|
+
puts "deployed #{installer.spec.name} to #{destination}"
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
require_relative 'lib/<%= gem_name%>'
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = '<%= gem_name %>'
|
6
|
+
s.version = '<%= gem_version %>'
|
7
|
+
s.authors = ["Delaney Burke"]
|
8
|
+
s.email = "delaney@zero2one.ee"
|
9
|
+
s.homepage = "http://zero2one.ee/gems/<%= gem_name%>"
|
10
|
+
s.summary = "<%= gem_name %> container desscripton"
|
11
|
+
s.description = "<%= gem_name %> container"
|
12
|
+
s.required_rubygems_version = ">= 1.3.6"
|
13
|
+
s.files = Dir['lib/**/*', 'src/**/*'].reject { |f| File.directory?(f) }
|
14
|
+
# s.add_dependency 'some-gem'
|
15
|
+
# s.extra_rdoc_files = ['README.md', 'LICENSE']
|
16
|
+
s.license = 'MIT'
|
17
|
+
s.metadata = {
|
18
|
+
"container" => "panamax",
|
19
|
+
"env" => <%= gem_name.capitalize %>::ENV,
|
20
|
+
"destination" => <%= gem_name.capitalize %>::DESTINATION
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lbhrr
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.32.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Delaney Kuldvee Burke
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-03-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: net-ssh
|
@@ -34,9 +34,10 @@ executables:
|
|
34
34
|
extensions: []
|
35
35
|
extra_rdoc_files: []
|
36
36
|
files:
|
37
|
+
- ".DS_Store"
|
37
38
|
- ".gitignore"
|
38
|
-
- ".gitlab-ci.yml"
|
39
39
|
- ".rspec"
|
40
|
+
- ".ruby-version"
|
40
41
|
- ".standard.yml"
|
41
42
|
- CHANGELOG.md
|
42
43
|
- CODE_OF_CONDUCT.md
|
@@ -47,13 +48,18 @@ files:
|
|
47
48
|
- Rakefile
|
48
49
|
- bin/console
|
49
50
|
- bin/setup
|
50
|
-
-
|
51
|
+
- crane.png
|
51
52
|
- exe/lbhrr
|
52
53
|
- hero.png
|
53
54
|
- lbhrr.gemspec
|
55
|
+
- lib/.kafkr/acknowledged_messages.txt
|
56
|
+
- lib/.kafkr/message_queue.txt
|
54
57
|
- lib/lbhrr.rb
|
55
58
|
- lib/lbhrr/version.rb
|
56
59
|
- sig/lbhrr.rbs
|
60
|
+
- templates/lib/panamax.rb.erb
|
61
|
+
- templates/lib/rubygems_plugin.rb.erb
|
62
|
+
- templates/panamax.gemspec.erb
|
57
63
|
homepage: https://github.com/dekubu/lbhrr
|
58
64
|
licenses:
|
59
65
|
- MIT
|
@@ -76,7 +82,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
76
82
|
- !ruby/object:Gem::Version
|
77
83
|
version: '0'
|
78
84
|
requirements: []
|
79
|
-
rubygems_version: 3.
|
85
|
+
rubygems_version: 3.5.5
|
80
86
|
signing_key:
|
81
87
|
specification_version: 4
|
82
88
|
summary: A CLI tool for deploying and managing Rack applications.
|
data/.gitlab-ci.yml
DELETED