Print this page
OS-200 need a better mechanism for storing persistent zone_did
Small comment-out because we don't include OS-200
OS-4019 zoneadm is slow with 1000s of zones
OS-3524 in order to support interaction with docker containers, need to be able to connect to stdio for init from GZ
OS-3525 in order to support 'docker logs' need to be able to get stdio from zone to log file
OS-3429 Expose zone's init exit status
OS-399 zone phys. mem. cap should be a rctl and have associated kstat

@@ -21,10 +21,11 @@
 
 /*
  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
  * Copyright (c) 2015 by Delphix. All rights reserved.
+ * Copyright 2015, Joyent Inc. All rights reserved.
  */
 
 /*
  * zoneadm is a command interpreter for zone administration.  It is all in
  * C (i.e., no lex/yacc), and all the argument passing is argc/argv based.

@@ -99,10 +100,11 @@
         zone_state_t    zstate_num;
         char            zbrand[MAXNAMELEN];
         char            zroot[MAXPATHLEN];
         char            zuuid[UUID_PRINTABLE_STRING_LENGTH];
         zone_iptype_t   ziptype;
+        zoneid_t        zdid;
 } zone_entry_t;
 
 #define CLUSTER_BRAND_NAME      "cluster"
 
 static zone_entry_t *zents;

@@ -441,10 +443,11 @@
                     ZONEID_WIDTH, "ID", "NAME", "STATUS", "PATH", "BRAND",
                     "IP");
         }
         if (!verbose) {
                 char *cp, *clim;
+                char zdid[80];
 
                 if (!parsable) {
                         (void) printf("%s\n", zent->zname);
                         return;
                 }

@@ -456,12 +459,16 @@
                 cp = zent->zroot;
                 while ((clim = strchr(cp, ':')) != NULL) {
                         (void) printf("%.*s\\:", clim - cp, cp);
                         cp = clim + 1;
                 }
-                (void) printf("%s:%s:%s:%s\n", cp, zent->zuuid, zent->zbrand,
-                    ip_type_str);
+                if (zent->zdid == -1)
+                        zdid[0] = '\0';
+                else
+                        (void) snprintf(zdid, sizeof (zdid), "%d", zent->zdid);
+                (void) printf("%s:%s:%s:%s:%s\n", cp, zent->zuuid, zent->zbrand,
+                    ip_type_str, zdid);
                 return;
         }
         if (zent->zstate_str != NULL) {
                 if (zent->zid == ZONE_ID_UNDEFINED)
                         (void) printf("%*s", ZONEID_WIDTH, "-");

@@ -552,10 +559,26 @@
         if (zid == GLOBAL_ZONEID) {
                 zent->ziptype = ZS_SHARED;
                 return (Z_OK);
         }
 
+        if ((handle = zonecfg_init_handle()) == NULL) {
+                zperror2(zent->zname, gettext("could not init handle"));
+                return (Z_ERR);
+        }
+        if ((err = zonecfg_get_handle(zent->zname, handle)) != Z_OK) {
+                zperror2(zent->zname, gettext("could not get handle"));
+                zonecfg_fini_handle(handle);
+                return (Z_ERR);
+        }
+
+        if ((err = zonecfg_get_iptype(handle, &zent->ziptype)) != Z_OK) {
+                zperror2(zent->zname, gettext("could not get ip-type"));
+                zonecfg_fini_handle(handle);
+                return (Z_ERR);
+        }
+
         /*
          * There is a race condition where the zone could boot while
          * we're walking the index file.  In this case the zone state
          * could be seen as running from the call above, but the zoneid
          * would be undefined.

@@ -572,30 +595,16 @@
                     sizeof (flags)) >= 0) {
                         if (flags & ZF_NET_EXCL)
                                 zent->ziptype = ZS_EXCLUSIVE;
                         else
                                 zent->ziptype = ZS_SHARED;
-                        return (Z_OK);
                 }
         }
 
-        if ((handle = zonecfg_init_handle()) == NULL) {
-                zperror2(zent->zname, gettext("could not init handle"));
-                return (Z_ERR);
-        }
-        if ((err = zonecfg_get_handle(zent->zname, handle)) != Z_OK) {
-                zperror2(zent->zname, gettext("could not get handle"));
-                zonecfg_fini_handle(handle);
-                return (Z_ERR);
-        }
+        zent->zdid = zonecfg_get_did(handle);
 
-        if ((err = zonecfg_get_iptype(handle, &zent->ziptype)) != Z_OK) {
-                zperror2(zent->zname, gettext("could not get ip-type"));
                 zonecfg_fini_handle(handle);
-                return (Z_ERR);
-        }
-        zonecfg_fini_handle(handle);
 
         return (Z_OK);
 }
 
 /*

@@ -764,22 +773,26 @@
 
 /*
  * Retrieve a zone entry by name.  Returns NULL if no such zone exists.
  */
 static zone_entry_t *
