usr/src/lib/install_transfer/ips.py
changeset 1160 6f7e708c38ec
parent 1151 95413393ef67
child 1161 5c1b6d445efc
--- a/usr/src/lib/install_transfer/ips.py	Tue May 31 11:07:18 2011 -0700
+++ b/usr/src/lib/install_transfer/ips.py	Tue May 31 14:21:09 2011 -0700
@@ -106,7 +106,7 @@
     __metaclass__ = abc.ABCMeta
 
     # Variables associated with the package image
-    CLIENT_API_VERSION = 57
+    CLIENT_API_VERSION = 58
     DEF_REPO_URI = "http://pkg.opensolaris.org/release"
     DEF_PROG_TRACKER = progress.CommandLineProgressTracker()
 
@@ -301,7 +301,6 @@
             self.logger.debug("Image Type: zone")
 
         not_allowed = set(["prefix", "repo_uri", "origins", "mirrors"])
-        #img_args = set(self.image_args)
         img_args = set(self.image_args.keys())
         overlap = list(not_allowed & img_args)
         if overlap:
@@ -380,15 +379,52 @@
 
         # Add specified publishers/origins/mirrors to the image.
         for idx, element in enumerate(self._add_publ):
-            self.logger.debug("Adding additional publishers")
-            if self._add_mirror[idx]:
-                repo = publisher.Repository(mirrors=self._add_mirror[idx],
-                                            origins=self._add_origin[idx])
+            # If this publisher doesn't already exist, add it.
+            if not self.api_inst.has_publisher(prefix=element):
+                self.logger.debug("Adding additional publisher %s" % \
+                                  str(element))
+                if self._add_mirror[idx]:
+                    repo = publisher.Repository(mirrors=self._add_mirror[idx],
+                                                origins=self._add_origin[idx])
+                else:
+                    repo = publisher.Repository(origins=self._add_origin[idx])
+                pub = publisher.Publisher(prefix=element, repository=repo)
+                if not self.dry_run:
+                    self.api_inst.add_publisher(pub=pub, refresh_allowed=False)
+            # Else update the existing publisher with this spec
             else:
-                repo = publisher.Repository(origins=self._add_origin[idx])
-            pub = publisher.Publisher(prefix=element, repository=repo)
-            if not self.dry_run:
-                self.api_inst.add_publisher(pub=pub, refresh_allowed=False)
+                self.logger.debug("Updating publisher information for " \
+                                  "%s" % str(element))
+                pub = self.api_inst.get_publisher(prefix=element,
+                                                  duplicate=True)
+                repository = pub.repository
+                if self._add_origin[idx]:
+                    for origin in self._add_origin[idx]:
+                        if not repository.has_origin(origin):
+                            repository.add_origin(origin)
+                if self._add_mirror[idx]:
+                    for mirror in self._add_mirror[idx]:
+                        if not repository.has_mirror(mirror):
+                            repository.add_mirror(mirror)
+                self.api_inst.update_publisher(pub=pub, refresh_allowed=False)
+
+        # Get the publisher information of what the image is set with now.
+        # Re-set publisher_list to that list, so that it can be used later
+        # to be printed out
+        pub_list = self.api_inst.get_publishers(duplicate=True)
+        pub_list_for_print = list()
+        for pub in pub_list:
+            repo = pub.repository
+            origin_uris = list()
+            mirror_uris = list()
+            if repo.origins:
+                for origin in repo.origins:
+                    origin_uris.append(origin.uri)
+            if repo.mirrors:
+                for mirror in repo.mirrors:
+                    mirror_uris.append(mirror.uri)
+            pub_list_for_print.append((pub.prefix, origin_uris, mirror_uris))
+        self.publisher_list = pub_list_for_print
 
         if self.dry_run:
             self.logger.debug("Dry Run: publishers updated")
@@ -456,6 +492,12 @@
                         self.api_inst.execute_plan()
                         self.api_inst.reset()
 
+                        # The above call will end up leaving our process's cwd
+                        # in the image's root area, which will cause pain later
+                        # in trying to unmount the image.  So we manually
+                        # change dir back to "/".
+                        os.chdir("/")
+
                         # Release stdout and stderr
                         sys.stdout = tmp_stdout
                         sys.stderr = tmp_stderr
