Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cleanup docker support #257

Merged
merged 8 commits into from
Feb 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions lib/docker_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# frozen_string_literal: true

require 'json'
require 'puppet_litmus'

def docker_exec(container, command)
run_local_command("docker exec #{container} #{command}")
end

def docker_image_os_release_facts(image)
os_release_facts = {}
begin
os_release = run_local_command("docker run --rm #{image} cat /etc/os-release")
# The or-release file is a newline-separated list of environment-like
# shell-compatible variable assignments.
re = '^(.+)=(.+)'
os_release.each_line do |line|
line = line.strip || line
next if line.nil? || line.empty?

_, key, value = line.match(re).to_a
# The values seems to be quoted most of the time, however debian only quotes
# some of the values :/. Parse it, as if it was a JSON string.
value = JSON.parse(value) unless value[0] != '"'
os_release_facts[key] = value
end
rescue StandardError
# fall through to parsing the id and version from the image if it doesn't have `/etc/os-release`
id, version_id = image.split(':')
id = id.sub(%r{/}, '_')
os_release_facts['ID'] = id
os_release_facts['VERSION_ID'] = version_id
end
os_release_facts
end

def docker_tear_down(node_name, inventory_location)
extend PuppetLitmus::InventoryManipulation
inventory_full_path = File.join(inventory_location, '/spec/fixtures/litmus_inventory.yaml')
raise "Unable to find '#{inventory_full_path}'" unless File.file?(inventory_full_path)

inventory_hash = inventory_hash_from_inventory_file(inventory_full_path)
node_facts = facts_from_node(inventory_hash, node_name)
remove_docker = "docker rm -f #{node_facts['container_id']}"
run_local_command(remove_docker)
remove_node(inventory_hash, node_name)
puts "Removed #{node_name}"
File.open(inventory_full_path, 'w') { |f| f.write inventory_hash.to_yaml }
{ status: 'ok' }
end

# Workaround for fixing the bash message in stderr when tty is missing
def docker_fix_missing_tty_error_message(container_id)
system("docker exec #{container_id} sed -i 's/^mesg n/tty -s \\&\\& mesg n/g' /root/.profile")
end
5 changes: 0 additions & 5 deletions lib/task_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,3 @@ def token_from_fogfile(provider = 'abs')
rescue StandardError
puts 'Failed to get token from .fog file'
end

# Workaround for fixing the bash message in stderr when tty is missing
def fix_missing_tty_error_message(container_id)
system("docker exec #{container_id} sed -i 's/^mesg n/tty -s \\&\\& mesg n/g' /root/.profile")
end
107 changes: 107 additions & 0 deletions spec/unit/docker_helper_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# frozen_string_literal: true

require 'docker_helper'
require 'stringio'

describe 'Docker Helper Functions' do
let(:container_id) { 'abc12345' }
let(:inventory_location) { '.' }
let(:full_inventory_location) { "#{inventory_location}/spec/fixtures/litmus_inventory.yaml" }
let(:inventory_yaml) do
<<-YAML
version: 2
groups:
- name: docker_nodes
targets:
- name: #{container_id}
uri: #{container_id}
config:
transport: docker
docker:
shell-command: bash -lc
connect-timeout: 120
facts:
provisioner: docker_exp
container_id: #{container_id}
platform: litmusimage/debian:12
os-release:
PRETTY_NAME: Debian GNU/Linux 12 (bookworm)
NAME: Debian GNU/Linux
VERSION_ID: '12'
VERSION: 12 (bookworm)
VERSION_CODENAME: bookworm
ID: debian
HOME_URL: https://www.debian.org/
SUPPORT_URL: https://www.debian.org/support
BUG_REPORT_URL: https://bugs.debian.org/
- name: ssh_nodes
targets: []
- name: winrm_nodes
targets: []
- name: lxd_nodes
targets: []
YAML
end

let(:os_release_facts) do
<<-FILE
PRETTY_NAME="Debian GNU/Linux 12 (bookworm)"
NAME="Debian GNU/Linux"
VERSION_ID="12"
VERSION="12 (bookworm)"
VERSION_CODENAME=bookworm
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"
FILE
end

describe '.docker_exec' do
it 'calls run_local_command' do
allow(self).to receive(:run_local_command).with("docker exec #{container_id} a command").and_return('some output')
expect(docker_exec(container_id, 'a command')).to eq('some output')
end
end

describe '.docker_image_os_release_facts' do
it 'returns parsed hash of /etc/os-release from container' do
allow(self).to receive(:run_local_command)
.with('docker run --rm litmusimage/debian:12 cat /etc/os-release')
.and_return(os_release_facts)
expect(docker_image_os_release_facts('litmusimage/debian:12')).to match(hash_including('PRETTY_NAME' => 'Debian GNU/Linux 12 (bookworm)'))
end

it 'returns minimal facts if parse fails for any reason' do
allow(self).to receive(:run_local_command)
.with('docker run --rm litmusimage/debian:12 cat /etc/os-release')
.and_return(StandardError)
expect(docker_image_os_release_facts('litmusimage/debian:12')).to match(hash_including('ID' => 'litmusimage_debian'))
end
end

describe '.docker_tear_down' do
it 'expect to raise error if inventory file is not found' do
allow(File).to receive(:file?).and_return(false)
expect { docker_tear_down(container_id, inventory_location) }.to raise_error(RuntimeError, "Unable to find '#{inventory_location}/spec/fixtures/litmus_inventory.yaml'")
end

it 'expect to return status ok' do
allow(File).to receive(:file?).with(full_inventory_location).and_return(true)
allow(File).to receive(:exist?).with(full_inventory_location).and_return(true)
allow(File).to receive(:open).with(full_inventory_location, anything).and_yield(StringIO.new(inventory_yaml.dup))
allow(self).to receive(:run_local_command).with("docker rm -f #{container_id}")
allow(self).to receive(:remove_node).and_return(nil)
expect {
expect(docker_tear_down(container_id, inventory_location)).to eql({ status: 'ok' })
}.to output("Removed #{container_id}\n").to_stdout
end
end

describe '.docker_fix_missing_tty_error_message' do
it 'execute command on container to disable mesg' do
allow(self).to receive(:system).with("docker exec #{container_id} sed -i 's/^mesg n/tty -s \\&\\& mesg n/g' /root/.profile")
expect(docker_fix_missing_tty_error_message(container_id)).to be_nil
end
end
end
3 changes: 2 additions & 1 deletion tasks/docker.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
}
},
"files": [
"provision/lib/task_helper.rb"
"provision/lib/task_helper.rb",
"provision/lib/docker_helper.rb"
]
}
Loading
Loading