How to move/copy files locally with Chef
Chef InfraChef Infra Problem Overview
I haven't yet come across a Chef resource that will copy/move files locally. For example, I want to download jetty hightide and unzip it. Once done, copy all the files into a particular folder, like this:
# mv /var/tmp/jetty-hightide-7.4.5.v20110725/* /opt/jetty/
BTW, jettyhightide when unzipped, gives you a folder and inside that folder rest of the files are located. Hence unzip jetty-hightide-7.4.5.v20110725.zip -d /opt/jetty/
is useless because it will create a directory /opt/jetty/jetty-hightide-7.4.5.v20110725/*
whereas what I really want is /opt/jetty/*
. Hence I am looking for a local copy/move resource in Chef.
Chef Infra Solutions
Solution 1 - Chef Infra
How to copy single file
First way
I use file
statement to copy file (compile-time check)
file "/etc/init.d/someService" do
owner 'root'
group 'root'
mode 0755
content ::File.open("/home/someService").read
action :create
end
here :
"/etc/init.d/someService"
- target file,"/home/someService"
- source file
Also you can wrap ::File.open("/home/someService").read
in lazy
block
...
lazy { ::File.open("/home/someService").read }
...
Second way
User remote_file
statement (run-time check)
remote_file "Copy service file" do
path "/etc/init.d/someService"
source "file:///home/someService"
owner 'root'
group 'root'
mode 0755
end
Third way
Also you can use shell/batch
For-each directory
Dir[ "/some/directory/resources/**/*" ].each do |curr_path|
file "/some/target/dir/#{Pathname.new(curr_path).basename}" do
owner 'root'
group 'root'
mode 0755
content lazy { IO.read(curr_path, mode: 'rb').read }
action :create
end if File.file?(curr_path)
directory "/some/target/dir/#{File.dirname(curr_path)}" do
path curr_path
owner 'root'
group 'root'
mode 0755
action :create
end if File.directory?(curr_path)
end
This is just idea, because sub-paths in this example is not handled correctly.
Solution 2 - Chef Infra
I got it working by using bash
resource as below:
bash "install_jettyhightide" do
code <<-EOL
unzip /var/tmp/jetty-hightide-7.4.5.v20110725.zip -d /opt/jetty/
mv /opt/jetty/jetty-hightide-7.4.5.v20110725/* /opt/jetty/
cp /opt/jetty/bin/jetty.sh /etc/init.d/jetty
update-rc.d jetty defaults
EOL
end
But I was really hoping for a chef way of doing it. copying/moving files locally would be the most generic task a sysadmin will need to do.
Solution 3 - Chef Infra
I know this question have already been answered, and discussed, but here is the method I use when creating files.
- First include the file under the cookbook's files/default folder
- Then on your recipe use the
cookbook_file
resource
e.g:
cookbook_file "/server/path/to/file.ext" do
source "filename.ext"
owner "root"
group "root"
mode 00600
action :create_if_missing
end
From chef documentation: https://docs.chef.io/resources/cookbook_file/
> The cookbook_file resource is used to transfer files from a > sub-directory of the files/ directory in a cookbook to a specified > path that is located on the host running the chef-client or chef-solo.
Solution 4 - Chef Infra
You could give the ark cookbook a try. This extracts the file for you and you afterwards notice an execute
resource.
Solution 5 - Chef Infra
Besides the way you've done it and accepted it, if you only wanted to run one command like you initially asked (copy or move), and not run a block of commands, then you could do it with the [execute][1] resource:
execute "copy_core" do
command "mv /var/tmp/jetty-hightide-7.4.5.v20110725 /opt/jetty"
user "root"
end
Maybe this will help someone else looking at this in the future. [1]: https://docs.chef.io/resource_execute.html
Solution 6 - Chef Infra
I would actually use something like the following (notice "binread") as this would work for text files and binary files. using "read" would yield surprising results with binary files particularly if you use both unix and windows systems.
file destination do
content IO.binread(source)
action :create
end
Solution 7 - Chef Infra
If your recipe is already tied to Windows, you can use embedded PowerShell scripts, like this:
# Copy files from "C:/foo/lib" to "C:/foo"
powershell_script "copy_lib" do
code <<-EOH
$ErrorActionPreference = "Stop"
Get-ChildItem -Path "C:/foo/lib" -File | Foreach-Object {
Copy-Item -Path $_.Fullname -Destination "C:/foo" -Force
}
EOH
end
# Delete "C:/foo/lib" folder
powershell_script "delete_lib" do
code <<-EOH
$ErrorActionPreference = "Stop"
Remove-Item -Path "C:/foo/lib" -Recurse
EOH
end
Solution 8 - Chef Infra
To Copy files locally in CHEF
file "C:/Users/Administrator/chef/1.xml"
do ---> tar content lazy
{
IO.read("C:/Users/Administrator/chef-repo/cookbooks/2.xml")
} -->src
action :create
end