ubicloud/prog/install_rhizome.rb
Jeremy Evans 6de231a5de Fix PostgresServerNexus#destroy to not violate strand leases
Previously, PostgresServerNexus#destroy ran:

```ruby
strand.children.each { it.destroy }
```

This is not safe as there could be an existing lease for the
strand children.  Child strands are either:

* BootstrapRhizome
* InstallRhizome (via push from Bootstrap Rhizome)
* Postgres::PostgresServerNexus (via restart from #unavailable)

Fix this by adding a destroy semaphore for all child strands,
except the Postgres::PostgresServerNexus ones, as we don't want
a child restart prog for the same server to also go into destroy.

Note that if a restart has been triggered via unavailable, and
then the destroy semaphore has been incremented, the destroy
cannot complete until after the restart commands return
successfully.

It would probably be better to have restart in a separate prog,
that could exit similarly to how Boostrap/InstallRhizome are
setup, so that destruction could proceed even if the restart
commands will not run successfully.
2025-09-16 06:11:16 +09:00

67 lines
1.6 KiB
Ruby

# frozen_string_literal: true
require "rubygems/package"
require "stringio"
require "digest/sha2"
class Prog::InstallRhizome < Prog::Base
subject_is :sshable
semaphore :destroy
SKIP_VALIDATION = ["Gemfile.lock"]
def before_run
when_destroy_set? do
pop "exiting early due to destroy semaphore"
end
end
label def start
tar = StringIO.new
file_hash_map = {} # pun intended
Gem::Package::TarWriter.new(tar) do |writer|
base = Config.root + "/rhizome"
Dir.glob(["Gemfile", "Gemfile.lock", "common/**/*", "#{frame["target_folder"]}/**/*"], base: base) do |file|
next if !frame["install_specs"] && file.end_with?("_spec.rb")
full_path = base + "/" + file
stat = File.stat(full_path)
if stat.directory?
writer.mkdir(file, stat.mode)
elsif stat.file?
writer.add_file(file, stat.mode) do |tf|
File.open(full_path, "rb") do
IO.copy_stream(it, tf)
end
end
file_hash_map[file] = Digest::SHA384.file(full_path).hexdigest unless SKIP_VALIDATION.include?(file)
else
# :nocov:
fail "BUG"
# :nocov:
end
end
writer.add_file("hashes.json", 0o100755) do |tf|
tf.write file_hash_map.to_json
end
end
payload = tar.string.freeze
sshable.cmd("tar xf -", stdin: payload)
hop_install_gems
end
label def install_gems
sshable.cmd("bundle config set --local path vendor/bundle && bundle install")
hop_validate
end
label def validate
sshable.cmd("common/bin/validate")
pop "installed rhizome"
end
end