smf_manifest.py revision 1933
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen# CDDL HEADER START
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen# The contents of this file are subject to the terms of the
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen# Common Development and Distribution License (the "License").
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen# You may not use this file except in compliance with the License.
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen# See the License for the specific language governing permissions
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen# and limitations under the License.
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen# When distributing Covered Code, include this CDDL HEADER in each
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen# If applicable, add the following below this CDDL HEADER, with the
dd0ba1bab2c1b89c7e063fa45d156fa72b8260d5Timo Sirainen# fields enclosed by brackets "[]" replaced with your own identifying
dd0ba1bab2c1b89c7e063fa45d156fa72b8260d5Timo Sirainen# information: Portions Copyright [yyyy] [name of copyright owner]
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen# CDDL HEADER END
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainenfrom pkg.portable import PD_LOCAL_PATH, PD_PROTO_DIR, PD_PROTO_DIR_LIST
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen# A list of locations beneath a given proto_dir where we expect to
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen# find SMF manifest files
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainenmanifest_locations = [ "lib/svc/manifest", "var/svc/manifest" ]
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenclass SMFManifestDependency(base.PublishingDependency):
df6478c4cf605bd81b3891c148b84c14eb6c4035Timo Sirainen # maps SMF fmris to the manifest files that defined them
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen # maps SMF FMRIs to a list the SMF FMRIs they declare as dependencies
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen def __init__(self, action, path, pkg_vars, proto_dir):
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen """ See __init__ for PublishingDependency.
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen base.PublishingDependency.__init__(self, action,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen base_names, paths, pkg_vars, proto_dir, "smf_manifest")
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen def populate_cache(proto_dirs, force_update=False):
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen """Build our instance_mf and instance_deps dictionaries
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen from the known SMF manifests installed on the current system
ee26329cb5cc679b5645e4933d529f86accb976aTimo Sirainen and those that appear in the proto_dirs.
e9f2d9104d395bcf54be3f8ba8d9f63aecf0bcbeTimo Sirainen # we want our proto_dirs to be the authoritative source
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen # for SMF manifests, so scan the local system first, then
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen # iterate through the proto_dirs, starting from the
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen # oldest, overwriting with progressively newer proto_dirs
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen manifest_paths.append(os.path.join("/", location))
6f73af3a3a6ee900c7e736874587968d76a20bc0Timo Sirainen """Add a information information about the SMF instances and
6f73af3a3a6ee900c7e736874587968d76a20bc0Timo Sirainen their dependencies from the given manifest_file to a global
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen set of dictionaries."""
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen instance_mf, instance_deps = parse_smf_manifest(
0f66f12eb4cdbf47670975044c88d8f388bf92dfTimo Sirainen # more work is needed here when
e9f2d9104d395bcf54be3f8ba8d9f63aecf0bcbeTimo Sirainen # multiple-manifests per service is supported by
e9f2d9104d395bcf54be3f8ba8d9f63aecf0bcbeTimo Sirainen # SMF: we'll need to merge additional
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen # service-level dependencies into each service
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen # instance as each manifest gets added.
d24daa83c25063ef12b524c9ffcc9ecca34dadb9Timo Sirainen """Split an SMF FMRI into constituent parts, returning the svc protocol,
d24daa83c25063ef12b524c9ffcc9ecca34dadb9Timo Sirainen the service name, and the instance name, if any."""
d24daa83c25063ef12b524c9ffcc9ecca34dadb9Timo Sirainen raise ValueError(_("FMRI does not appear to be valid"))
d24daa83c25063ef12b524c9ffcc9ecca34dadb9Timo Sirainen """Search a dictionary of SMF FMRI mappings, returning a list of
d24daa83c25063ef12b524c9ffcc9ecca34dadb9Timo Sirainen results. If the FMRI points to an instance, we can return quickly. If
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen the FMRI points to a service, we return all matching instances. Note
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen if the dictionary contains service FMRIs, those won't appear in the
b159b7fb9740b6e37238016d8395a351de498d50Timo Sirainen results - we only ever return instances."""
b159b7fb9740b6e37238016d8395a351de498d50Timo Sirainen protocol, service, instance = split_smf_fmri(fmri)
b159b7fb9740b6e37238016d8395a351de498d50Timo Sirainen if instance is not None:
b159b7fb9740b6e37238016d8395a351de498d50Timo Sirainen # return all matching instances of this service
b159b7fb9740b6e37238016d8395a351de498d50Timo Sirainen if item.startswith(protocol + ":" + service + ":"):
31050c3df6cbe403e8ced8ef11b5c4e12124d354Timo Sirainen """Given an instance FMRI, determine the FMRIs it depends on. If we
31050c3df6cbe403e8ced8ef11b5c4e12124d354Timo Sirainen match more than one fmri, we raise an exception. """
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen # this can only happen if we've been asked to resolve a
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen # service-level FMRI, not a fully qualified instance FMRI
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen _("more than one set of dependencies found: %s") % results)
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen results = search_smf_dic(fmri, SMFManifestDependency.instance_deps)
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen _("more than one set of dependencies found: %s") % results)
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen """Given an SMF FMRI that satisfies a given SMF dependency, determine
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen which file(s) deliver that dependency using both the provided
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen instance_mf dictionary and the global SmfManifestDependency dictionary.
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen If multiple files match, we have a problem."""
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainen manifests.update(search_smf_dic(fmri, instance_mf))
b159b7fb9740b6e37238016d8395a351de498d50Timo Sirainen # we can't satisfy the dependency at all
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen raise ValueError(_("cannot resolve FMRI to a delivered file"))
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen # instances satisfying the dependency are delivered by
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen # multiple files - we can't deal with this either
b159b7fb9740b6e37238016d8395a351de498d50Timo Sirainen _("FMRI is delivered by multiple files: %s") % manifests)
b159b7fb9740b6e37238016d8395a351de498d50Timo Sirainen # we should only ever have one element in our set at this point,
b159b7fb9740b6e37238016d8395a351de498d50Timo Sirainen # so doing a pop() is safe.
dc0474dc9d5652d76cb41f439844dd80c8b96642Timo Sirainendef process_smf_manifest_deps(action, pkg_vars, **kwargs):
b159b7fb9740b6e37238016d8395a351de498d50Timo Sirainen """Given an action and a place to find the file it references, if the
b159b7fb9740b6e37238016d8395a351de498d50Timo Sirainen file is an SMF manifest, we return a list of SmfManifestDependencies
b159b7fb9740b6e37238016d8395a351de498d50Timo Sirainen pointing to the SMF manifests in the proto area that would satisfy each
b159b7fb9740b6e37238016d8395a351de498d50Timo Sirainen dependency, a list of errors, and a dictionary containing the SMF FMRIs
cfbf891f065b18602703ed6fa2af1a541d4d0b04Timo Sirainen that were contained in the SMF manifest that this action delivers.
a2ec607689dc88112bf08785960e441153f35d57Timo Sirainen Note that while we resolve SMF dependencies from SMF FMRIs to the files
b159b7fb9740b6e37238016d8395a351de498d50Timo Sirainen that deliver them, we don't attempt to further resolve those files to
b159b7fb9740b6e37238016d8395a351de498d50Timo Sirainen pkg(5) packages at this point.
b159b7fb9740b6e37238016d8395a351de498d50Timo Sirainen That stage is done using the normal "pkgdepend resolve" mechanism."""
b159b7fb9740b6e37238016d8395a351de498d50Timo Sirainen [ _("%s actions cannot deliver SMF manifests") %
b159b7fb9740b6e37238016d8395a351de498d50Timo Sirainen # we don't report an error here, as SMF manifest files may be delivered
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen # to a location specifically not intended to be imported to the SMF
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen # repository.
a2ce2eb4c266e2854fd34416ea5cfbe05dfd3971Timo Sirainen if not has_smf_manifest_dir(action.attrs["path"]):
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return [], [], {}
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen SMFManifestDependency.populate_cache(action.attrs[PD_PROTO_DIR_LIST])
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen instance_mf, instance_deps = parse_smf_manifest(proto_file)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return [], [ _("Unable to parse SMF manifest %s") %
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen protocol, service, instance = split_smf_fmri(fmri)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen # we're only interested in trying to resolve
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen # dependencies that instances have declared
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen elist.append(_("Problem resolving %(fmri)s: %(err)s") %
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen # determine the set of SMF FMRIs we depend on
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen _("Problem determining dependencies for %(fmri)s:"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen # determine the file paths that deliver those dependencies
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen # we've declared an SMF dependency, but can't
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen # determine what file delivers it from the known
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen # SMF manifests in either the proto area or the
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen # local machine.
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen _("Unable to generate SMF dependency on "
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen "%(dep_fmri)s declared in %(proto_file)s by"
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen deps.append(SMFManifestDependency(action, manifest, pkg_vars,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen """Given a minidom Element deps, search for the <service_fmri> elements
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen inside it, and return the values as a list of strings."""
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen fmris = dependency.getElementsByTagName("service_fmri")
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen grouping = dependency.getAttribute("grouping")
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen # we don't include SMF path dependencies as these are often
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen # not packaged files.
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen dependency = service_fmri.getAttribute("value")
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen """Quickly determine if smf_file is a valid SMF manifest."""
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen # catching ValueError, as minidom has been seen to raise this on some
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen # invalid XML files.
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen except (xml.parsers.expat.ExpatError, ValueError):
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen "/usr/share/lib/xml/dtd/service_bundle.dtd.1":
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen """Returns a tuple of two dictionaries. The first maps the SMF FMRIs
1f6653c23f792401623734d783ede1653ba65436Timo Sirainen found in that manifest to the path of the manifest file. The second maps
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen each SMF FMRI found in the file to the list of FMRIs that are declared
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen as dependencies.
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen Note this method makes no distinction between service FMRIs and instance
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen FMRIs; both get added to the dictionaries, but only the instance FMRIs
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen should be used to determine dependencies.
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen Calling this with a path to the file, we include manifest_paths in the
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen first dictionary, otherwise with raw file data, we don't.
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen If we weren't handed an SMF XML file, or have trouble parsing it, we
2623ed55e5bc547363abc7bc9de6b4ad2c53e531Timo Sirainen return a tuple of None, None.
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen # catching ValueError, as minidom has been seen to raise this on some
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen # invalid XML files.
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen except (xml.parsers.expat.ExpatError, ValueError):
6cd02a9525acb9897a65b05bfeee9b8d283e0f74Timo Sirainen return None, None
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen return None, None
b30499429feee4f16f1e09c7047101dc7ff38304Timo Sirainen "/usr/share/lib/xml/dtd/service_bundle.dtd.1":
b30499429feee4f16f1e09c7047101dc7ff38304Timo Sirainen return None, None
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen svcs = smf_doc.getElementsByTagName("service")
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen # get the service name
e37fbcda56ab154557e84f990012502be53aa6c6Timo Sirainen # no defined service name, so no dependencies here
0a51697f82fbd45a511710479e99efd42dc18453Timo Sirainen # Get the FMRIs we declare dependencies on. When splitting SMF
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen # services across multiple manifests is supported, more work
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen # will be needed here.
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen svc_dependencies.extend(__get_smf_dependencies(svc_deps))
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen # determine our instances
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if service.getElementsByTagName("create_default_instance"):
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen insts = service.getElementsByTagName("instance")
b30499429feee4f16f1e09c7047101dc7ff38304Timo Sirainen # we've declared a
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen # create_default_instance tag but we've
b30499429feee4f16f1e09c7047101dc7ff38304Timo Sirainen # also explicitly created an instance
b30499429feee4f16f1e09c7047101dc7ff38304Timo Sirainen # called "default"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen # we can use getElementsByTagName here, since
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen # there are no nested <dependency> tags that
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen # won't apply, unlike for <service> above, when
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen # we needed to look strictly at immediate
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen "dependency")
cfbb3ff45d6bd27e6442e332fa69c43c984ca651Timo Sirainen if fmri is not None:
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen # add the service FMRI
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen instance_deps["svc:%s" % svc_name] = svc_dependencies
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen """Determine if the given path string contains any of the directories
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen where SMF manifests are usually delivered. An optional named parameter
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen prefix gets stripped from the path before checking.