Skip to content

Commit

Permalink
improve logging of failed container deletions
Browse files Browse the repository at this point in the history
  • Loading branch information
skaes committed Mar 4, 2024
1 parent 5dc1566 commit 8379278
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 79 deletions.
32 changes: 22 additions & 10 deletions lib/fpm/fry/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ class ContainerCreationFailed < StandardError
include FPM::Fry::WithData
end

class ContainerDeletionFailed < StandardError
include FPM::Fry::WithData
end

# Raised when trying to read file that can't be read e.g. because it's a
# directory.
class NotAFile < StandardError
Expand Down Expand Up @@ -111,7 +115,7 @@ def read(name, resource)
)
end
rescue Excon::Error => e
@logger.error("unexpected response when reading resource: url: #{url}, error: #{e}")
logger.error("unexpected response when reading resource: url: #{url}, error: #{e}")
raise
end
if [404,500].include? res.status
Expand Down Expand Up @@ -165,14 +169,14 @@ def link_target(name, resource)
end

def copy(name, resource, map, options = {})
ex = FPM::Fry::Tar::Extractor.new(logger: @logger)
ex = FPM::Fry::Tar::Extractor.new(logger: logger)
base = File.dirname(resource)
read(name, resource) do | entry |
file = File.join(base, entry.full_name).chomp('/')
file = file.sub(%r"\A\./",'')
to = map[file]
next unless to
@logger.debug("Copy",name: file, to: to)
logger.debug("Copy",name: file, to: to)
ex.extract_entry(to, entry, options)
end
end
Expand All @@ -182,7 +186,7 @@ def changes(name)
res = agent.get(path: url, expects: [200, 204])
return JSON.parse(res.body)
rescue Excon::Error => e
@logger.error("could not retrieve changes for: #{name}, url: #{url}, error: #{e}")
logger.error("could not retrieve changes for: #{name}, url: #{url}, error: #{e}")
raise
end

Expand Down Expand Up @@ -220,27 +224,35 @@ def create(image)
)
data = JSON.parse(res.body)
if res.status != 201
@logger.error(data["message"])
logger.error(data["message"])
if res.status == 404
@logger.info("execute docker pull #{image} first or specify --pull argument for fpm-fry")
logger.info("execute docker pull #{image} first or specify --pull argument for fpm-fry")
end
raise ContainerCreationFailed.new("could not create container from #{image}", message: data["message"])
end
data['Id']
rescue Excon::Error => e
@logger.error("could not create container from #{image}, url: #{url}, error: #{e}")
logger.error("could not create container from #{image}, url: #{url}, error: #{e}")
raise
end

def destroy(container)
return unless container

url = self.url('containers', container)
agent.delete(
res = agent.delete(
path: url,
expects: [204]
expects: [204, 409]
)
return unless res.status == 409
data = JSON.parse(res.body) rescue ({"message" => "could not parse response body: '#{res.body}'"})
if data["message"] =~ /removal of container .* is already in progress/
logger.info(data["message"])
else
raise ContainerDeletionFailed.new("could not destroy container #{container}", data)
end
rescue Excon::Error => e
@logger.error("could not destroy container: #{container}, url: #{url}, error: #{e}")
logger.error("could not destroy container: #{container}, url: #{url}, error: #{e}")
raise
end

Expand Down
144 changes: 75 additions & 69 deletions lib/fpm/fry/command/cook.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
module FPM; module Fry
class Command::Cook < Command

class BuildFailed < StandardError
include FPM::Fry::WithData
end

option '--keep', :flag, 'Keep the container after build'
option '--overwrite', :flag, 'Overwrite package', default: true
option '--verbose', :flag, 'Verbose output', default: false
Expand Down Expand Up @@ -212,79 +216,81 @@ def pull_base_image!
end

def build!
body = begin
url = client.url('containers','create')
args = {
headers: {
'Content-Type' => 'application/json'
},
path: url,
expects: [201],
body: JSON.generate({"Image" => build_image})
}
args[:query] = { platform: platform } if platform
res = client.post(args)
JSON.parse(res.body)
rescue Excon::Error
logger.error "could not create #{build_image}, url: #{url}"
raise
end
container = body['Id']
begin
begin
url = client.url('containers',container,'start')
client.post(
headers: {
'Content-Type' => 'application/json'
},
path: url,
expects: [204],
body: JSON.generate({})
)
rescue Excon::Error
logger.error "could not start container #{container}, url: #{url}"
raise
end
container = create_build_container
start_build_container(container)
attach_to_build_container_and_stream_logs(container)
wait_for_build_container_to_shut_down(container)
yield container
ensure
unless keep?
client.destroy(container) if container
end
end

begin
url = client.url('containers',container,'attach?stderr=1&stdout=1&stream=1&logs=1')
client.post(
path: url,
body: '',
expects: [200],
middlewares: [
StreamParser.new(out,err),
Excon::Middleware::Expects,
Excon::Middleware::Instrumentor,
Excon::Middleware::Mock
]
)
rescue Excon::Error
logger.error "could not attach to container #{container}, url: #{url}"
raise
end
def create_build_container
url = client.url('containers','create')
args = {
headers: {
'Content-Type' => 'application/json'
},
path: url,
expects: [201],
body: JSON.generate({"Image" => build_image})
}
args[:query] = { platform: platform } if platform
res = client.post(args)
JSON.parse(res.body)['Id']
rescue Excon::Error
logger.error "could not create #{build_image}, url: #{url}"
raise
end

begin
res = client.post(
path: client.url('containers',container,'wait'),
expects: [200],
body: ''
)
json = JSON.parse(res.body)
if json["StatusCode"] != 0
raise Fry::WithData("Build failed", exit_code: json["StatusCode"])
end
rescue Excon::Error
logger.error "could not wait successfully for container #{container}, url: #{url}"
raise
end
def start_build_container(container)
url = client.url('containers',container,'start')
client.post(
headers: {
'Content-Type' => 'application/json'
},
path: url,
expects: [204],
body: JSON.generate({})
)
rescue Excon::Error
logger.error "could not start container #{container}, url: #{url}"
raise
end

yield container
ensure
unless keep?
client.destroy(container)
end
def attach_to_build_container_and_stream_logs(container)
url = client.url('containers',container,'attach?stderr=1&stdout=1&stream=1&logs=1')
client.post(
path: url,
body: '',
expects: [200],
middlewares: [
StreamParser.new(out,err),
Excon::Middleware::Expects,
Excon::Middleware::Instrumentor,
Excon::Middleware::Mock
]
)
rescue Excon::Error
logger.error "could not attach to container #{container}, url: #{url}"
raise
end

def wait_for_build_container_to_shut_down(container)
res = client.post(
path: client.url('containers',container,'wait'),
expects: [200],
body: ''
)
json = JSON.parse(res.body)
if json["StatusCode"] != 0
raise BuildFailed.new("Build script failed with non zero exit code", json)
end
rescue Excon::Error
logger.error "could not wait successfully for container #{container}, url: #{url}"
raise
end

def input_package(container)
Expand Down

0 comments on commit 8379278

Please sign in to comment.