# HG changeset patch # User Bart Smaalders # Date 1223702114 25200 # Node ID 22bc748edce6e017fc25b7d6e32c286380ca8cd5 # Parent fc856572d86e948afd47f2eb11db737944aae716 577 need service action for smf(5) manifests 578 need restart action or equivalent to poke smf(5) services diff -r fc856572d86e -r 22bc748edce6 src/client.py --- a/src/client.py Fri Oct 10 16:32:27 2008 -0700 +++ b/src/client.py Fri Oct 10 22:15:14 2008 -0700 @@ -72,6 +72,7 @@ import pkg.version import pkg.Uuid25 import pkg +from pkg.client.debugvalues import DebugValues from pkg.client.history import RESULT_FAILED_UNKNOWN from pkg.client.history import RESULT_CANCELED @@ -145,6 +146,7 @@ Options: -R dir + -D/--debug name=value Environment: PKG_IMAGE""")) @@ -1931,10 +1933,21 @@ gettext.install("pkg", "/usr/lib/locale") try: - opts, pargs = getopt.getopt(sys.argv[1:], "R:") + opts, pargs = getopt.getopt(sys.argv[1:], "R:D:", ["debug="]) except getopt.GetoptError, e: usage(_("illegal global option -- %s") % e.opt) + for opt, arg in opts: + if opt == "-D" or opt == "--debug": + try: + key, value = arg.split('=', 1) + except: + usage(_("%s takes argument of form name=value, not %s") + % (opt, arg)) + DebugValues.set_value(key, value) + elif opt == "-R": + mydir = arg + if pargs == None or len(pargs) == 0: usage() @@ -1950,6 +1963,9 @@ global_settings.PKG_TIMEOUT_MAX)) if subcommand == "image-create": + if "mydir" in locals(): + usage(_("-R not allowed for %s subcommand") % + subcommand) try: ret = image_create(img, pargs) except getopt.GetoptError, e: @@ -1957,6 +1973,9 @@ (subcommand, e.opt)) return ret elif subcommand == "version": + if "mydir" in locals(): + usage(_("-R not allowed for %s subcommand") % + subcommand) if pargs: usage(_("version: command does not take operands " \ "('%s')") % " ".join(pargs)) @@ -1971,10 +1990,6 @@ provided_image_dir = True pkg_image_used = False - for opt, arg in opts: - if opt == "-R": - mydir = arg - if "mydir" not in locals(): try: mydir = os.environ["PKG_IMAGE"] diff -r fc856572d86e -r 22bc748edce6 src/modules/client/actuator.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/modules/client/actuator.py Fri Oct 10 22:15:14 2008 -0700 @@ -0,0 +1,279 @@ +#!/usr/bin/python2.4 +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. + + +class GenericActuator(object): + """Actuators are action attributes that cause side effects + on live images when those actions are updated, installed + or removed. Since no side effects are caused when the + affected image isn't the current root image, the OS may + need to cause the equivalent effect during boot. + """ + + actuator_attrs = set() + + def __init__(self): + self.install = {} + self.removal = {} + self.update = {} + + + def scan_install(self, attrs): + self.__scan(self.install, attrs) + + def scan_removal(self, attrs): + self.__scan(self.removal, attrs) + + def scan_update(self, attrs): + self.__scan(self.update, attrs) + + def __scan(self, dictionary, attrs): + for a in set(attrs.keys()) & self.actuator_attrs: + if a in dictionary: + dictionary[a].add(attrs[a]) + else: + dictionary[a] = set([attrs[a]]) + + def clone_required(self): + return False + + def exec_prep(self, image): + pass + + def exec_pre_actuators(self, image): + pass + + def exec_post_actuators(self, image): + pass + + def exec_fail_actuators(self, image): + pass + + def __str__(self): + return "Removals: %s\nInstalls: %s\nUpdates: %s\n" % \ + (self.removal, self.install, self.update) + +# range of possible SMF service states +SMF_SVC_UNKNOWN = 0 +SMF_SVC_DISABLED = 1 +SMF_SVC_MAINTENANCE = 2 +SMF_SVC_TMP_DISABLED = 3 +SMF_SVC_TMP_ENABLED = 4 +SMF_SVC_ENABLED = 5 + +import os +import subprocess +from pkg.client.debugvalues import DebugValues + +svcprop_path = "/usr/bin/svcprop" +svcadm_path = "/usr/sbin/svcadm" + +class Actuator(GenericActuator): + """Solaris specific Actuator implementation...""" + + actuator_attrs = set([ + "reboot_on_update", # have to reboot to update this file + "refresh_fmri", # refresh this service on any change + "restart_fmri", # restart this service on any change + "suspend_fmri", # suspend this service during update + "disable_fmri" # disable this service prior to removal + ]) + + def __init__(self): + GenericActuator.__init__(self) + self.suspend_fmris = None + self.tmp_suspend_fmris = None + self.do_nothing = True + self.cmd_path = "" + + def clone_required(self): + return "reboot_on_update" in self.update + + def exec_prep(self, image): + if not image.is_liveroot(): + dir = DebugValues.get_value("actuator_cmds_dir") + if not dir: + return + self.cmd_path = dir + self.do_nothing = False + + def exec_pre_actuators(self, image): + """do pre execution actuator processing...""" + + if self.do_nothing: + return + + suspend_fmris = self.update.get("suspend_fmri", set()) + tmp_suspend_fmris = set() + + disable_fmris = self.removal.get("disable_fmri", set()) + + # eliminate services not loaded or not running + # remember those services enabled only temporarily + + for fmri in suspend_fmris.copy(): + state = self.__smf_svc_get_state(fmri) + if state <= SMF_SVC_TMP_ENABLED: + suspend_fmris.remove(fmri) + if state == SMF_SVC_TMP_ENABLED: + tmp_suspend_fmris.add(fmri) + + for fmri in disable_fmris.copy(): + if self.__smf_svc_is_disabled(fmri): + disable_fmris.remove(fmri) + + self.suspend_fmris = suspend_fmris + self.tmp_suspend_fmris = tmp_suspend_fmris + + args = (svcadm_path, "disable", "-t") + + params = tuple(suspend_fmris | tmp_suspend_fmris) + + if params: + self.__call(args + params) + + args = (svcadm_path, "disable") + params = tuple(disable_fmris) + + if params: + self.__call(args + params) + + def exec_fail_actuators(self, image): + """handle a failed install""" + + if self.do_nothing: + return + + args = (svcadm_path, "mark", "maintenance") + params = tuple(self.suspend_fmris | + self.tmp_suspend_fmris) + + if params: + self.__call(args + params) + + def exec_post_actuators(self, image): + """do post execution actuator processing""" + + if self.do_nothing: + return + + refresh_fmris = self.removal.get("refresh_fmri", set()) | \ + self.update.get("refresh_fmri", set()) | \ + self.install.get("refresh_fmri", set()) + + restart_fmris = self.removal.get("restart_fmri", set()) | \ + self.update.get("restart_fmri", set()) | \ + self.install.get("restart_fmri", set()) + + # ignore services not present or not + # enabled + + for fmri in refresh_fmris.copy(): + if self.__smf_svc_is_disabled(fmri): + refresh_fmris.remove(fmri) + + args = (svcadm_path, "refresh") + params = tuple(refresh_fmris) + + if params: + self.__call(args + params) + + for fmri in restart_fmris.copy(): + if self.__smf_svc_is_disabled(fmri): + restart_fmris.remove(fmri) + + args = (svcadm_path, "restart") + params = tuple(restart_fmris) + if params: + self.__call(args + params) + + # reenable suspended services that were running + # be sure to not enable services that weren't running + # and temp. enable those services that were in that + # state. + + args = (svcadm_path, "enable") + params = tuple(self.suspend_fmris) + if params: + self.__call(args + params) + + args = (svcadm_path, "enable", "-t") + params = tuple(self.tmp_suspend_fmris) + if params: + self.__call(args + params) + + def __smf_svc_get_state(self, fmri): + """ return state of smf service """ + + props = self.__get_smf_props(fmri) + if not props: + return SMF_SVC_UNKNOWN + + if "maintenance" in props["restarter/state"]: + return SMF_SVC_MAINTENANCE + + if "true" not in props["general/enabled"]: + if "general_ovr/enabled" not in props: + return SMF_SVC_DISABLED + elif "true" in props["general_ovr/enabled"]: + return SMF_SVC_TMP_ENABLED + else: + if "general_ovr/enabled" not in props: + return SMF_SVC_ENABLED + elif "false" in props["general_ovr/enabled"]: + return SMF_SVC_TMP_DISABLED + + def __smf_svc_is_disabled(self, fmri): + return self.__smf_svc_get_state(fmri) < SMF_SVC_TMP_ENABLED + + def __get_smf_props(self, svcfmri): + args = (svcprop_path, "-c", svcfmri) + buf = self.__call(args) + return dict([ + l.strip().split(None, 1) + for l in buf + ]) + + def __call(self, args): + # a way to invoke a separate executable for testing + if self.cmd_path: + args = ( + os.path.join(self.cmd_path, + args[0].lstrip("/")),) + args[1:] + try: + proc = subprocess.Popen(args, stdout = subprocess.PIPE, + stderr = subprocess.STDOUT) + buf = proc.stdout.readlines() + ret = proc.wait() + except OSError, e: + raise RuntimeError, "cannot execute %s" % args + + if ret != 0: + raise RuntimeError, "Subprocess (%s) non-zero exit code: %s" \ + % (args, buf) + + return buf + + diff -r fc856572d86e -r 22bc748edce6 src/modules/client/debugvalues.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/modules/client/debugvalues.py Fri Oct 10 22:15:14 2008 -0700 @@ -0,0 +1,41 @@ +#!/usr/bin/python2.4 +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. + + +class DebugValues(object): + """ simple singleton class to handle debug variables """ + __debug_values = {} + + def __call__(self): + return self + + def get_value(self, key): + """ returns None if not set """ + return self.__debug_values.get(key, None) + + def set_value(self, key, value): + self.__debug_values[key] = value + +DebugValues=DebugValues() diff -r fc856572d86e -r 22bc748edce6 src/modules/client/imageplan.py --- a/src/modules/client/imageplan.py Fri Oct 10 16:32:27 2008 -0700 +++ b/src/modules/client/imageplan.py Fri Oct 10 22:15:14 2008 -0700 @@ -31,6 +31,8 @@ import pkg.client.indexer as indexer import pkg.search_errors as se from pkg.client.imageconfig import REQUIRE_OPTIONAL +import pkg.client.actuator as actuator + from pkg.client.filter import compile_filter from pkg.misc import msg from pkg.misc import CLIENT_DEFAULT_MEM_USE_KB @@ -99,6 +101,8 @@ self.check_cancelation = check_cancelation + self.actuators = None + def __str__(self): if self.state == UNEVALUATED: s = "UNEVALUATED:\n" @@ -111,6 +115,8 @@ s = "" for pp in self.pkg_plans: s = s + "%s\n" % pp + + s = s + "Actuators:\n%s" % self.actuators return s def get_plan(self, full=True): @@ -127,6 +133,7 @@ def display(self): for pp in self.pkg_plans: msg("%s -> %s" % (pp.origin_fmri, pp.destination_fmri)) + msg("Actuators:\n" % self.actuators) def is_proposed_fmri(self, fmri): for pf in self.target_fmris: @@ -463,6 +470,8 @@ self.progtrack.evaluate_progress() + self.actuators = actuator.Actuator() + # iterate over copy of removals since we're modding list # keep track of deletion count so later use of index works named_removals = {} @@ -485,6 +494,8 @@ (i - deletions, id(self.removal_actions[i-deletions][1])) + self.actuators.scan_removal(a[1].attrs) + self.progtrack.evaluate_progress() for a in self.install_actions: @@ -504,6 +515,8 @@ cache_name a[2].attrs["save_file"] = cache_name + self.actuators.scan_install(a[2].attrs) + self.progtrack.evaluate_progress() # Go over update actions l_actions = self.get_link_actions() @@ -516,6 +529,12 @@ path = a[2].attrs["path"] if path in l_actions: l_refresh.extend([(a[0], l, l) for l in l_actions[path]]) + + # scan both old and new actions + # repairs may result in update action w/o orig action + if a[1]: + self.actuators.scan_update(a[1].attrs) + self.actuators.scan_update(a[2].attrs) self.update_actions.extend(l_refresh) # sort actions to match needed processing order @@ -653,42 +672,55 @@ self.state = EXECUTED_OK return - # execute removals + self.actuators.exec_prep(self.image) + + self.actuators.exec_pre_actuators(self.image) - self.progtrack.actions_set_goal("Removal Phase", len(self.removal_actions)) - for p, src, dest in self.removal_actions: - p.execute_removal(src, dest) - self.progtrack.actions_add_progress() - self.progtrack.actions_done() + try: + + # execute removals - # execute installs - - self.progtrack.actions_set_goal("Install Phase", len(self.install_actions)) + self.progtrack.actions_set_goal("Removal Phase", + len(self.removal_actions)) + for p, src, dest in self.removal_actions: + p.execute_removal(src, dest) + self.progtrack.actions_add_progress() + self.progtrack.actions_done() - for p, src, dest in self.install_actions: - p.execute_install(src, dest) - self.progtrack.actions_add_progress() - self.progtrack.actions_done() + # execute installs + + self.progtrack.actions_set_goal("Install Phase", + len(self.install_actions)) + + for p, src, dest in self.install_actions: + p.execute_install(src, dest) + self.progtrack.actions_add_progress() + self.progtrack.actions_done() - # execute updates + # execute updates - self.progtrack.actions_set_goal("Update Phase", len(self.update_actions)) + self.progtrack.actions_set_goal("Update Phase", + len(self.update_actions)) - for p, src, dest in self.update_actions: - p.execute_update(src, dest) - self.progtrack.actions_add_progress() + for p, src, dest in self.update_actions: + p.execute_update(src, dest) + self.progtrack.actions_add_progress() - self.progtrack.actions_done() + self.progtrack.actions_done() - + # handle any postexecute operations - # handle any postexecute operations + for p in self.pkg_plans: + p.postexecute() - for p in self.pkg_plans: - p.postexecute() + self.image.clear_pkg_state() + + except: + self.actuators.exec_fail_actuators(self.image) + raise + else: + self.actuators.exec_post_actuators(self.image) - self.image.clear_pkg_state() - self.state = EXECUTED_OK # reduce memory consumption @@ -700,6 +732,8 @@ del self.target_rem_fmris del self.target_fmris del self.__directories + + del self.actuators # Perform the incremental update to the search indexes # for all changed packages diff -r fc856572d86e -r 22bc748edce6 src/tests/baseline.txt --- a/src/tests/baseline.txt Fri Oct 10 16:32:27 2008 -0700 +++ b/src/tests/baseline.txt Fri Oct 10 22:15:14 2008 -0700 @@ -194,6 +194,7 @@ api.t_version.py TestVersion.testversionsuccessor7|pass api.t_version.py TestVersion.testversionsuccessor8|pass api.t_version.py TestVersion.testversionsuccessor9|pass +cli.t_actuators.py TestPkgActuators.test_actuators|pass cli.t_api.py TestPkgApi.test_bad_orderings|pass cli.t_api.py TestPkgApi.test_reset|pass cli.t_api_info.py TestApiInfo.test_info_local_remote|pass diff -r fc856572d86e -r 22bc748edce6 src/tests/cli/t_actuators.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/tests/cli/t_actuators.py Fri Oct 10 22:15:14 2008 -0700 @@ -0,0 +1,339 @@ +#!/usr/bin/python2.4 +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. + +import testutils +if __name__ == "__main__": + testutils.setup_environment("../../../proto") + +import os +import unittest +import shutil + +class TestPkgActuators(testutils.SingleDepotTestCase): + # Only start/stop the depot once (instead of for every test) + persistent_depot = True + + svcprop_enabled_data = \ +"""general/enabled boolean true +general/entity_stability astring Unstable +general/single_instance boolean true +restarter/start_pid count 4172 +restarter/start_method_timestamp time 1222382991.639687000 +restarter/start_method_waitstatus integer 0 +restarter/transient_contract count +restarter/auxiliary_state astring none +restarter/next_state astring none +restarter/state astring online +restarter/state_timestamp time 1222382991.644413000 +restarter_actions/refresh integer +restarter_actions/maint_on integer +restarter_actions/maint_off integer +restarter_actions/restart integer +local-filesystems/entities fmri svc:/system/filesystem/local +local-filesystems/grouping astring require_all +local-filesystems/restart_on astring none +local-filesystems/type astring service +remote-filesystems/entities fmri svc:/network/nfs/client svc:/system/filesystem/autofs +remote-filesystems/grouping astring optional_all +remote-filesystems/restart_on astring none +remote-filesystems/type astring service +startd/duration astring transient +start/timeout_seconds count 0 +start/type astring method +stop/exec astring :true +stop/timeout_seconds count 0 +stop/type astring method +""" + svcprop_disabled_data = \ +"""general/enabled boolean false +general/entity_stability astring Unstable +general/single_instance boolean true +restarter/start_pid count 4172 +restarter/start_method_timestamp time 1222382991.639687000 +restarter/start_method_waitstatus integer 0 +restarter/transient_contract count +restarter/auxiliary_state astring none +restarter/next_state astring none +restarter/state astring disabled +restarter/state_timestamp time 1222992132.445811000 +restarter_actions/refresh integer +restarter_actions/maint_on integer +restarter_actions/maint_off integer +restarter_actions/restart integer +local-filesystems/entities fmri svc:/system/filesystem/local +local-filesystems/grouping astring require_all +local-filesystems/restart_on astring none +local-filesystems/type astring service +remote-filesystems/entities fmri svc:/network/nfs/client svc:/system/filesystem/autofs +remote-filesystems/grouping astring optional_all +remote-filesystems/restart_on astring none +remote-filesystems/type astring service +startd/duration astring transient +start/timeout_seconds count 0 +start/type astring method +stop/exec astring :true +stop/timeout_seconds count 0 +stop/type astring method +""" + svcprop_temp_enabled_data = \ +"""general/enabled boolean false +general/entity_stability astring Unstable +general/single_instance boolean true +restarter/start_pid count 7816 +restarter/start_method_timestamp time 1222992237.506096000 +restarter/start_method_waitstatus integer 0 +restarter/transient_contract count +restarter/auxiliary_state astring none +restarter/next_state astring none +restarter/state astring online +restarter/state_timestamp time 1222992237.527408000 +restarter_actions/refresh integer +restarter_actions/maint_on integer +restarter_actions/maint_off integer +restarter_actions/restart integer +general_ovr/enabled boolean true +local-filesystems/entities fmri svc:/system/filesystem/local +local-filesystems/grouping astring require_all +local-filesystems/restart_on astring none +local-filesystems/type astring service +remote-filesystems/entities fmri svc:/network/nfs/client svc:/system/filesystem/autofs +remote-filesystems/grouping astring optional_all +remote-filesystems/restart_on astring none +remote-filesystems/type astring service +startd/duration astring transient +start/timeout_seconds count 0 +start/type astring method +stop/exec astring :true +stop/timeout_seconds count 0 +stop/type astring method +""" + svcprop_temp_disabled_data = \ +"""general/enabled boolean true +general/entity_stability astring Unstable +general/single_instance boolean true +restarter/start_pid count 7816 +restarter/start_method_timestamp time 1222992237.506096000 +restarter/start_method_waitstatus integer 0 +restarter/transient_contract count +restarter/auxiliary_state astring none +restarter/next_state astring none +restarter/state astring disabled +restarter/state_timestamp time 1222992278.822335000 +restarter_actions/refresh integer +restarter_actions/maint_on integer +restarter_actions/maint_off integer +restarter_actions/restart integer +general_ovr/enabled boolean false +local-filesystems/entities fmri svc:/system/filesystem/local +local-filesystems/grouping astring require_all +local-filesystems/restart_on astring none +local-filesystems/type astring service +remote-filesystems/entities fmri svc:/network/nfs/client svc:/system/filesystem/autofs +remote-filesystems/grouping astring optional_all +remote-filesystems/restart_on astring none +remote-filesystems/type astring service +startd/duration astring transient +start/timeout_seconds count 0 +start/type astring method +stop/exec astring :true +stop/timeout_seconds count 0 +stop/type astring method +""" + empty_data = "" + + svcprop_data = \ +"""#!/usr/bin/sh +cat $PKG_TEST_DIR/$PKG_SVCPROP_OUTPUT +exit $PKG_SVCPROP_EXIT_CODE +""" + svcadm_data = \ +"""#!/usr/bin/sh +echo $0 "$@" >> $PKG_TEST_DIR/svcadm_arguments +exit $(PKG_SVCADM_EXIT_CODE) +""" + + + misc_files = [ "svcprop_enabled", "svcprop_disabled", "svcprop_temp_enabled", "empty", + "svcprop_temp_enabled", "usr/bin/svcprop", "usr/sbin/svcadm"] + + testdata_dir = None + + def setUp(self): + + testutils.SingleDepotTestCase.setUp(self) + tp = self.get_test_prefix() + self.testdata_dir = os.path.join(tp, "testdata") + os.mkdir(self.testdata_dir) + self.pkg_list = [] + + self.pkg_list+= [""" + open basics@1.0,5.11-0 + add file """ + self.testdata_dir + """/empty mode=0644 owner=root group=sys path=/test_restart restart_fmri=svc:system/test_restart_svc + close """] + + self.pkg_list+= [""" + open basics@1.1,5.11-0 + add file """ + self.testdata_dir + """/empty mode=0655 owner=root group=sys path=/test_restart restart_fmri=svc:system/test_restart_svc + close """] + + self.pkg_list+= [""" + open basics@1.2,5.11-0 + add file """ + self.testdata_dir + """/empty mode=0646 owner=root group=sys path=/test_restart restart_fmri=svc:system/test_restart_svc + close """] + + self.pkg_list+= [""" + open basics@1.3,5.11-0 + add file """ + self.testdata_dir + """/empty mode=0657 owner=root group=sys path=/test_restart refresh_fmri=svc:system/test_refresh_svc + close """] + + self.pkg_list+= [""" + open basics@1.4,5.11-0 + add file """ + self.testdata_dir + """/empty mode=0667 owner=root group=sys path=/test_restart suspend_fmri=svc:system/test_suspend_svc + close """] + + self.pkg_list+= [""" + open basics@1.5,5.11-0 + add file """ + self.testdata_dir + """/empty mode=0677 owner=root group=sys path=/test_restart suspend_fmri=svc:system/test_suspend_svc disable_fmri=svc:system/test_disable_svc + close """] + + for f in self.misc_files: + filename = os.path.join(self.testdata_dir, f) + if not os.path.exists(os.path.dirname(filename)): + os.makedirs(os.path.dirname(filename)) + file_handle = open(filename, 'wb') + data = "self.%s_data" % os.path.basename(f) + file_handle.write(eval(data)) + file_handle.close() + os.chmod(filename, 0755) + + def tearDown(self): + testutils.SingleDepotTestCase.tearDown(self) + if self.testdata_dir: + shutil.rmtree(self.testdata_dir) + + def test_actuators(self): + """test actuators""" + + durl = self.dc.get_depot_url() + for pkg in self.pkg_list: + self.pkgsend_bulk(durl, pkg) + self.image_create(durl) + os.environ["PKG_TEST_DIR"] = self.testdata_dir + os.environ["PKG_SVCADM_EXIT_CODE"] = "0" + os.environ["PKG_SVCPROP_EXIT_CODE"] = "0" + + svcadm_output = os.path.join(self.testdata_dir, + "svcadm_arguments") + + # make it look like our test service is enabled + os.environ["PKG_SVCPROP_OUTPUT"] = "svcprop_enabled" + + # test to see if our test service is restarted on install + cmdstr = "--debug actuator_cmds_dir=%s" % self.testdata_dir + self.pkg(cmdstr + " install basics@1.0") + self.pkg("verify") + + self.file_contains(svcadm_output, "svcadm restart svc:system/test_restart_svc") + os.unlink(svcadm_output) + + # test to see if our test service is restarted on upgrade + cmdstr = "--debug actuator_cmds_dir=%s" % self.testdata_dir + self.pkg(cmdstr + " install basics@1.1") + self.pkg("verify") + self.file_contains(svcadm_output, "svcadm restart svc:system/test_restart_svc") + os.unlink(svcadm_output) + + # test to see if our test service is restarted on uninstall + self.pkg(cmdstr + " uninstall basics") + self.pkg("verify") + self.file_contains(svcadm_output, "svcadm restart svc:system/test_restart_svc") + os.unlink(svcadm_output) + + # make it look like our test service is not enabled + os.environ["PKG_SVCPROP_OUTPUT"] = "svcprop_disabled" + + # test to see to make sure we don't restart disabled service + cmdstr = "--debug actuator_cmds_dir=%s" % self.testdata_dir + self.pkg(cmdstr + " install basics@1.2") + self.pkg("verify") + self.file_does_not_exist(svcadm_output) + + # make it look like our test service(s) is/are enabled + os.environ["PKG_SVCPROP_OUTPUT"] = "svcprop_enabled" + + # test to see if refresh works as designed, along w/ restart + cmdstr = "--debug actuator_cmds_dir=%s" % self.testdata_dir + self.pkg(cmdstr + " install basics@1.3") + self.pkg("verify") + self.file_contains(svcadm_output, "svcadm restart svc:system/test_restart_svc") + self.file_contains(svcadm_output, "svcadm refresh svc:system/test_refresh_svc") + os.unlink(svcadm_output) + + # test if suspend works + cmdstr = "--debug actuator_cmds_dir=%s" % self.testdata_dir + self.pkg(cmdstr + " install basics@1.4") + self.pkg("verify") + self.file_contains(svcadm_output, "svcadm disable -t svc:system/test_suspend_svc") + self.file_contains(svcadm_output, "svcadm enable svc:system/test_suspend_svc") + os.unlink(svcadm_output) + + # test if suspend works properly w/ temp. enabled service + # make it look like our test service(s) is/are temp enabled + os.environ["PKG_SVCPROP_OUTPUT"] = "svcprop_temp_enabled" + cmdstr = "--debug actuator_cmds_dir=%s" % self.testdata_dir + self.pkg(cmdstr + " install basics@1.5") + self.pkg("verify") + self.file_contains(svcadm_output, "svcadm disable -t svc:system/test_suspend_svc") + self.file_contains(svcadm_output, "svcadm enable -t svc:system/test_suspend_svc") + os.unlink(svcadm_output) + + # test if service is disabled on uninstall + cmdstr = "--debug actuator_cmds_dir=%s" % self.testdata_dir + self.pkg(cmdstr + " uninstall basics") + self.pkg("verify") + self.file_contains(svcadm_output, "svcadm disable svc:system/test_disable_svc") + + def file_does_not_exist(self, path): + file_path = os.path.join(self.get_img_path(), path) + if os.path.exists(file_path): + self.assert_(False, "File %s exists" % path) + + def file_contains(self, path, string): + file_path = os.path.join(self.get_img_path(), path) + try: + f = file(file_path) + except: + self.assert_(False, "File %s does not exist or contain %s" % (path, string)) + + for line in f: + if string in line: + f.close() + break + else: + f.close() + self.assert_(False, "File %s does not contain %s" % (path, string)) + +if __name__ == "__main__": + unittest.main() diff -r fc856572d86e -r 22bc748edce6 src/tests/run.py diff -r fc856572d86e -r 22bc748edce6 src/util/distro-import/86/reboot --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/util/distro-import/86/reboot Fri Oct 10 22:15:14 2008 -0700 @@ -0,0 +1,6 @@ +# tag kernel binaries as needing reboot +chattr_glob kernel/* type file reboot_needed=true +chattr_glob kernel/*.conf type file reboot_needed=false +chattr_glob platform/* type file reboot_needed=true +chattr_glob platform/*.conf type file reboot_needed=false +# See SUNWcsl for tags for other libraries diff -r fc856572d86e -r 22bc748edce6 src/util/distro-import/86/smf_manifests --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/util/distro-import/86/smf_manifests Fri Oct 10 22:15:14 2008 -0700 @@ -0,0 +1,2 @@ +# make sure manifest changes are picked up +chattr_glob var/svc/manifest/*.xml type file restart_fmri=svc:/system/manifest-import:default diff -r fc856572d86e -r 22bc748edce6 src/util/distro-import/87/common/SUNWcsl --- a/src/util/distro-import/87/common/SUNWcsl Fri Oct 10 16:32:27 2008 -0700 +++ b/src/util/distro-import/87/common/SUNWcsl Fri Oct 10 22:15:14 2008 -0700 @@ -1,4 +1,12 @@ package SUNWcsl import SUNWcsl import SUNWcslr -end package +# tag libc as needing reboot for now; this will change +# when we handle overlay mounts correctly on x86 +# XXX work needed for SPARC +chattr lib/libc.so.1 reboot_needed=true +chattr lib/amd64/libc.so reboot_needed=true +chattr usr/lib/libc/libc_hwcap1.so.1 reboot_needed=true +chattr usr/lib/libc/libc_hwcap2.so.1 reboot_needed=true +chattr usr/lib/libc/libc_hwcap3.so.1 reboot_needed=true +end package diff -r fc856572d86e -r 22bc748edce6 src/util/distro-import/Makefile --- a/src/util/distro-import/Makefile Fri Oct 10 16:32:27 2008 -0700 +++ b/src/util/distro-import/Makefile Fri Oct 10 22:15:14 2008 -0700 @@ -43,7 +43,7 @@ TMPPKGS=SUNWfixes EXTRA_OPTIONS= -SOLARIS.PY=./solaris.py -b 0.$(BUILDID) $(EXTRA_OPTIONS) -T \*.py +SOLARIS.PY=./solaris.py -b 0.$(BUILDID) $(EXTRA_OPTIONS) -T \*.py -G smf_manifests -G reboot # # always remove the following (editable) files from packages we bulk import; diff -r fc856572d86e -r 22bc748edce6 src/util/distro-import/solaris.py --- a/src/util/distro-import/solaris.py Fri Oct 10 16:32:27 2008 -0700 +++ b/src/util/distro-import/solaris.py Fri Oct 10 22:15:14 2008 -0700 @@ -966,8 +966,14 @@ elif token == "end": endarg = lexer.get_token() if endarg == "package": - for f in global_includes: - SolarisParse(f) + for filename in global_includes: + for i in include_path: + f = os.path.join(i, filename) + if os.path.exists(f): + SolarisParse(f) + break + else: + raise RuntimeError, "File not found: %s" % filename try: end_package(curpkg) except Exception, e: