Class: Tebako::ReleaseStore

Inherits:
Object
  • Object
show all
Defined in:
lib/tebako/release_store.rb

Overview

Content-addressed package releases with verified atomic activation and rollback.

Constant Summary collapse

SCHEMA_VERSION =
1

Instance Method Summary collapse

Constructor Details

#initialize(root) ⇒ ReleaseStore

Returns a new instance of ReleaseStore.



22
23
24
25
26
27
28
# File 'lib/tebako/release_store.rb', line 22

def initialize(root)
  @root = File.expand_path(root)
  @objects = File.join(@root, "objects", "sha256")
  @releases = File.join(@root, "releases")
  @history = File.join(@root, "history.json")
  @lock = File.join(@root, "update.lock")
end

Instance Method Details

#activate(release_id, target) ⇒ Object



58
59
60
61
62
63
64
65
66
67
68
# File 'lib/tebako/release_store.rb', line 58

def activate(release_id, target)
  with_lock do
    release = load_release(release_id)
    package_object = object_path(release.fetch("package_sha256"))
    verify_object!(package_object, release.fetch("package_sha256"), release.fetch("package_size"))
    previous = File.file?(target) ? Digest::SHA256.file(target).hexdigest : nil
    publish_target(package_object, target)
    append_history(release_id, previous)
    release
  end
end

#import(package_path) ⇒ Object



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/tebako/release_store.rb', line 30

def import(package_path)
  inspection = Tebako::LayeredPackage.inspect(package_path)
  package = File.binread(package_path)
  FileUtils.mkdir_p([@objects, @releases])
  new_objects = 0
  new_objects += 1 if store_object(inspection.sha256, package)
  layers = inspection.layers.map do |layer|
    payload = package.byteslice(layer.offset, layer.byte_size)
    new_objects += 1 if store_object(layer.sha256, payload)
    {
      "mount_point" => layer.mount_point,
      "sha256" => layer.sha256,
      "size" => layer.byte_size
    }
  end
  release = {
    "schema_version" => SCHEMA_VERSION,
    "release_id" => inspection.sha256,
    "package_sha256" => inspection.sha256,
    "package_size" => inspection.byte_size,
    "format" => inspection.format,
    "format_version" => "#{inspection.major_version}.#{inspection.minor_version}",
    "layers" => layers
  }
  atomic_write_json(release_path(inspection.sha256), release)
  release.merge("new_objects" => new_objects)
end

#rollback(target) ⇒ Object



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/tebako/release_store.rb', line 70

def rollback(target)
  with_lock do
    history = read_history
    raise ArgumentError, "No previous release is available" if history.length < 2

    history.pop
    previous = history.last.fetch("release_id")
    release = load_release(previous)
    package_object = object_path(release.fetch("package_sha256"))
    verify_object!(package_object, release.fetch("package_sha256"), release.fetch("package_size"))
    publish_target(package_object, target)
    atomic_write_json(@history, history)
    release
  end
end

#statusObject



86
87
88
89
90
91
92
93
# File 'lib/tebako/release_store.rb', line 86

def status
  {
    "schema_version" => SCHEMA_VERSION,
    "history" => read_history,
    "objects" => Dir.exist?(@objects) ? Dir.children(@objects).length : 0,
    "releases" => Dir.exist?(@releases) ? Dir.glob(File.join(@releases, "*.json")).length : 0
  }
end