chef-provisioning-docker
chef-provisioning-docker copied to clipboard
ERROR: machine_batch[default] (@recipe_files::/root/workdir/kafka-cluster.rb line 64) had an error: Errno::ENOENT: No such file or directory @ rb_sysopen - proc/10110/root/etc/chef/client.pem
Hi, I'm having this error when trying to run chef-provisioning-docker from within docker (which is actually quite useful to get a reproducible self-contained chef environment and allows to run multiple chef-provisioning on different drivers in parallel ).
I don't know the cause of this behaviour, all that I know is that write_file method in
/lib/chef/provisioning/docker_driver/docker_transport.rb
determins the pem path from container_path()
method, which in turn, does:
def container_path(path)
File.join('proc', container.info['State']['Pid'].to_s, 'root', path)
end
My quick and dirty bypass is to force the containing directory creation:
def write_file(path, content)
require "file_utils"
mkdir_p File.dirname(container_path(path))
File.open(container_path(path), 'w') { |file| file.write(content) }
end
I'm guessing that the fact that I'm in a container changes the way the driver behaves, what do you think ? If you think this bypass is acceptable, I can submit a PR.
This won't work. First, chef-provisioning is not designed to run under docker.
Second, problem in your scenario is that CPD tries to copy files directly into newly created container fs bypassing standard docker approach for this (Dockerfile+ADD, or download files from remote location). So creating directory just makes no sense.
From my perspective, write_file
must be reimplemented by downloading files from host system via http. This also supposed to work in your case.
You also can try older version of CPD prior to 07753c4520d3364124dbdca434cd102e471b8bb4, which has different implementation of write_file
.
I was also thinking about mounting /proc
directory to your CPD container. Unfortunately it will be direct mapping -v /proc:/proc
, which doesn't seem a good idea. You can try to parametrize File.join('proc',
and mount it some where else.
Thanks marc-,
Does chef provide a library to do the http transfer - if so what is it, or would it be necessary to write it from scratch ?
No, it doesn't. You can probably start from looking at lib/chef/provisioning/docker_driver/chef_zero_http_proxy.rb
.
Here is a first "stupid" (not using HTTP) implementation using netcat on the destination:
def write_file(path, content)
server = Socket.new(:INET, :STREAM, 0)
ip = Socket.ip_address_list.detect{|intf| intf.ipv4_private?}
ip = ip.ip_address if ip
server.bind(Addrinfo.tcp(ip, 0))
port = server.local_address.ip_port
server.close
server = TCPServer.new(port)
Thread.new do
client = server.accept
client.print content
client.flush
client.close
end
execute "mkdir -p #{File.dirname path}"
res = 1
while res != 0
res = execute("sh -c 'nc -v -q1 #{ip} #{port} > #{path} 2>/tmp/nc_error'").exitstatus
end
Chef::Log.debug("write_file server.close")
server.close
end
def upload_file(local_path, path)
write_file(path, File.read(local_path))
end
LGTM. You need to replace nc with ruby code and make a PR. And BTW, it shouldn't be necessary http, plain sockets are fine too. Though, it would be nice to have some secure transport between node where you run chef and node with container (in case docker service is run remotely). We use write file to deliver certificates.
I opened PR #67