mirror of
https://github.com/munki/munki.git
synced 2026-02-20 22:20:56 -06:00
Relocate MunkiStatus.app and Munki-notifier.app to ../Contents/Helpers/ from ../Contents/Resources/ - Munki6dev base (#1207)
* Relocate MunkiStatus.app and Munki-notifier.app to ../Contents/Helpers/ from ../Contents/Resources/ - Updated location of munki-notifier in code/apps/Managed Software Center/Managed Software Center/Controllers/MainWindowController.swift - Added code/client/installhelper script - Amended code/tools/make_munki_mpkg.sh with new locations for munki-notifier and MunkiStatus as well as changes required to leverage `installhelper` - Amended code/tools/pkgresources/Scripts_app_usage/postinstall to leverage `installhelper` - Deleted code/tools/pkgresources/Scripts_app_usage/preinstall as the actions within should be handled now by `installhelper` - Amended code/tools/pkgresources/Scripts_launchd/postinstall to leverage `installhelper` - Amended launchd/LaunchAgents/com.googlecode.munki.munki-notifier.plist to use the new path to munki-notifier.app - Amended launchd/LaunchAgents/com.googlecode.munki.MunkiStatus.plist to use the new path to MunkiStatus.app This is a resubmission of https://github.com/munki/munki/pull/1203, which needed it's base branch changing from `main` to `Munki6dev` * Update installhelper - Removed CHECK_TIME global -374fbaf922 (r1515000516)- Remove erroneous login window comments -374fbaf922 (r1515006835)and374fbaf922 (r1515006962)- Simplified IF condition -374fbaf922 (r1515005565)this was in place incase LimitLoadToSessionType contained multiple values (as it can). * Update installhelper - Reverted changes made for -374fbaf922 (r1515005565)- Changed constant/global PASSED_ARG to local: launchd_group - https://github.com/munki/munki/pull/1207#discussion_r1515002646 and https://github.com/munki/munki/pull/1207#discussion_r1515002968 * Update installhelper * Update installhelper * Update installhelper * Update installhelper * Update make_munki_mpkg.sh Amended so that the launchd pkg is installed by default
This commit is contained in:
@@ -961,8 +961,8 @@ class MainWindowController: NSWindowController, NSWindowDelegate, WKNavigationDe
|
||||
// we can't remove them directly since we didn't actually post them
|
||||
// so we can't use
|
||||
// NSUserNotificationCenter.default.removeAllDeliveredNotifications()
|
||||
let munkiNotifierPath = Bundle.main.path(forResource: "munki-notifier", ofType: "app")
|
||||
if let munkiNotifierPath = munkiNotifierPath {
|
||||
let munkiNotifierPath = Bundle.main.bundlePath + "/Contents/Helpers/munki-notifier.app"
|
||||
if FileManager.default.fileExists(atPath: munkiNotifierPath) {
|
||||
NSLog("munki-notifier path: %@", munkiNotifierPath as String)
|
||||
// now make sure it's not already running
|
||||
let executablePath = munkiNotifierPath + "/Contents/MacOS/munki-notifier"
|
||||
|
||||
484
code/client/installhelper
Executable file
484
code/client/installhelper
Executable file
@@ -0,0 +1,484 @@
|
||||
#!/usr/local/munki/munki-python
|
||||
# encoding: utf-8
|
||||
#
|
||||
# Copyright 2011-2024 Greg Neagle.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""
|
||||
installhelper
|
||||
|
||||
Created 2024-02-28.
|
||||
|
||||
A helper tool for handling launchd items when installing Munki
|
||||
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
|
||||
# standard libs
|
||||
import glob
|
||||
import os
|
||||
import logging
|
||||
import logging.handlers
|
||||
import re
|
||||
import subprocess
|
||||
import time
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
# Append munki's path, to load our libs when not running under munki
|
||||
# pylint: disable = C0413
|
||||
sys.path.append('/usr/local/munki')
|
||||
|
||||
# our libs
|
||||
from munkilib import osutils
|
||||
from munkilib import prefs
|
||||
from munkilib import FoundationPlist
|
||||
|
||||
# globals
|
||||
LAUNCHD_PREFIX = 'com.googlecode.munki.'
|
||||
APPUSAGE_AGENT = LAUNCHD_PREFIX + 'app_usage_monitor'
|
||||
APPUSAGE_DAEMON = LAUNCHD_PREFIX + 'appusaged'
|
||||
INSTALL_HELPER = LAUNCHD_PREFIX + 'installhelper'
|
||||
PROG_NAME = 'managedsoftwareupdate'
|
||||
APP_NAME = 'installhelper'
|
||||
APP_VERSION = '0.1'
|
||||
|
||||
|
||||
def main():
|
||||
'''Main function'''
|
||||
|
||||
# If INSTALLHELPER_RUN_TYPE isn't set
|
||||
if not os.environ.get('INSTALLHELPER_RUN_TYPE'):
|
||||
# Set launchd_group to the first value passed
|
||||
launchd_group = sys.argv[1].lower()
|
||||
# If INSTALLHELPER_RUN_TYPE is set and we have a valid value passed
|
||||
elif (os.environ.get('INSTALLHELPER_RUN_TYPE') == 'appusage' or
|
||||
os.environ.get('INSTALLHELPER_RUN_TYPE') == 'launchd'):
|
||||
# Set launchd_group to the value of INSTALLHELPER_RUN_TYPE
|
||||
launchd_group = os.environ.get('INSTALLHELPER_RUN_TYPE')
|
||||
# If we've got here, something isn't right
|
||||
else:
|
||||
# Error message
|
||||
logging.info("ERROR: Cannot ascertain correct value for passed argument")
|
||||
# Exit
|
||||
sys.exit(1)
|
||||
|
||||
# Setup logging
|
||||
setup_logging()
|
||||
|
||||
# If not launched via launchd
|
||||
if not os.environ.get('INSTALLHELPER_RUN_TYPE'):
|
||||
# Launched manually
|
||||
logging.info("Launched manually - arg: %s", launchd_group)
|
||||
create_launch_daemon(launchd_group)
|
||||
# If launched via launchd
|
||||
else:
|
||||
# Launched via launchd
|
||||
logging.info("Launched via launchd - arg: %s", launchd_group)
|
||||
process_munki_launchd(launchd_group)
|
||||
|
||||
|
||||
def create_launch_daemon(launchd_group):
|
||||
'''Creates and loads the launch daemon'''
|
||||
|
||||
# Set name and path based on the value of launchd_group
|
||||
launch_daemon_name = 'com.googlecode.munki.installhelper-' + launchd_group
|
||||
launch_daemon_path = '/Library/LaunchDaemons/' + launch_daemon_name + '.plist'
|
||||
|
||||
# Progress notification
|
||||
logging.info("Creating launch daemon")
|
||||
|
||||
# Retrieve all running launch daemons
|
||||
cmd = ['/bin/launchctl', 'list']
|
||||
cmd_out = subprocess.run(cmd, capture_output = True, check = False)
|
||||
launchd_labels = split_launchctl_list(cmd_out)
|
||||
|
||||
# Check to see if launch_daemon_name is already loaded, and stop if so
|
||||
if launch_daemon_name in launchd_labels:
|
||||
# Stop the launch daemon at the login window
|
||||
cmd = ['/bin/launchctl', 'bootout', 'system/' + launch_daemon_name]
|
||||
subprocess.call(cmd)
|
||||
|
||||
# Populate launch deamon dict
|
||||
launch_daemon = {}
|
||||
launch_daemon['EnvironmentVariables'] = {'INSTALLHELPER_RUN_TYPE': launchd_group}
|
||||
launch_daemon['Label'] = launch_daemon_name
|
||||
launch_daemon['ProgramArguments'] = ['/usr/local/munki/installhelper']
|
||||
launch_daemon['RunAtLoad'] = True
|
||||
|
||||
# Create the launch daemon
|
||||
FoundationPlist.writePlist(launch_daemon, launch_daemon_path)
|
||||
|
||||
# Set the launch daemons owner and perms
|
||||
os.chown(launch_daemon_path, 0, 0)
|
||||
os.chmod(launch_daemon_path, int('644', 8))
|
||||
|
||||
# Load the launch daemon
|
||||
logging.info("Starting: %s", launch_daemon_path)
|
||||
cmd = ['/bin/launchctl', 'bootstrap', 'system', launch_daemon_path]
|
||||
subprocess.call(cmd)
|
||||
|
||||
|
||||
def get_logged_in_users():
|
||||
'''Returns a dict containing any logged in users uid and username'''
|
||||
|
||||
# Var declaration
|
||||
user_details = {}
|
||||
|
||||
# Retrieve details of all running processes
|
||||
cmd = ['/bin/ps', '-axo', 'uid,login,args']
|
||||
cmd_out = subprocess.run(cmd, capture_output = True, check = False)
|
||||
# Split out the above output
|
||||
for some_process in cmd_out.stdout.decode().splitlines():
|
||||
# Retrieve details for users that are running loginwindow.app, excluding root
|
||||
if "loginwindow.app" in some_process.lower() and some_process.split()[0] != "0":
|
||||
# Capture the userid and username for all users running the loginwindow
|
||||
user_details[some_process.split()[0]] = some_process.split()[1]
|
||||
|
||||
# Returns either an empty dict, or a dict with userid and usernames
|
||||
return user_details
|
||||
|
||||
|
||||
def is_managedsoftwareupdate_running():
|
||||
'''If managedsoftwareupdate is running, check again in x seconds'''
|
||||
|
||||
# Check to see if managedsoftwareupdate is running
|
||||
managedsoftwareupdate_pid = osutils.pythonScriptRunning(PROG_NAME)
|
||||
|
||||
# An instance of managedsoftwareupdate is running, so we need to try again later
|
||||
while managedsoftwareupdate_pid:
|
||||
logging.info("*" * 60)
|
||||
logging.info("%s is running as pid %s.", managedsoftwareupdate_pid, os.getpid())
|
||||
logging.info("checking again in 10 seconds")
|
||||
logging.info("*" * 60)
|
||||
time.sleep(10)
|
||||
|
||||
# If managedsoftwareupdate is not running.. return from function to proceed
|
||||
logging.info("%s is not running, proceeding...", (PROG_NAME))
|
||||
|
||||
|
||||
def process_launch_daemons(launch_daemons, launchd_group, loginwindow_launchds):
|
||||
'''Processes Munki's Launch Daemons'''
|
||||
|
||||
# Progress notification
|
||||
logging.info("Processing Launch Daemons")
|
||||
|
||||
# Var declaration
|
||||
matched_labels = []
|
||||
|
||||
# Retrieve all running launch daemons
|
||||
cmd = ['/bin/launchctl', 'list']
|
||||
cmd_out = subprocess.run(cmd, capture_output = True, check = False)
|
||||
launchd_labels = split_launchctl_list(cmd_out)
|
||||
|
||||
# For each plist in /Library/LaunchDaemons/ prefixed with LAUNCHD_PREFIX
|
||||
for launch_daemon in launch_daemons:
|
||||
try:
|
||||
# Make sure content is valid, before proceeding to reload
|
||||
daemon_content = FoundationPlist.readPlist(launch_daemon)
|
||||
except FoundationPlist.NSPropertyListSerializationException:
|
||||
break
|
||||
# Get the Label
|
||||
daemon_label = daemon_content.get('Label')
|
||||
# If we have a label and it's not an INSTALL_HELPER launchd item
|
||||
if daemon_label and not INSTALL_HELPER in daemon_label:
|
||||
# Check to see if the launch daemon is loaded, before stopping
|
||||
if daemon_label in launchd_labels:
|
||||
# Stop the launch daemon
|
||||
logging.info("Stopping: %s", launch_daemon)
|
||||
cmd = ['/bin/launchctl', 'bootout', 'system/' + daemon_label]
|
||||
subprocess.call(cmd)
|
||||
# Load the launch daemon
|
||||
logging.info("Starting: %s", launch_daemon)
|
||||
cmd = ['/bin/launchctl', 'bootstrap', 'system', launch_daemon]
|
||||
subprocess.call(cmd)
|
||||
# Append the launchd items label to matched_labels
|
||||
matched_labels.append(daemon_label)
|
||||
|
||||
# If we're to interact with all non-appusage launchd items
|
||||
if launchd_group == 'launchd':
|
||||
# For each label in launchd_labels
|
||||
for launchd_label in launchd_labels:
|
||||
# If we have a label, it's not in matched_labels or loginwindow_launchds,
|
||||
# and it's not an APPUSAGE_DAEMON or a INSTALL_HELPER launchd item
|
||||
if (launchd_label not in matched_labels + loginwindow_launchds + [APPUSAGE_DAEMON]
|
||||
and not launchd_label.startswith(INSTALL_HELPER)):
|
||||
# Stop the launch daemon
|
||||
logging.info("Stopping: %s", launchd_label)
|
||||
cmd = ['/bin/launchctl', 'bootout', 'system/' + launchd_label]
|
||||
subprocess.call(cmd)
|
||||
|
||||
|
||||
def process_loginwindow_launch_agents(launch_agents):
|
||||
'''Processes Munki's LoginWindow Launch Agents'''
|
||||
|
||||
# Progress notification
|
||||
logging.info("Processing LoginWindow Launch Agents")
|
||||
|
||||
# Var declaration
|
||||
loginwindow_launchds = []
|
||||
|
||||
# Get the labels for any launchd running at the LoginWindow, this will only list LoginWindow
|
||||
# launch agents when ran at the LoginWindow
|
||||
cmd = ['/bin/launchctl', 'dumpstate']
|
||||
cmd_out = subprocess.run(cmd, capture_output = True, check = False)
|
||||
launchd_labels = re.findall("loginwindow/.*/(" + LAUNCHD_PREFIX + ".*) =",
|
||||
cmd_out.stdout.decode())
|
||||
|
||||
# For each plist in /Library/LaunchAgents/ prefixed with LAUNCHD_PREFIX
|
||||
for launch_agent in launch_agents:
|
||||
try:
|
||||
# Make sure content is valid, before proceeding to reload
|
||||
agent_content = FoundationPlist.readPlist(launch_agent)
|
||||
except FoundationPlist.NSPropertyListSerializationException:
|
||||
break
|
||||
# If we're to limit loading
|
||||
if agent_content.get('LimitLoadToSessionType'):
|
||||
# If the launch agent includes LimitLoadToSessionType, and it contains LoginWindow
|
||||
if 'LoginWindow' in agent_content.get('LimitLoadToSessionType'):
|
||||
# If the launch agent is to be loaded at the login window, get the Label
|
||||
agent_label = agent_content.get('Label')
|
||||
# If we have a label and it's not an INSTALL_HELPER launchd item
|
||||
if agent_label and not INSTALL_HELPER in agent_label:
|
||||
# Check to see if the launch agent is loaded, before stopping
|
||||
if agent_label in launchd_labels:
|
||||
# Stop the launch agent at the login window
|
||||
logging.info("Stopping: %s", launch_agent)
|
||||
cmd = ['/bin/launchctl', 'unload', '-S', 'LoginWindow', launch_agent]
|
||||
subprocess.call(cmd)
|
||||
# Load the launch agent at the login window
|
||||
logging.info("Starting: %s", launch_agent)
|
||||
cmd = ['/bin/launchctl', 'load', '-S', 'LoginWindow', launch_agent]
|
||||
subprocess.call(cmd)
|
||||
# Append the launchd items label to loginwindow_launchds
|
||||
loginwindow_launchds.append(agent_label)
|
||||
|
||||
# For each label in launchd_labels
|
||||
for launchd_label in launchd_labels:
|
||||
# If we have a label, it's not in loginwindow_launchds and it's not an INSTALL_HELPER
|
||||
# launchd item
|
||||
if (launchd_label not in loginwindow_launchds
|
||||
and not launchd_label.startswith(INSTALL_HELPER)):
|
||||
# Stop the launch agent
|
||||
logging.info("Stopping: %s", launchd_label)
|
||||
cmd = ['/bin/launchctl', 'bootout', 'loginwindow/' + launchd_label]
|
||||
subprocess.call(cmd)
|
||||
|
||||
# Returns loginwindow_launchds
|
||||
return loginwindow_launchds
|
||||
|
||||
|
||||
def process_munki_launchd(launchd_group):
|
||||
'''Reload Munki's launchd'''
|
||||
|
||||
# If we're to interact only with the appusage launchd items
|
||||
if launchd_group == 'appusage':
|
||||
# returns a list containing just the path to the app_usage_monitor launch agent
|
||||
launch_agents = ['/Library/LaunchAgents/' + APPUSAGE_AGENT+ '.plist']
|
||||
# returns a list containing just the path to the appusaged launch daemon
|
||||
launch_daemons = ['/Library/LaunchDaemons/' + APPUSAGE_DAEMON + '.plist']
|
||||
|
||||
# If we're to interact with all non-appusage launchd items
|
||||
if launchd_group == 'launchd':
|
||||
# Returns a list of Munki's launch agents, excluding the APPUSAGE_AGENT agent
|
||||
launch_agents = [launch_agent for launch_agent in
|
||||
glob.glob('/Library/LaunchAgents/' + LAUNCHD_PREFIX + '*') if not
|
||||
APPUSAGE_AGENT in launch_agent]
|
||||
# Returns a list of Munki's launch daemons, excluding the APPUSAGE_DAEMON and
|
||||
# INSTALL_HELPER launchd items
|
||||
launch_daemons = [launch_daemon for launch_daemon in
|
||||
glob.glob('/Library/LaunchDaemons/' + LAUNCHD_PREFIX + '*') if not
|
||||
(APPUSAGE_DAEMON or INSTALL_HELPER) in launch_daemon]
|
||||
|
||||
# Only proceed if PROG_NAME isn't running, looping until it's not running
|
||||
is_managedsoftwareupdate_running()
|
||||
|
||||
# Get the userid and username of any logged in users
|
||||
user_details = get_logged_in_users()
|
||||
|
||||
# If users are logged in
|
||||
if user_details:
|
||||
# If users are logged in, reload the required launch agents as them
|
||||
process_user_launch_agents(launch_agents, launchd_group, user_details)
|
||||
|
||||
# If we're not only looking to reload the appusage launchd's
|
||||
if launchd_group != 'appusage':
|
||||
# reload munki's loginwindow launch agents, returning a list of labels
|
||||
loginwindow_launchds = process_loginwindow_launch_agents(launch_agents)
|
||||
# If we're just looking to reload the appusage launchd's
|
||||
else:
|
||||
# Set to an empty list
|
||||
loginwindow_launchds = []
|
||||
|
||||
# Reload launch daemons as needed
|
||||
process_launch_daemons(launch_daemons, launchd_group, loginwindow_launchds)
|
||||
|
||||
# Set name and path based on the value of launchd_group
|
||||
launch_daemon_name = INSTALL_HELPER + '-' + launchd_group
|
||||
launch_daemon_path = '/Library/LaunchDaemons/' + launch_daemon_name + '.plist'
|
||||
|
||||
# If the launch daemon exists
|
||||
if os.path.isfile(launch_daemon_path):
|
||||
# Progress notification
|
||||
logging.info("Completed tasks, tidying up")
|
||||
# Delete the launch daemon
|
||||
logging.info("Deleting: %s", launch_daemon_path)
|
||||
os.unlink(launch_daemon_path)
|
||||
# Unload the launch daemon
|
||||
logging.info("Unloading: %s", launch_daemon_name)
|
||||
cmd = ['/bin/launchctl', 'bootout', 'system/' + launch_daemon_name]
|
||||
subprocess.call(cmd)
|
||||
|
||||
|
||||
def process_user_launch_agents(launch_agents, launchd_group, user_details):
|
||||
'''Processes Munki's user Launch Agents'''
|
||||
|
||||
# For each logged in user
|
||||
for userid, username in user_details.items():
|
||||
# Var declaration
|
||||
matched_labels = []
|
||||
# Log who we're reloading the Launch Agents as
|
||||
logging.info("Processing Launch Agents for: %s", username)
|
||||
# Retrieve all running launch agents for the user
|
||||
cmd = ['/bin/launchctl', 'asuser', str(userid), '/bin/launchctl', 'list']
|
||||
cmd_out = subprocess.run(cmd, capture_output = True, check = False)
|
||||
launchd_labels = split_launchctl_list(cmd_out)
|
||||
# For each plist in /Library/LaunchAgents/ prefixed with LAUNCHD_PREFIX
|
||||
for launch_agent in launch_agents:
|
||||
try:
|
||||
# Make sure content is valid, before proceeding to reload
|
||||
agent_content = FoundationPlist.readPlist(launch_agent)
|
||||
except FoundationPlist.NSPropertyListSerializationException:
|
||||
break
|
||||
# If the launch agent doesn't contain LimitLoadToSessionType or
|
||||
# LimitLoadToSessionType exists and it contains Aqua
|
||||
if (not agent_content.get('LimitLoadToSessionType') or 'Aqua' in
|
||||
agent_content.get('LimitLoadToSessionType')):
|
||||
# If the launch agent is to be loaded at the login window, get the Label
|
||||
agent_label = agent_content.get('Label')
|
||||
# If we have a label and it's not an INSTALL_HELPER launchd item
|
||||
if agent_label and not agent_label.startswith(INSTALL_HELPER):
|
||||
# Check to see if the launch agent is loaded, before stopping
|
||||
if agent_label in launchd_labels:
|
||||
# Stop the launch agent
|
||||
logging.info("Stopping: %s", launch_agent)
|
||||
cmd = ['/bin/launchctl', 'asuser', str(userid), '/bin/launchctl', 'bootout',
|
||||
'gui/' + str(userid) + '/' + agent_label]
|
||||
subprocess.call(cmd)
|
||||
# Load the launch agent
|
||||
logging.info("Starting: %s", launch_agent)
|
||||
cmd = ['/bin/launchctl', 'asuser', str(userid), '/bin/launchctl', 'bootstrap',
|
||||
'gui/' + str(userid), launch_agent]
|
||||
subprocess.call(cmd)
|
||||
# Append the launchd items label to matched_labels
|
||||
matched_labels.append(agent_label)
|
||||
|
||||
# If we're to interact with all non-appusage launchd items
|
||||
if launchd_group == 'launchd':
|
||||
# For each label in launchd_labels
|
||||
for launchd_label in launchd_labels:
|
||||
# If we have a label, it's not in matched_labels and it's not an INSTALL_HELPER
|
||||
# launchd item
|
||||
if (launchd_label not in matched_labels + [APPUSAGE_AGENT]
|
||||
and not launchd_label.startswith(INSTALL_HELPER)):
|
||||
# Stop the launch agent
|
||||
logging.info("Stopping: %s", launchd_label)
|
||||
cmd = ['/bin/launchctl', 'asuser', str(userid), '/bin/launchctl', 'bootout',
|
||||
'gui/' + str(userid) + '/' + launchd_label]
|
||||
subprocess.call(cmd)
|
||||
|
||||
|
||||
def setup_logging():
|
||||
'''Configure logging'''
|
||||
|
||||
# Creates the logging dir if doesn't exist
|
||||
Path(os.path.dirname(prefs.pref('LogFile'))).mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Store the log in the same directory as ManagedSoftwareUpdate.log
|
||||
log_path = os.path.join(os.path.dirname(prefs.pref('LogFile')), APP_NAME + '.log')
|
||||
|
||||
# Generic settings
|
||||
log_level = logging.getLevelName('INFO')
|
||||
|
||||
# Log format
|
||||
log_format = logging.Formatter('%(asctime)s %(levelname)s %(message)s', '%b %d %Y %H:%M:%S %z')
|
||||
|
||||
# Change root logger level from WARNING to NOTSET in order for all messages to be delegated.
|
||||
# https://stackoverflow.com/a/59431653
|
||||
logging.getLogger('').setLevel(logging.NOTSET)
|
||||
|
||||
# Create a rotating log file handler, rotate at 10MB, keeping 9 backups
|
||||
file_logger = logging.handlers.RotatingFileHandler(log_path, 'a', 100000, 9, 'utf-8')
|
||||
# Set file logging level
|
||||
file_logger.setLevel(log_level)
|
||||
# Set file log format
|
||||
file_logger.setFormatter(log_format)
|
||||
# Add to logger
|
||||
logging.getLogger('').addHandler(file_logger)
|
||||
|
||||
# Add console handler to logging object
|
||||
console_logger = logging.StreamHandler()
|
||||
# Set console logging level
|
||||
console_logger.setLevel(log_level)
|
||||
# Set console logging format
|
||||
console_logger.setFormatter(log_format)
|
||||
# Add to logger
|
||||
logging.getLogger('').addHandler(console_logger)
|
||||
|
||||
# Start log
|
||||
logging.info("Starting %s - %s", APP_NAME, APP_VERSION)
|
||||
|
||||
|
||||
def split_launchctl_list(cmd_out):
|
||||
'''Takes launchctl list output and returns a list with just the labels'''
|
||||
|
||||
# Var declaration
|
||||
launchd_labels = []
|
||||
|
||||
# Strip cmd_out to just the labels of the running launch agents
|
||||
for launchd_item in cmd_out.stdout.decode().splitlines():
|
||||
# If the launchd_item starts with LAUNCHD_PREFIX
|
||||
if launchd_item.split('\t')[2].startswith(LAUNCHD_PREFIX):
|
||||
# Add the label to launchd_labels
|
||||
launchd_labels.append(launchd_item.split('\t')[2])
|
||||
|
||||
# Returns a list of launchd labels
|
||||
return launchd_labels
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
# Check to see if we're root
|
||||
if os.geteuid() != 0:
|
||||
print("ERROR: You must run this as root!", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
# If INSTALLHELPER_RUN_TYPE isn't set
|
||||
if not os.environ.get('INSTALLHELPER_RUN_TYPE'):
|
||||
# If we have no arguments passed or the arguments passed are not expected.. exit
|
||||
if len(sys.argv) == 1 or not (sys.argv[1].lower() == 'appusage' or
|
||||
sys.argv[1].lower() == 'launchd'):
|
||||
print("ERROR: Requires either \'appusage\' or \'launchd\' arguments to be passed.")
|
||||
sys.exit(1)
|
||||
# If INSTALLHELPER_RUN_TYPE is set
|
||||
else:
|
||||
# Else if we have INSTALLHELPER_RUN_TYPE defined, and it's not what's expected.. exit
|
||||
if not (os.environ.get('INSTALLHELPER_RUN_TYPE') != 'appusage' or
|
||||
os.environ.get('INSTALLHELPER_RUN_TYPE') != 'launchd'):
|
||||
# Set launchd_group to the value of INSTALLHELPER_RUN_TYPE
|
||||
print("ERROR: Requires INSTALLHELPER_RUN_TYPE to be set to either \'appusage\' or "
|
||||
"\'launchd\'")
|
||||
sys.exit(1)
|
||||
|
||||
# Proceed to run main
|
||||
main()
|
||||
@@ -508,7 +508,7 @@ mkdir -m 755 "$ADMINROOT/usr/local"
|
||||
mkdir -m 755 "$ADMINROOT/usr/local/munki"
|
||||
# Copy command line admin utilities.
|
||||
# edit this if list of tools changes!
|
||||
for TOOL in makecatalogs makepkginfo manifestutil munkiimport iconimporter repoclean
|
||||
for TOOL in makecatalogs makepkginfo manifestutil munkiimport iconimporter repoclean installhelper
|
||||
do
|
||||
cp -X "$MUNKIROOT/code/client/$TOOL" "$ADMINROOT/usr/local/munki/" 2>&1
|
||||
done
|
||||
@@ -544,10 +544,12 @@ mkdir -m 1775 "$APPROOT"
|
||||
mkdir -m 775 "$APPROOT/Applications"
|
||||
# Copy Managed Software Center application.
|
||||
cp -R "$MSCAPP" "$APPROOT/Applications/"
|
||||
# Create Helper directory
|
||||
mkdir -m 775 "$APPROOT/Applications/Managed Software Center.app/Contents/Helpers/"
|
||||
# Copy MunkiStatus helper app
|
||||
cp -R "$MSAPP" "$APPROOT/Applications/Managed Software Center.app/Contents/Resources/"
|
||||
cp -R "$MSAPP" "$APPROOT/Applications/Managed Software Center.app/Contents/Helpers/"
|
||||
# Copy notifier helper app
|
||||
cp -R "$NOTIFIERAPP" "$APPROOT/Applications/Managed Software Center.app/Contents/Resources/"
|
||||
cp -R "$NOTIFIERAPP" "$APPROOT/Applications/Managed Software Center.app/Contents/Helpers/"
|
||||
# make sure not writeable by group or other
|
||||
chmod -R go-w "$APPROOT/Applications/Managed Software Center.app"
|
||||
|
||||
@@ -556,7 +558,7 @@ if [ "$APPSIGNINGCERT" != "" ]; then
|
||||
echo "Signing Managed Software Center.app Bundles..."
|
||||
/usr/bin/codesign -f -s "$APPSIGNINGCERT" --options runtime --timestamp --verbose \
|
||||
"$APPROOT/Applications/Managed Software Center.app/Contents/PlugIns/MSCDockTilePlugin.docktileplugin" \
|
||||
"$APPROOT/Applications/Managed Software Center.app/Contents/Resources/munki-notifier.app"
|
||||
"$APPROOT/Applications/Managed Software Center.app/Contents/Helpers/munki-notifier.app"
|
||||
SIGNING_RESULT="$?"
|
||||
if [ "$SIGNING_RESULT" -ne 0 ]; then
|
||||
echo "Error signing Managed Software Center.app: $SIGNING_RESULT"
|
||||
@@ -564,7 +566,7 @@ if [ "$APPSIGNINGCERT" != "" ]; then
|
||||
fi
|
||||
|
||||
echo "Signing MunkiStatus.app Frameworks..."
|
||||
/usr/bin/find "$APPROOT/Applications/Managed Software Center.app/Contents/Resources/MunkiStatus.app/Contents/Frameworks" -type f -perm -u=x -exec /usr/bin/codesign -f -s "$APPSIGNINGCERT" --options runtime --timestamp --verbose {} \;
|
||||
/usr/bin/find "$APPROOT/Applications/Managed Software Center.app/Contents/Helpers/MunkiStatus.app/Contents/Frameworks" -type f -perm -u=x -exec /usr/bin/codesign -f -s "$APPSIGNINGCERT" --options runtime --timestamp --verbose {} \;
|
||||
SIGNING_RESULT="$?"
|
||||
if [ "$SIGNING_RESULT" -ne 0 ]; then
|
||||
echo "Error signing MunkiStatus.app Frameworks: $SIGNING_RESULT"
|
||||
@@ -580,7 +582,7 @@ if [ "$APPSIGNINGCERT" != "" ]; then
|
||||
|
||||
echo "Signing Managed Software Center.app..."
|
||||
/usr/bin/codesign -f -s "$APPSIGNINGCERT" --options runtime --timestamp --verbose \
|
||||
"$APPROOT/Applications/Managed Software Center.app/Contents/Resources/MunkiStatus.app" \
|
||||
"$APPROOT/Applications/Managed Software Center.app/Contents/Helpers/MunkiStatus.app" \
|
||||
"$APPROOT/Applications/Managed Software Center.app"
|
||||
SIGNING_RESULT="$?"
|
||||
if [ "$SIGNING_RESULT" -ne 0 ]; then
|
||||
@@ -914,18 +916,6 @@ cat > "$DISTFILE" <<EOF
|
||||
<os-version min="10.13"/>
|
||||
</allowed-os-versions>
|
||||
</volume-check>
|
||||
<script>
|
||||
<![CDATA[
|
||||
function launchdRestartAction() {
|
||||
var launchd_choice = choices.launchd.packageUpgradeAction
|
||||
if (launchd_choice == "upgrade" || launchd_choice == "downgrade") {
|
||||
return "RequireRestart";
|
||||
} else {
|
||||
return "None";
|
||||
}
|
||||
}
|
||||
]]>
|
||||
</script>
|
||||
<options hostArchitectures="x86_64,arm64" customize="allow" allow-external-scripts="no"/>
|
||||
<domains enable_anywhere="true"/>
|
||||
<choices-outline>
|
||||
@@ -951,7 +941,7 @@ cat > "$DISTFILE" <<EOF
|
||||
<choice id="app" title="$APPTITLE" description="$APPDESC">
|
||||
<pkg-ref id="$PKGID.app"/>
|
||||
</choice>
|
||||
<choice id="launchd" title="$LAUNCHDTITLE" description="$LAUNCHDDESC" start_selected='my.choice.packageUpgradeAction != "installed"'>
|
||||
<choice id="launchd" title="$LAUNCHDTITLE" description="$LAUNCHDDESC">
|
||||
<pkg-ref id="$PKGID.launchd"/>
|
||||
</choice>
|
||||
<choice id="app_usage" title="$APPUSAGETITLE" description="$APPUSAGEDESC">
|
||||
@@ -968,9 +958,9 @@ cat > "$DISTFILE" <<EOF
|
||||
<pkg-ref id="$PKGID.core" auth="Root">${PKGPREFIX}munkitools_core.pkg</pkg-ref>
|
||||
<pkg-ref id="$PKGID.admin" auth="Root">${PKGPREFIX}munkitools_admin.pkg</pkg-ref>
|
||||
<pkg-ref id="$PKGID.app" auth="Root">${PKGPREFIX}munkitools_app.pkg</pkg-ref>
|
||||
<pkg-ref id="$PKGID.launchd" auth="Root" onConclusionScript="launchdRestartAction()">${PKGPREFIX}munkitools_launchd.pkg</pkg-ref>
|
||||
<pkg-ref id="$PKGID.app_usage" auth="Root">${PKGPREFIX}munkitools_app_usage.pkg</pkg-ref>
|
||||
<pkg-ref id="$PKGID.python" auth="Root">${PKGPREFIX}munkitools_python.pkg</pkg-ref>
|
||||
<pkg-ref id="$PKGID.launchd" auth="Root">${PKGPREFIX}munkitools_launchd.pkg</pkg-ref>
|
||||
<pkg-ref id="$PKGID.app_usage" auth="Root">${PKGPREFIX}munkitools_app_usage.pkg</pkg-ref>
|
||||
$BOOTSTRAPREF
|
||||
$CONFREF
|
||||
$CLIENTCERTREF
|
||||
|
||||
@@ -1,22 +1,19 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Lovingly adapted from Per Olofsson
|
||||
# https://github.com/MagerValp/Scripted-Mac-Package-Creation/blob/master/scripts/postinstall
|
||||
#
|
||||
# this postinstall should run installhelper in the background, with it then waiting until
|
||||
# managedsoftwareupdate isn't running and then (re)load Munki's appusage launchditems items as needed
|
||||
#
|
||||
|
||||
export PATH=/usr/bin:/bin:/usr/sbin:/sbin
|
||||
|
||||
# Execute postinstall actions if we're installing on a live system.
|
||||
# This is useful for loading launch daemons and agents.
|
||||
if [ "$3" = "/" ]; then
|
||||
|
||||
# Run postinstall actions for root.
|
||||
launchctl bootstrap system/ /Library/LaunchDaemons/com.googlecode.munki.appusaged.plist
|
||||
|
||||
# Run postinstall actions for all logged in users.
|
||||
for uid in $(ps -axo uid,args | grep "/[F]inder.app/" | awk '{print $1}'); do
|
||||
launchctl bootstrap gui/"$uid"/ /Library/LaunchAgents/com.googlecode.munki.app_usage_monitor.plist
|
||||
done
|
||||
|
||||
fi
|
||||
|
||||
exit 0
|
||||
# Only execute postinstall actions if we're installing on a live system.
|
||||
if [ "$3" = "/" ]
|
||||
then
|
||||
installHelper='/usr/local/munki/installhelper'
|
||||
if [ -f "${installHelper}" ]
|
||||
then
|
||||
/bin/echo "Loading ${installHelper}..."
|
||||
"${installHelper}" appusage &
|
||||
else
|
||||
/bin/echo "Cannot locate: ${installHelper}..."
|
||||
fi
|
||||
fi
|
||||
@@ -1,29 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Lovingly adapted from Per Olofsson
|
||||
# https://github.com/MagerValp/Scripted-Mac-Package-Creation/blob/master/scripts/postinstall
|
||||
|
||||
export PATH=/usr/bin:/bin:/usr/sbin:/sbin
|
||||
|
||||
# Execute preinstall actions if we're installing on a live system.
|
||||
# This is useful for unloading launch daemons and agents.
|
||||
if [ "$3" = "/" ]; then
|
||||
|
||||
# Run preinstall actions for root.
|
||||
if launchctl print system/munki.app_usage_monitor > /dev/null 2>&1 ; then
|
||||
launchctl bootout system/munki.app_usage_monitor
|
||||
fi
|
||||
if launchctl print system/com.googlecode.munki.appusaged. > /dev/null 2>&1 ; then
|
||||
launchctl bootout system/com.googlecode.munki.appusaged
|
||||
fi
|
||||
|
||||
# Run preinstall actions for all logged in users.
|
||||
for uid in $(ps -axo uid,args | grep "/[F]inder.app/" | awk '{print $1}'); do
|
||||
if launchctl print gui/"$uid"/com.googlecode.munki.app_usage_monitor > /dev/null 2>&1 ; then
|
||||
launchctl bootout gui/"$uid"/com.googlecode.munki.app_usage_monitor
|
||||
fi
|
||||
done
|
||||
|
||||
fi
|
||||
|
||||
exit 0
|
||||
@@ -1,51 +1,19 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Lovingly lifted from Per Olofsson
|
||||
# https://github.com/MagerValp/Scripted-Mac-Package-Creation/blob/master/scripts/postinstall
|
||||
|
||||
# this is intended for a new install of the Munki tools -- the tools will be
|
||||
# installed and the launchagents/daemons will be activated without the need for
|
||||
# a restart
|
||||
#
|
||||
# This should not be used for "upgrade" installs of the munkitools, or by
|
||||
# installs handled by Munki itself.
|
||||
# this postinstall should run installhelper in the background, with it then waiting until
|
||||
# managedsoftwareupdate isn't running and then (re)load Munki's launchd items as needed
|
||||
#
|
||||
|
||||
export PATH=/usr/bin:/bin:/usr/sbin:/sbin
|
||||
|
||||
# Execute postinstall actions if we're installing on a live system.
|
||||
# This is useful for loading launch daemons and agents.
|
||||
if [ "$3" = "/" ]; then
|
||||
|
||||
# is a Munki launchd job already loaded? if so, exit now
|
||||
for JOB in logouthelper managedsoftwareupdate-check managedsoftwareupdate-install managedsoftwareupdate-manualcheck
|
||||
do
|
||||
if launchctl list com.googlecode.munki.${JOB} >/dev/null 2>&1 ; then
|
||||
echo "com.googlecode.munki.${JOB} is loaded: exiting postflight"
|
||||
exit 0
|
||||
fi
|
||||
done
|
||||
|
||||
# Load all launch daemons.
|
||||
launchctl bootstrap system/ /Library/LaunchDaemons/com.googlecode.munki.authrestartd.plist
|
||||
launchctl bootstrap system/ /Library/LaunchDaemons/com.googlecode.munki.logouthelper.plist
|
||||
launchctl bootstrap system/ /Library/LaunchDaemons/com.googlecode.munki.managedsoftwareupdate-check.plist
|
||||
launchctl bootstrap system/ /Library/LaunchDaemons/com.googlecode.munki.managedsoftwareupdate-install.plist
|
||||
launchctl bootstrap system/ /Library/LaunchDaemons/com.googlecode.munki.managedsoftwareupdate-manualcheck.plist
|
||||
|
||||
loggedInUser=$( echo "show State:/Users/ConsoleUser" | scutil | awk '/Name :/ && ! /loginwindow/ { print $3 }' )
|
||||
if [ "$loggedInUser" = "" ] ; then
|
||||
# no-one is logged in; I.E. we're at the loginwindow.
|
||||
# Load the loginwindow launchagents
|
||||
launchctl load -S LoginWindow /Library/LaunchAgents/com.googlecode.munki.managedsoftwareupdate-loginwindow.plist
|
||||
launchctl load -S LoginWindow /Library/LaunchAgents/com.googlecode.munki.MunkiStatus.plist
|
||||
# Only execute postinstall actions if we're installing on a live system.
|
||||
if [ "$3" = "/" ]
|
||||
then
|
||||
installHelper='/usr/local/munki/installhelper'
|
||||
if [ -f "${installHelper}" ]
|
||||
then
|
||||
/bin/echo "Loading ${installHelper}..."
|
||||
"${installHelper}" launchd &
|
||||
else
|
||||
/bin/echo "Cannot locate: ${installHelper}..."
|
||||
fi
|
||||
|
||||
# Load launch agents for all currently logged in users.
|
||||
for uid in $(ps -axo uid,args | grep "/[F]inder.app/" | awk '{print $1}'); do
|
||||
launchctl bootstrap gui/"$uid"/ /Library/LaunchAgents/com.googlecode.munki.ManagedSoftwareCenter.plist
|
||||
launchctl bootstrap gui/"$uid"/ /Library/LaunchAgents/com.googlecode.munki.munki-notifier.plist
|
||||
done
|
||||
|
||||
fi
|
||||
|
||||
exit 0
|
||||
fi
|
||||
@@ -24,7 +24,7 @@
|
||||
</array>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/Applications/Managed Software Center.app/Contents/Resources/MunkiStatus.app/Contents/MacOS/MunkiStatus</string>
|
||||
<string>/Applications/Managed Software Center.app/Contents/Helpers/MunkiStatus.app/Contents/MacOS/MunkiStatus</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<array>
|
||||
<string>/usr/local/munki/launchapp</string>
|
||||
<string>-a</string>
|
||||
<string>/Applications/Managed Software Center.app/Contents/Resources/munki-notifier.app</string>
|
||||
<string>/Applications/Managed Software Center.app/Contents/Helpers/munki-notifier.app</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
Reference in New Issue
Block a user