chef/legacy/cpe_sal/resources/cpe_sal.rb (195 lines of code) (raw):
#
# Cookbook:: cpe_sal
# Resources:: cpe_sal
#
# vim: syntax=ruby:expandtab:shiftwidth=2:softtabstop=2:tabstop=2
#
# Copyright:: (c) 2019-present, Uber Technologies, Inc.
# All rights reserved.
#
# This source code is licensed under the Apache 2.0 license found in the
# LICENSE file in the root directory of this source tree.
#
unified_mode true
resource_name :cpe_sal
provides :cpe_sal, :os => ['darwin', 'windows']
default_action :manage
action :manage do
install
configure
manage_plugins
cleanup
end
action_class do # rubocop:disable Metrics/BlockLength
def create_sal_folder(dir)
# Create Sal folder
if windows?
directory dir do
action :create
group node['root_group']
owner root_owner
end
end
end
def install
return unless node['cpe_sal']['install']
# Get info about the sal_scripts pkg, rejecting unset values
pkg_info = node['cpe_sal']['scripts_pkg'].compact
if pkg_info.empty? || pkg_info.nil?
Chef::Log.warn('scripts_pkg is not populated, skipping pkg install')
return
end
macos_install(pkg_info) if macos?
windows_install(pkg_info) if windows?
end
def macos_install(pkg_info)
# Install sal_scripts.pkg
cpe_remote_pkg pkg_info['name'] do
checksum pkg_info['checksum']
pkg_url pkg_info['pkg_url'] if pkg_info['pkg_url']
pkg_name pkg_info['pkg_name'] if pkg_info['pkg_name']
receipt pkg_info['receipt']
version pkg_info['version']
end
end
def windows_install(pkg_info)
# Bail if directory isn't set
gosal_dir = node['cpe_sal']['gosal_dir']
if gosal_dir.empty? || gosal_dir.nil?
Chef::Log.warn('gosal dir is not populated, skipping configuration')
return
end
# Ensure the folder exists and is properly managed
create_sal_folder(gosal_dir)
# Save gosal in your pkg repo as: pkgrepo/name/gosal-version.exe
gosal_exe = ::File.join(gosal_dir, 'gosal.exe')
# Defining owner/group properties here causes this to be non-idempotent
cpe_remote_file pkg_info['name'] do
checksum pkg_info['checksum']
file_name "#{pkg_info['name']}-#{pkg_info['version']}.exe"
mode '0644'
path gosal_exe
end
end
def configure
return unless node['cpe_sal']['configure']
# Get info about sal config, rejecting unset values
sal_prefs = node['cpe_sal']['config'].compact
if sal_prefs.empty? || sal_prefs.nil?
Chef::Log.warn('config is not populated, skipping configuration')
return
end
macos_configure(sal_prefs) if macos?
windows_configure(sal_prefs) if windows?
end
def macos_configure(sal_prefs)
# Build configuration profile and pass it to cpe_profiles
prefix = node['cpe_profiles']['prefix']
organization = node['organization'] ? node['organization'] : 'Uber' # rubocop:disable Style/UnneededCondition
if node.os_at_least_or_lower?('10.15.99')
sal_profile = {
'PayloadIdentifier' => "#{prefix}.sal",
'PayloadRemovalDisallowed' => true,
'PayloadScope' => 'System',
'PayloadType' => 'Configuration',
'PayloadUUID' => '1c03dd17-d2d7-4a68-be40-f41bea3642a9',
'PayloadOrganization' => organization,
'PayloadVersion' => 1,
'PayloadDisplayName' => 'Sal',
'PayloadContent' => [],
}
sal_profile['PayloadContent'].push(
'PayloadType' => 'com.github.salopensource.sal',
'PayloadVersion' => 1,
'PayloadIdentifier' => "#{prefix}.sal",
'PayloadUUID' => 'e33adee2-4a19-4e69-a330-461920ec8279',
'PayloadEnabled' => true,
'PayloadDisplayName' => 'Sal',
)
sal_prefs.each do |k, v|
sal_profile['PayloadContent'][0][k] = v
end
node.default['cpe_profiles']["#{prefix}.sal"] = sal_profile
else
# Profiles are dead on macOS Big sur and later, so use defaults write
sal_prefs.each_key do |key|
next if sal_prefs[key].nil?
if node.at_least_chef14?
macos_userdefaults "Configure Sal - #{key}" do
domain '/Library/Preferences/com.github.salopensource.sal'
key key
value sal_prefs[key]
end
end
end
end
# Make sure the launchds are always loaded if present
CPE::Sal.launchds.each do |d|
launchd d do
action :enable
only_if { ::File.exist?("/Library/LaunchDaemons/#{d}.plist") }
end
end
end
def windows_configure(sal_prefs)
# Bail if directory isn't set
gosal_dir = node['cpe_sal']['gosal_dir']
if gosal_dir.empty? || gosal_dir.nil?
Chef::Log.warn('gosal dir is not populated, skipping configuration')
return
end
# Ensure the folder exists and is properly managed
create_sal_folder(gosal_dir)
# Install JSON configuration file
config_json = ::File.join(gosal_dir, 'config.json')
sal_json_prefs = {
'key' => sal_prefs['key'],
'management' => sal_prefs['management'],
'url' => sal_prefs['ServerURL'],
}
file config_json do
content Chef::JSONCompat.to_json_pretty(sal_json_prefs)
group node['root_group']
owner root_owner
end
# Create a scheduled task to run gosal / use template for splay and stop
# relying on Chef's built in portions for this as it's buggy.
gosal_ps1 = ::File.join(gosal_dir, 'gosal_task_splay.ps1')
template 'gosal splay powershell script' do
path gosal_ps1
source 'gosal_task_splay.erb'
end
ps_cmd = 'C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe ' \
"-NoProfile -ExecutionPolicy Bypass \"#{gosal_ps1}\""
windows_task node['cpe_sal']['scripts_pkg']['name'] do
command ps_cmd
frequency :minute
frequency_modifier node['cpe_sal']['task']['minutes_per_run']
run_level :highest
end
end
def manage_plugins
return unless node['cpe_sal']['manage_plugins']
macos_plugins if macos?
end
def macos_plugins
# Get plugins dir from cpe_sal library
plugins_dir = CPE::Sal.plugins_dir
plugins = node['cpe_sal']['plugins'].compact
if plugins.empty? && plugins.empty?
Chef::Log.warn('plugins is not populated, skipping plugins install')
return
end
plugins.each do |name, script|
directory "#{plugins_dir}/#{name}_chef" do
group node['root_group']
mode '0755'
owner root_owner
end
cookbook_file "#{plugins_dir}/#{name}_chef/#{script}" do
group node['root_group']
mode '0750'
owner root_owner
source script
end
end
end
def cleanup
macos_cleanup if macos?
end
def macos_cleanup
# Get plugins dir and currently installed plugins list from cpe_sal library
plugins_dir = CPE::Sal.plugins_dir
if ::File.exist?(plugins_dir)
existing_plugins = CPE::Sal.existing_plugins
plugins = node['cpe_sal']['plugins'].compact
# If plugin directory exists on disk, but isn't managed, remove it.
existing_plugins.each do |plugin|
existing_plugin = plugin.split('_')[0]
unless plugins.key?(existing_plugin)
directory "#{plugins_dir}/#{existing_plugin}_chef" do
action :delete
recursive true
end
end
end
end
unless node['cpe_sal']['configure']
CPE::Sal.launchds.each do |d|
launchd d do
action :disable
only_if { ::File.exist?("/Library/LaunchDaemons/#{d}.plist") }
end
end
end
end
end