@@ -531,7 +573,9 @@
     def set_image_args(self):
         '''Set the image args we need set because the information
            was passed in via other attributes. These include progtrack,
-           prefix, repo_uri, origins, and mirrors.
+           prefix, repo_uri, origins, and mirrors.  If we're creating a
+           zone image, we also need to set the use-system-repo property
+           in the props argument.
         '''
         self._image_args = copy.copy(self.image_args)
         self._image_args["progtrack"] = self.prog_tracker
@@ -543,6 +587,13 @@
             self._image_args["origins"] = self._origin[1:]
         if self._mirror and self._mirror is not None:
             self._image_args["mirrors"] = self._mirror
+        if self.is_zone:
+            if self._image_args.has_key("props"):
+                props_dict = self._image_args["props"]
+                props_dict["use-system-repo"] = True
+            else:
+                props_dict = {"use-system-repo": True}
+                self._image_args["props"] = props_dict
 
     def get_ips_api_inst(self):
         '''Get a handle to the api instance. If it is specified to use
@@ -594,6 +645,13 @@
                     version_id=self.CLIENT_API_VERSION, root=self.dst,
                     imgtype=self.completeness, is_zone=self.is_zone,
                     force=True, **self._image_args)
+
+                # The above call will end up leaving our process's cwd in
+                # the image's root area, which will cause pain later on
+                # in tyring to unmount the image.  So we manually change
+                # dir back to "/".
+                os.chdir("/")
+
             except api_errors.VersionException, ips_err:
                 self.logger.exception("Error creating the IPS image")
                 raise ValueError("The IPS API version specified, "
@@ -696,21 +754,32 @@
         img_arg_list = dst_image.get_children(Args.ARGS_LABEL, Args)
 
         # If arguments were specified, validate that the
-        # user only specified them once.
+        # user only specified them once, and that they
+        # didn't specify arguments they're not allowed to.
         for args in img_arg_list:
-            self.image_args = args.arg_dict
             # ssl_key and ssl_cert are part of the image specification.
             # If the user has put them into the args that's an error
             # since we wouldn't know which one to use if they were
             # specified in both places.
             not_allowed = set(["ssl_key", "ssl_cert"])
-            img_args = set(self.image_args.keys())
-            overlap = list(not_allowed & img_args)
+            cur_img_args = set(args.arg_dict.keys())
+            overlap = list(not_allowed & cur_img_args)
             if overlap:
                 raise ValueError("The following components may be specified "
                                  "with the destination image of the manifest "
                                  "but are invalid as args: %s" % str(overlap))
 
+            # Check that the current set of image args being processed
+            # are not duplicates of one we've already processed.
+            image_args = set(self.image_args.keys())
+            overlap = list(image_args & cur_img_args)
+            if overlap:
+                raise ValueError("The following components are specified "
+                                 "twice in the manifest: %s" % str(overlap))
+
+            # Update the image args with the current image args being processed.
+            self.image_args.update(args.arg_dict)
+
         # Parse the transfer specific attributes.
         self._parse_transfer_node(soft_node)
 
@@ -825,17 +894,26 @@
             pub_list = src.get_children(Publisher.PUBLISHER_LABEL, Publisher,
                                         not_found_is_err=True)
 
-            # The first publisher is the preferred one.
-            pub = pub_list.pop(0)
-            self._set_publisher_info(pub, preferred=True)
+            # If we're not installing a zone image, the first publisher is
+            # treated as the preferred one (i.e. it's passed as arguments to
+            # the image_create() call); for a zone, all publishers should
+            # be processed as additional publishers since a zone image will
+            # be created with the system repository already in place.
+            if not self.is_zone:
+                pub = pub_list.pop(0)
+                self._set_publisher_info(pub, preferred=True)
             for pub in pub_list:
                 self._set_publisher_info(pub, preferred=False)
         else:
             if self.img_action != self.EXISTING:
                 # If the source isn't specified, use the defaults for create.
-                self._origin = [self.DEF_REPO_URI]
-                self.logger.debug("    Origin Info: %s", self.DEF_REPO_URI)
-                self._mirror = None
+                # For a zone image, the system repo will already be set up
+                # as the default repo so we don't need to set up a the default
+                # here if source isn't specified.
+                if not self.is_zone:
+                    self._origin = [self.DEF_REPO_URI]
+                    self.logger.debug("    Origin Info: %s", self.DEF_REPO_URI)
+                    self._mirror = None
 
 
 class TransferIPSAttr(AbstractIPS):