How to move/copy files locally with Chef

Chef Infra

Chef 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.

  1. First include the file under the cookbook's files/default folder
  2. 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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionslayedbyluciferView Question on Stackoverflow
Solution 1 - Chef InfraCAMOBAPView Answer on Stackoverflow
Solution 2 - Chef InfraslayedbyluciferView Answer on Stackoverflow
Solution 3 - Chef InfraMarcos AbreuView Answer on Stackoverflow
Solution 4 - Chef InfraStephenKingView Answer on Stackoverflow
Solution 5 - Chef InfraTitiView Answer on Stackoverflow
Solution 6 - Chef InfraruiView Answer on Stackoverflow
Solution 7 - Chef InfraJoelFanView Answer on Stackoverflow
Solution 8 - Chef Infrauser4627911View Answer on Stackoverflow