chef/cookbooks/cpe_workspaceone/libraries/hubcli.rb (90 lines of code) (raw):
#
# Cookbook:: cpe_workspaceone
# Library:: hubcli
#
# 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.
#
class Chef
class Node
# Only the top level device_attributes object is memoized as we won't actually call
# anything if it been called previously in the chef run.
def ws1_device_attributes
@ws1_device_attributes ||= get_ws1_device_attributes
end
def get_ws1_device_attributes
unless macos?
Chef::Log.warn('node.ws1_device_attributes called on non-macOS!')
return {}
end
# Bail if device is not enrolled into mdm
return {} unless node.profile_installed?('ProfileDisplayName', 'Device Manager')
# Bail if hubcli doesn't exist
return {} unless ws1_hubcli_exists
# If for some reason an admin doesn't want to use the cache, always return the json from WS1
ws1_use_cache = node['cpe_workspaceone']['use_cache']
return _get_available_ws1_profiles_list unless ws1_use_cache
# Setup cache file
ws1_cache_file_path = ::File.join(Chef::Config[:file_cache_path], 'cpe_workspaceone-device_attributes.json')
ws1_cache_exists = ::File.exist?(ws1_cache_file_path)
ws1_cache_old = ws1_json_age_over_invalidation?(ws1_cache_file_path)
# Cache exists and is fresh - utilize cache
if ws1_cache_exists && !ws1_cache_old
parsed_ws1_json = node.parse_json(ws1_cache_file_path)
# Check the OS version of the json contents vs current version. If the current OS is greater than the
# last checked OS version (Example, upgrading from 10.14 to 10.15 in between two hour chef cache), reject
# the current cache and check again, so we can look for newly available profiles.
if node.greater_than?(node['platform_version'], parsed_ws1_json['os_version'])
ws1_device_attributes = _get_available_ws1_profiles_list
else
return parsed_ws1_json
end
# Cache either doesn't exist or isn't fresh
else
# Trigger a sync to kickstart WS1 agent
_trigger_sync
ws1_device_attributes = _get_available_ws1_profiles_list
end
# Only write the attributes if they come back in a good, clean state
unless ws1_device_attributes.empty?
node.write_contents_to_file(ws1_cache_file_path, Chef::JSONCompat.to_json_pretty(ws1_device_attributes))
end
ws1_device_attributes
rescue Exception => e # rubocop:disable Lint/RescueException
Chef::Log.warn("Failed to get workspace one device attributes with error #{e}")
{}
end
def ws1_hubcli_exists
@ws1_hubcli_exists ||= ::File.exists?(hubcli_path)
end
def hubcli_path
return 'hubcli' if node['cpe_workspaceone']['hubcli_path'].nil?
node['cpe_workspaceone']['hubcli_path']
end
def hubcli_cmd(cmd)
"#{hubcli_path.gsub(/ /, '\ ')} #{cmd.strip}"
end
def hubcli_execute(cmd)
unless ws1_hubcli_exists
Chef::Log.warn('Tried to execute hubcli, hubcli does not exist')
end
# hash rockets trigger a deprecation command and an argument error
shell_out(hubcli_cmd(cmd), timeout: node['cpe_workspaceone']['hubcli_timeout']) # rubocop:disable Style/HashSyntax
end
def _get_available_ws1_profiles_list
attributes = {}
if macos?
cmd = hubcli_execute(
'profiles --list --json',
)
end
if cmd.exitstatus.zero?
if macos?
attributes = Chef::JSONCompat.parse(cmd.stdout.to_s)
end
else
return attributes
end
# Bail if the attributes are empty
return {} if attributes.empty?
# add the OS version so we can do intelligent actions
if macos?
attributes['os_version'] = node['platform_version']
end
attributes
end
def _trigger_sync
if macos?
hubcli_execute('sync')
end
end
def ws1_json_age_over_invalidation?(path_of_file)
@ws1_json_age_over_invalidation ||=
begin
age_length = false
if ::File.exist?(path_of_file)
diff_time = (Time.now - File.mtime(path_of_file)).to_i
age_length = diff_time > node['cpe_workspaceone']['cache_invalidation']
end
age_length
end
end
end
end