class ChefCLI::PolicyfileServices::ExportRepo
Attributes
export_dir[R]
policy_group[R]
root_dir[R]
storage_config[R]
ui[R]
Public Class Methods
new(policyfile: nil, export_dir: nil, root_dir: nil, archive: false, force: false, policy_group: nil)
click to toggle source
# File lib/chef-cli/policyfile_services/export_repo.rb, line 44 def initialize(policyfile: nil, export_dir: nil, root_dir: nil, archive: false, force: false, policy_group: nil) @root_dir = root_dir @export_dir = File.expand_path(export_dir) @archive = archive @force_export = force @ui = UI.new @policy_data = nil @policyfile_lock = nil @policy_group = policy_group @policy_group ||= "local".freeze policyfile_rel_path = policyfile || "Policyfile.rb" policyfile_full_path = File.expand_path(policyfile_rel_path, root_dir) @storage_config = Policyfile::StorageConfig.new.use_policyfile(policyfile_full_path) @staging_dir = nil end
Public Instance Methods
archive?()
click to toggle source
# File lib/chef-cli/policyfile_services/export_repo.rb, line 63 def archive? @archive end
archive_file_location()
click to toggle source
# File lib/chef-cli/policyfile_services/export_repo.rb, line 90 def archive_file_location return nil unless archive? filename = "#{policyfile_lock.name}-#{policyfile_lock.revision_id}.tgz" File.join(export_dir, filename) end
export()
click to toggle source
# File lib/chef-cli/policyfile_services/export_repo.rb, line 97 def export with_staging_dir do create_repo_structure copy_cookbooks create_policyfile_repo_item create_policy_group_repo_item copy_policyfile_lock create_client_rb create_readme_md if archive? create_archive else mv_staged_repo end end rescue => error msg = "Failed to export policy (in #{policyfile_filename}) to #{export_dir}" raise PolicyfileExportRepoError.new(msg, error) end
policy_data()
click to toggle source
# File lib/chef-cli/policyfile_services/export_repo.rb, line 80 def policy_data @policy_data ||= FFI_Yajl::Parser.parse(IO.read(policyfile_lock_expanded_path)) rescue => error raise PolicyfileExportRepoError.new("Error reading lockfile #{policyfile_lock_expanded_path}", error) end
policy_name()
click to toggle source
# File lib/chef-cli/policyfile_services/export_repo.rb, line 67 def policy_name policyfile_lock.name end
policyfile_lock()
click to toggle source
# File lib/chef-cli/policyfile_services/export_repo.rb, line 86 def policyfile_lock @policyfile_lock || validate_lockfile end
run()
click to toggle source
# File lib/chef-cli/policyfile_services/export_repo.rb, line 71 def run assert_lockfile_exists! assert_export_dir_clean! validate_lockfile write_updated_lockfile export end
Private Instance Methods
assert_export_dir_clean!()
click to toggle source
# File lib/chef-cli/policyfile_services/export_repo.rb, line 348 def assert_export_dir_clean! if !force_export? && !conflicting_fs_entries.empty? && !archive? msg = "Export dir (#{export_dir}) not clean. Refusing to export. (Conflicting files: #{conflicting_fs_entries.join(", ")})" raise ExportDirNotEmpty, msg end end
assert_lockfile_exists!()
click to toggle source
# File lib/chef-cli/policyfile_services/export_repo.rb, line 342 def assert_lockfile_exists! unless File.exist?(policyfile_lock_expanded_path) raise LockfileNotFound, "No lockfile at #{policyfile_lock_expanded_path} - you need to run `install` before `push`" end end
chefignore_for(cookbook_path)
click to toggle source
# File lib/chef-cli/policyfile_services/export_repo.rb, line 202 def chefignore_for(cookbook_path) Chef::Cookbook::Chefignore.new(File.join(cookbook_path, "chefignore")) end
client_rb_staging_path()
click to toggle source
# File lib/chef-cli/policyfile_services/export_repo.rb, line 411 def client_rb_staging_path File.join(dot_chef_staging_dir, "config.rb") end
conflicting_fs_entries()
click to toggle source
# File lib/chef-cli/policyfile_services/export_repo.rb, line 359 def conflicting_fs_entries Dir.glob(File.join(cookbook_artifacts_dir, "*")) + Dir.glob(File.join(policies_dir, "*")) + Dir.glob(File.join(policy_groups_dir, "*")) + Dir.glob(File.join(export_dir, "Policyfile.lock.json")) end
cookbook_artifacts_dir()
click to toggle source
# File lib/chef-cli/policyfile_services/export_repo.rb, line 366 def cookbook_artifacts_dir File.join(export_dir, "cookbook_artifacts") end
cookbook_artifacts_staging_dir()
click to toggle source
# File lib/chef-cli/policyfile_services/export_repo.rb, line 395 def cookbook_artifacts_staging_dir File.join(staging_dir, "cookbook_artifacts") end
cookbook_files_to_copy(cookbook_path)
click to toggle source
# File lib/chef-cli/policyfile_services/export_repo.rb, line 186 def cookbook_files_to_copy(cookbook_path) cookbook = cookbook_loader_for(cookbook_path).cookbook_version root = Pathname.new(cookbook.root_dir) cookbook.all_files.map do |full_path| Pathname.new(full_path).relative_path_from(root).to_s end end
cookbook_loader_for(cookbook_path)
click to toggle source
# File lib/chef-cli/policyfile_services/export_repo.rb, line 196 def cookbook_loader_for(cookbook_path) loader = Chef::Cookbook::CookbookVersionLoader.new(cookbook_path, chefignore_for(cookbook_path)) loader.load! loader end
copy_cookbook(lock)
click to toggle source
# File lib/chef-cli/policyfile_services/export_repo.rb, line 157 def copy_cookbook(lock) dirname = "#{lock.name}-#{lock.identifier}" export_path = File.join(staging_dir, "cookbook_artifacts", dirname) metadata_rb_path = File.join(export_path, "metadata.rb") FileUtils.mkdir(export_path) unless File.directory?(export_path) copy_unignored_cookbook_files(lock, export_path) FileUtils.rm_f(metadata_rb_path) if lock.cookbook_version.nil? ui.msg "Unable to get the cookbook version/metadata for #{lock}" end metadata = lock.cookbook_version.metadata metadata_json_path = File.join(export_path, "metadata.json") File.open(metadata_json_path, "wb+") do |f| f.print(FFI_Yajl::Encoder.encode(metadata.to_hash, pretty: true )) end end
copy_cookbooks()
click to toggle source
# File lib/chef-cli/policyfile_services/export_repo.rb, line 151 def copy_cookbooks policyfile_lock.cookbook_locks.each do |name, lock| copy_cookbook(lock) end end
copy_policyfile_lock()
click to toggle source
# File lib/chef-cli/policyfile_services/export_repo.rb, line 226 def copy_policyfile_lock File.open(lockfile_staging_path, "wb+") do |f| f.print(FFI_Yajl::Encoder.encode(policyfile_lock.to_lock, pretty: true )) end end
copy_unignored_cookbook_files(lock, export_path)
click to toggle source
# File lib/chef-cli/policyfile_services/export_repo.rb, line 176 def copy_unignored_cookbook_files(lock, export_path) cookbook_files_to_copy(lock.cookbook_path).each do |rel_path| full_source_path = File.join(lock.cookbook_path, rel_path) full_dest_path = File.join(export_path, rel_path) dest_dirname = File.dirname(full_dest_path) FileUtils.mkdir_p(dest_dirname) unless File.directory?(dest_dirname) FileUtils.cp(full_source_path, full_dest_path) end end
create_archive()
click to toggle source
# File lib/chef-cli/policyfile_services/export_repo.rb, line 132 def create_archive Dir.chdir(staging_dir) do targets = Find.find(".").collect { |e| e } Mixlib::Archive.new(archive_file_location).create(targets, gzip: true) end end
create_client_rb()
click to toggle source
# File lib/chef-cli/policyfile_services/export_repo.rb, line 232 def create_client_rb File.open(client_rb_staging_path, "wb+") do |f| f.print( <<~CONFIG ) ### Chef Infra Client Configuration ### # The settings in this file will configure chef to apply the exported policy in # this directory. To use it, run: # # chef-client -z # policy_name '#{policy_name}' policy_group '#{policy_group}' use_policyfile true policy_document_native_api true # In order to use this repo, you need a version of Chef Infra Client and Chef Zero # that supports policyfile "native mode" APIs: current_version = Gem::Version.new(Chef::VERSION) unless Gem::Requirement.new(">= 12.7").satisfied_by?(current_version) puts("!" * 80) puts(<<-MESSAGE) This Chef Repo requires features introduced in Chef Infra Client 12.7, but you are using Chef \#{Chef::VERSION}. Please upgrade to Chef Infra Client 12.7 or later. MESSAGE puts("!" * 80) exit!(1) end CONFIG end end
create_policy_group_repo_item()
click to toggle source
# File lib/chef-cli/policyfile_services/export_repo.rb, line 212 def create_policy_group_repo_item data = { "policies" => { policyfile_lock.name => { "revision_id" => policyfile_lock.revision_id, }, }, } File.open(policy_group_repo_item_path, "wb+") do |f| f.print(FFI_Yajl::Encoder.encode(data, pretty: true )) end end
create_policyfile_repo_item()
click to toggle source
# File lib/chef-cli/policyfile_services/export_repo.rb, line 206 def create_policyfile_repo_item File.open(policyfile_repo_item_path, "wb+") do |f| f.print(FFI_Yajl::Encoder.encode(policyfile_lock.to_lock, pretty: true )) end end
create_readme_md()
click to toggle source
# File lib/chef-cli/policyfile_services/export_repo.rb, line 265 def create_readme_md File.open(readme_staging_path, "wb+") do |f| f.print( <<~README ) # Exported Chef Infra Repository for Policy '#{policy_name}' Policy revision: #{policyfile_lock.revision_id} This directory contains all the cookbooks and configuration necessary for Chef to converge a system using this exported policy. To converge a system with the exported policy, use a privileged account to run `chef-client -z` from the directory containing the exported policy. ## Contents: ### Policyfile.lock.json A copy of the exported policy, used by the `chef push-archive` command. ### .chef/config.rb A configuration file for Chef Infra Client. This file configures Chef Infra Client to use the correct `policy_name` and `policy_group` for this exported repository. Chef Infra Client will use this configuration automatically if you've set your working directory properly. ### cookbook_artifacts/ All of the cookbooks required by the policy will be stored in this directory. ### policies/ A different copy of the exported policy, used by the `chef-client` command. ### policy_groups/ Policy groups are used by Chef Infra Server to manage multiple revisions of the same policy. The default "local" policy is recommended for export use since there can be no different revisions when not utilizing a server. README end end
create_repo_structure()
click to toggle source
# File lib/chef-cli/policyfile_services/export_repo.rb, line 143 def create_repo_structure FileUtils.mkdir_p(export_dir) FileUtils.mkdir_p(dot_chef_staging_dir) FileUtils.mkdir_p(cookbook_artifacts_staging_dir) FileUtils.mkdir_p(policies_staging_dir) FileUtils.mkdir_p(policy_groups_staging_dir) end
dot_chef_dir()
click to toggle source
# File lib/chef-cli/policyfile_services/export_repo.rb, line 378 def dot_chef_dir File.join(export_dir, ".chef") end
dot_chef_staging_dir()
click to toggle source
# File lib/chef-cli/policyfile_services/export_repo.rb, line 391 def dot_chef_staging_dir File.join(staging_dir, ".chef") end
force_export?()
click to toggle source
# File lib/chef-cli/policyfile_services/export_repo.rb, line 355 def force_export? @force_export end
lockfile_staging_path()
click to toggle source
# File lib/chef-cli/policyfile_services/export_repo.rb, line 407 def lockfile_staging_path File.join(staging_dir, "Policyfile.lock.json") end
mv_staged_repo()
click to toggle source
# File lib/chef-cli/policyfile_services/export_repo.rb, line 307 def mv_staged_repo # If we got here, either these dirs are empty/don't exist or force is # set to true. FileUtils.rm_rf(cookbook_artifacts_dir) FileUtils.rm_rf(policies_dir) FileUtils.rm_rf(policy_groups_dir) FileUtils.rm_rf(dot_chef_dir) FileUtils.mv(cookbook_artifacts_staging_dir, export_dir) FileUtils.mv(policies_staging_dir, export_dir) FileUtils.mv(policy_groups_staging_dir, export_dir) FileUtils.mv(lockfile_staging_path, export_dir) FileUtils.mv(dot_chef_staging_dir, export_dir) FileUtils.mv(readme_staging_path, export_dir) end
policies_dir()
click to toggle source
# File lib/chef-cli/policyfile_services/export_repo.rb, line 370 def policies_dir File.join(export_dir, "policies") end
policies_staging_dir()
click to toggle source
# File lib/chef-cli/policyfile_services/export_repo.rb, line 399 def policies_staging_dir File.join(staging_dir, "policies") end
policy_group_repo_item_path()
click to toggle source
# File lib/chef-cli/policyfile_services/export_repo.rb, line 387 def policy_group_repo_item_path File.join(staging_dir, "policy_groups", "#{policy_group}.json") end
policy_groups_dir()
click to toggle source
# File lib/chef-cli/policyfile_services/export_repo.rb, line 374 def policy_groups_dir File.join(export_dir, "policy_groups") end
policy_groups_staging_dir()
click to toggle source
# File lib/chef-cli/policyfile_services/export_repo.rb, line 403 def policy_groups_staging_dir File.join(staging_dir, "policy_groups") end
policyfile_repo_item_path()
click to toggle source
# File lib/chef-cli/policyfile_services/export_repo.rb, line 382 def policyfile_repo_item_path basename = "#{policyfile_lock.name}-#{policyfile_lock.revision_id}" File.join(staging_dir, "policies", "#{basename}.json") end
readme_staging_path()
click to toggle source
# File lib/chef-cli/policyfile_services/export_repo.rb, line 415 def readme_staging_path File.join(staging_dir, "README.md") end
staging_dir()
click to toggle source
# File lib/chef-cli/policyfile_services/export_repo.rb, line 139 def staging_dir @staging_dir end
validate_lockfile()
click to toggle source
# File lib/chef-cli/policyfile_services/export_repo.rb, line 323 def validate_lockfile return @policyfile_lock if @policyfile_lock @policyfile_lock = ChefCLI::PolicyfileLock.new(storage_config).build_from_lock_data(policy_data) # TODO: enumerate any cookbook that have been updated @policyfile_lock.validate_cookbooks! @policyfile_lock rescue PolicyfileExportRepoError raise rescue => error raise PolicyfileExportRepoError.new("Invalid lockfile data", error) end
with_staging_dir() { || ... }
click to toggle source
# File lib/chef-cli/policyfile_services/export_repo.rb, line 119 def with_staging_dir p = Process.pid t = Time.new.utc.strftime("%Y%m%d%H%M%S") Dir.mktmpdir("chefcli-export-#{p}-#{t}") do |d| begin @staging_dir = d yield ensure @staging_dir = nil end end end
write_updated_lockfile()
click to toggle source
# File lib/chef-cli/policyfile_services/export_repo.rb, line 336 def write_updated_lockfile File.open(policyfile_lock_expanded_path, "wb+") do |f| f.print(FFI_Yajl::Encoder.encode(policyfile_lock.to_lock, pretty: true )) end end