Class: MultiRepo::Service::Docker

Inherits:
Object
  • Object
show all
Defined in:
lib/multi_repo/service/docker.rb

Constant Summary collapse

SMALL_IMAGE =
"hello-world:latest".freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(registry: self.class.registry, default_headers: nil, cache: true, dry_run: false) ⇒ Docker

Returns a new instance of Docker.



49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/multi_repo/service/docker.rb', line 49

def initialize(registry: self.class.registry, default_headers: nil, cache: true, dry_run: false)
  require "rest-client"
  require "fileutils"
  require "json"

  @registry = registry
  @default_headers = default_headers

  @cache   = cache
  @dry_run = dry_run

  self.class.clear_cache unless cache
end

Instance Attribute Details

#cacheObject

Returns the value of attribute cache.



47
48
49
# File 'lib/multi_repo/service/docker.rb', line 47

def cache
  @cache
end

#default_headersObject

Returns the value of attribute default_headers.



47
48
49
# File 'lib/multi_repo/service/docker.rb', line 47

def default_headers
  @default_headers
end

#dry_runObject

Returns the value of attribute dry_run.



47
48
49
# File 'lib/multi_repo/service/docker.rb', line 47

def dry_run
  @dry_run
end

#registryObject

Returns the value of attribute registry.



47
48
49
# File 'lib/multi_repo/service/docker.rb', line 47

def registry
  @registry
end

Class Method Details

.clear_cacheObject



11
12
13
# File 'lib/multi_repo/service/docker.rb', line 11

def self.clear_cache
  FileUtils.rm_f(Dir.glob("/tmp/docker-*"))
end

.ensure_small_imageObject



17
18
19
20
21
22
23
# File 'lib/multi_repo/service/docker.rb', line 17

def self.ensure_small_image
  return @has_small_image if defined?(@has_small_image)

  return false unless system?("docker pull #{SMALL_IMAGE} &>/dev/null")

  @has_small_image = true
end

.registryObject



3
4
5
# File 'lib/multi_repo/service/docker.rb', line 3

def self.registry
  @registry ||= ENV.fetch("DOCKER_REGISTRY")
end

.registry=(endpoint) ⇒ Object



7
8
9
# File 'lib/multi_repo/service/docker.rb', line 7

def self.registry=(endpoint)
  @registry = endpoint
end

.system!(command, **kwargs) ⇒ Object



43
44
45
# File 'lib/multi_repo/service/docker.rb', line 43

def self.system!(command, **kwargs)
  exit($?.exitstatus) unless system?(command, **kwargs)
end

.system?(command, dry_run: false, verbose: true) ⇒ Boolean

Returns:

  • (Boolean)


33
34
35
36
37
38
39
40
41
# File 'lib/multi_repo/service/docker.rb', line 33

def self.system?(command, dry_run: false, verbose: true)
  if dry_run
    puts "+ dry_run: #{command}".light_black
    true
  else
    puts "+ #{command}".light_black
    system(command)
  end
end

.tag_small_image(fq_path) ⇒ Object



25
26
27
28
29
30
31
# File 'lib/multi_repo/service/docker.rb', line 25

def self.tag_small_image(fq_path)
  return false unless ensure_small_image

  system?("docker tag #{SMALL_IMAGE} #{fq_path}") &&
    system?("docker push #{fq_path}") &&
    system?("docker rmi #{fq_path}")
end

Instance Method Details

#delete_registry_tag(image, tag, **kwargs) ⇒ Object



75
76
77
78
79
80
81
82
83
# File 'lib/multi_repo/service/docker.rb', line 75

def delete_registry_tag(image, tag, **kwargs)
  path = File.join("v2", image, "manifests", tag)
  request(:delete, path, **kwargs)
  true
rescue RestClient::NotFound => err
  # Ignore deletes on 404s because they are either already deleted or the tag is orphaned.
  raise unless err.http_code == 404
  false
end

#fetch_image_by_sha(source_image, tag: nil, platform: nil) ⇒ Object



98
99
100
101
102
103
104
105
# File 'lib/multi_repo/service/docker.rb', line 98

def fetch_image_by_sha(source_image, tag: nil, platform: nil)
  source_image_name, _source_image_sha = source_image.split("@")

  system!("docker pull #{"--platform=#{platform} " if platform}#{source_image}")
  system!("docker tag #{source_image} #{source_image_name}:#{tag}") if tag

  true
end

#force_delete_registry_tag(image, tag, **kwargs) ⇒ Object



85
86
87
88
89
90
91
92
# File 'lib/multi_repo/service/docker.rb', line 85

def force_delete_registry_tag(image, tag, **kwargs)
  return true if delete_registry_tag(image, tag, **kwargs)

  # The tag is likely orphaned, so recreate the tag with a new image, then immediately delete it
  fq_path = File.join(registry, "#{image}:#{tag}")
  self.class.tag_small_image(fq_path) &&
    delete_registry_tag(image, tag, **kwargs)
end

#manifest_inspect(image) ⇒ Object



119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/multi_repo/service/docker.rb', line 119

def manifest_inspect(image)
  command = "docker manifest inspect #{image}"

  cache_file = "/tmp/docker-manifest-#{image.split("@").last}.txt"
  if cache && File.exist?(cache_file)
    puts "+ cached: #{command}".light_black
    data = File.read(cache_file)
  else
    data = system_capture(command)
    File.write(cache_file, data)
  end

  data.blank? ? {} : JSON.parse(data)
end

#remove_images(*images) ⇒ Object



107
108
109
110
111
112
113
114
115
116
117
# File 'lib/multi_repo/service/docker.rb', line 107

def remove_images(*images)
  command = "docker rmi #{images.join(" ")}"

  # Don't use system_capture! as this is expected to fail if the image does not exist.
  if dry_run
    puts "+ dry_run: #{command}".light_black
  else
    puts "+ #{command}".light_black
    `#{command} 2>/dev/null`
  end
end

#retag(image, new_image) ⇒ Object



71
72
73
# File 'lib/multi_repo/service/docker.rb', line 71

def retag(image, new_image)
  system?("skopeo copy --multi-arch all docker://#{image} docker://#{new_image}", dry_run: dry_run)
end

#run(image, command, platform: nil) ⇒ Object



94
95
96
# File 'lib/multi_repo/service/docker.rb', line 94

def run(image, command, platform: nil)
  system_capture!("docker run --rm -it #{"--platform=#{platform} " if platform} #{image} #{command}")
end

#tags(image, **kwargs) ⇒ Object



63
64
65
66
67
68
69
# File 'lib/multi_repo/service/docker.rb', line 63

def tags(image, **kwargs)
  path = File.join("v2", image, "tags/list")
  cache_file = "/tmp/docker-tags-#{image.tr("/", "-")}-raw-#{Date.today}.json"
  request(:get, path, **kwargs).tap do |data|
    File.write(cache_file, JSON.pretty_generate(data))
  end["tags"]
end