-lookup_running_zone(const char *str)
+lookup_running_zone(const char *name)
 {
-        int i;
+        zoneid_t zid;
+        zone_entry_t *zent;
 
-        if (fetch_zents() != Z_OK)
+        if ((zid = getzoneidbyname(name)) == -1)
                 return (NULL);
 
-        for (i = 0; i < nzents; i++) {
-                if (strcmp(str, zents[i].zname) == 0)
-                        return (&zents[i]);
-        }
+        if ((zent = malloc(sizeof (zone_entry_t))) == NULL)
         return (NULL);
+
+        if (lookup_zone_info(name, zid, zent) != Z_OK) {
+                free(zent);
+                return (NULL);
+        }
+        return (zent);
 }
 
 /*
  * Check a bit in a mode_t: if on is B_TRUE, that bit should be on; if
  * B_FALSE, it should be off.  Return B_TRUE if the mode is bad (incorrect).

@@ -2781,10 +2794,65 @@
                 return_code = Z_ERR;
 
         return (return_code);
 }
 
+/*
+ * Called when readying or booting a zone.  We double check that the zone's
+ * debug ID is set and is unique.  This covers the case of pre-existing zones
+ * with no ID.  Also, its possible that a zone was migrated to this host
+ * and as a result it has a duplicate ID.  In this case we preserve the ID
+ * of the first zone we match on in the index file (since it was there before
+ * the current zone) and we assign a new unique ID to the current zone.
+ * Return true if we assigned a new ID, indicating that the zone configuration
+ * needs to be saved.
+ */
+static boolean_t
+verify_fix_did(zone_dochandle_t handle)
+{
+        zoneid_t mydid;
+        zone_entry_t zent;
+        FILE *cookie;
+        char *name;
+        boolean_t fix = B_FALSE;
+
+        mydid = zonecfg_get_did(handle);
+        if (mydid == -1) {
+                zonecfg_set_did(handle);
+                return (B_TRUE);
+        }
+
+        /* Get the full list of zones from the configuration. */
+        cookie = setzoneent();
+        while ((name = getzoneent(cookie)) != NULL) {
+                if (strcmp(target_zone, name) == 0) {
+                        free(name);
+                        break;  /* Once we find our entry, stop. */
+                }
+
+                if (strcmp(name, "global") == 0 ||
+                    lookup_zone_info(name, ZONE_ID_UNDEFINED, &zent) != Z_OK) {
+                        free(name);
+                        continue;
+                }
+
+                free(name);
+                if (zent.zdid == mydid) {
+                        fix = B_TRUE;
+                        break;
+                }
+        }
+        endzoneent(cookie);
+
+        if (fix) {
+                zonecfg_set_did(handle);
+                return (B_TRUE);
+        }
+
+        return (B_FALSE);
+}
+
 static int
 verify_details(int cmd_num, char *argv[])
 {
         zone_dochandle_t handle;
         char zonepath[MAXPATHLEN], checkpath[MAXPATHLEN];

@@ -2840,10 +2908,22 @@
         }
 
         if (verify_handle(cmd_num, handle, argv) != Z_OK)
                 return_code = Z_ERR;
 
+        if (cmd_num == CMD_READY || cmd_num == CMD_BOOT) {
+                int vcommit = 0, obscommit = 0;
+
+                vcommit = verify_fix_did(handle);
+                obscommit = zonecfg_fix_obsolete(handle);
+
+                if (vcommit || obscommit)
+                        if (zonecfg_save(handle) != Z_OK)
+                                (void) fprintf(stderr, gettext("Could not save "
+                                    "updated configuration.\n"));
+        }
+
         zonecfg_fini_handle(handle);
         if (return_code == Z_ERR)
                 (void) fprintf(stderr,
                     gettext("%s: zone %s failed to verify\n"),
                     execname, target_zone);

@@ -3863,14 +3943,14 @@
                         /*
                          * The SUNWattached.xml file is expected since it might
                          * exist if the zone was force-attached after a
                          * migration.
                          */
-        char            *std_entries[] = {"dev", "lu", "root",
-                            "SUNWattached.xml", NULL};
-                        /* (MAXPATHLEN * 3) is for the 3 std_entries dirs */
-        char            cmdbuf[sizeof (RMCOMMAND) + (MAXPATHLEN * 3) + 64];
+        char            *std_entries[] = {"dev", "lastexited", "logs", "lu",
+                            "root", "SUNWattached.xml", NULL};
+                        /* (MAXPATHLEN * 5) is for the 5 std_entries dirs */
+        char            cmdbuf[sizeof (RMCOMMAND) + (MAXPATHLEN * 5) + 64];
 
         /*
          * We shouldn't need these checks but lets be paranoid since we
          * could blow away the whole system here if we got the wrong zonepath.
          */

@@ -5373,11 +5453,11 @@
         int err;
         int res = Z_OK;
         priv_set_t *privset;
         zoneid_t zoneid;
         zone_dochandle_t handle;
-        struct zone_mcaptab mcap;
+        uint64_t mcap;
         char pool_err[128];
 
         zoneid = getzoneid();
 
         if (zonecfg_in_alt_root() || zoneid != GLOBAL_ZONEID ||

@@ -5464,23 +5544,16 @@
                         }
                 }
         }
 
         /*
-         * If a memory cap is configured, set the cap in the kernel using
-         * zone_setattr() and make sure the rcapd SMF service is enabled.
+         * If a memory cap is configured, make sure the rcapd SMF service is
+         * enabled.
          */
-        if (zonecfg_getmcapent(handle, &mcap) == Z_OK) {
-                uint64_t num;
+        if (zonecfg_get_aliased_rctl(handle, ALIAS_MAXPHYSMEM, &mcap) == Z_OK) {
                 char smf_err[128];
 
-                num = (uint64_t)strtoll(mcap.zone_physmem_cap, NULL, 10);
-                if (zone_setattr(zoneid, ZONE_ATTR_PHYS_MCAP, &num, 0) == -1) {
-                        zerror(gettext("could not set zone memory cap"));
-                        res = Z_ERR;
-                }
-
                 if (zonecfg_enable_rcapd(smf_err, sizeof (smf_err)) != Z_OK) {
                         zerror(gettext("enabling system/rcap service failed: "
                             "%s"), smf_err);
                         res = Z_ERR;
                 }