577 need service action for smf(5) manifests
578 need restart action or equivalent to poke smf(5) services
--- 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"]
--- /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
+
+
--- /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()
--- 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
--- 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
--- /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 [email protected],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 [email protected],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 [email protected],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 [email protected],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 [email protected],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 [email protected],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 [email protected]")
+ 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 [email protected]")
+ 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 [email protected]")
+ 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 [email protected]")
+ 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 [email protected]")
+ 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 [email protected]")
+ 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()
--- /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
--- /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
--- 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
--- 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;
--- 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: