예제 #1
0
    def create(self, dry_run):
        """ create - method to create, newfs and mount a lofi device
        """
        # create the ramdisk (if needed)
        self.create_ramdisk(dry_run)

        # create the lofi device
        cmd = [LOFIADM, "-a", self.ramdisk]
        if not dry_run:
            p = Popen.check_call(cmd,
                                 stdout=Popen.STORE,
                                 stderr=Popen.STORE,
                                 logger=ILN)
            self.lofi_device = p.stdout.strip()

        # newfs it
        cmd = [NEWFS, "-m", "0", "-o", "space"]
        if self.nbpi is not None:
            cmd.append("-i")
            cmd.append(str(self.nbpi))
        cmd.append(self.lofi_device.replace("lofi", "rlofi"))
        if not dry_run:
            # due to the way Popen works, we can not assign a logger to the
            # call, otherwise the process will complete before we can pass the
            # "y" to newfs
            logger = logging.getLogger(ILN)
            logger.debug("Executing: %s" % " ".join(cmd))
            p = Popen(cmd,
                      stdin=Popen.PIPE,
                      stdout=Popen.DEVNULL,
                      stderr=Popen.DEVNULL)
            p.communicate("y\n")

        # ensure a directory exists to mount the lofi device to
        if not os.path.exists(self.mountpoint) and not dry_run:
            os.makedirs(self.mountpoint)

        cmd = [
            MOUNT, "-F", "ufs", "-o", "rw", self.lofi_device, self.mountpoint
        ]
        if not dry_run:
            Popen.check_call(cmd,
                             stdout=Popen.STORE,
                             stderr=Popen.STORE,
                             logger=ILN)
        self.mounted = True
예제 #2
0
    def create(self, dry_run):
        """ create - method to create, newfs and mount a lofi device
        """
        # create the ramdisk (if needed)
        self.create_ramdisk(dry_run)

        # create the lofi device
        cmd = [LOFIADM, "-a", self.ramdisk]
        if not dry_run:
            p = Popen.check_call(cmd, stdout=Popen.STORE, stderr=Popen.STORE,
                                 logger=ILN)
            self.lofi_device = p.stdout.strip()

        # newfs it
        cmd = [NEWFS, "-m", "0", "-o", "space"]
        if self.nbpi is not None:
            cmd.append("-i")
            cmd.append(str(self.nbpi))
        cmd.append(self.lofi_device.replace("lofi", "rlofi"))
        if not dry_run:
            # due to the way Popen works, we can not assign a logger to the
            # call, otherwise the process will complete before we can pass the
            # "y" to newfs
            logger = logging.getLogger(ILN)
            logger.debug("Executing: %s" % " ".join(cmd))
            p = Popen(cmd, stdin=Popen.PIPE, stdout=Popen.DEVNULL,
                      stderr=Popen.DEVNULL)
            p.communicate("y\n")

        # ensure a directory exists to mount the lofi device to
        if not os.path.exists(self.mountpoint) and not dry_run:
            os.makedirs(self.mountpoint)

        cmd = [MOUNT, "-F", "ufs", "-o", "rw", self.lofi_device,
               self.mountpoint]
        if not dry_run:
            Popen.check_call(cmd, stdout=Popen.STORE, stderr=Popen.STORE,
                             logger=ILN)
        self.mounted = True
    def test_devnull(self):
        '''Test using Popen.DEVNULL for stdin'''
        popen = Popen(["/usr/bin/cat"], stdin=Popen.DEVNULL, stdout=Popen.PIPE)
        # Use PIPE for stdout as, for a failure case, the subprocess call
        # could hang indefinitely, so we can't block on it

        for wait_count in xrange(10):
            # If it's not done nearly instantly, something is wrong.
            # However, give the benefit of the doubt by waiting up to
            # 5 seconds for completion
            if popen.poll() is not None:
                break
            else:
                time.sleep(0.5)
        else:
            popen.kill()
            self.fail("stdin=Popen.DEVNULL did not work")

        stdout = popen.communicate()[0]
        self.assertEqual("", stdout)
    def test_devnull(self):
        '''Test using Popen.DEVNULL for stdin'''
        popen = Popen(["/usr/bin/cat"], stdin=Popen.DEVNULL, stdout=Popen.PIPE)
        # Use PIPE for stdout as, for a failure case, the subprocess call
        # could hang indefinitely, so we can't block on it

        for wait_count in xrange(10):
            # If it's not done nearly instantly, something is wrong.
            # However, give the benefit of the doubt by waiting up to
            # 5 seconds for completion
            if popen.poll() is not None:
                break
            else:
                time.sleep(0.5)
        else:
            popen.kill()
            self.fail("stdin=Popen.DEVNULL did not work")

        stdout = popen.communicate()[0]
        self.assertEqual("", stdout)
예제 #5
0
    # Generate incorporation pkg
    incorp_pkg_name = "pkg://%s/%s@%s" % \
        (args.publisher, INCORP_NAME, incorp_version)

    dep_pkg_name = "%s@%s" % (AI_PKG_NAME, ai_pkg_version)

    # Generate the manifest
    manifest = ('set name=pkg.fmri value=%(incorppkg)s\n'
                'depend type=incorporate fmri=%(depname)s'
                % {'incorppkg': incorp_pkg_name, 'depname': dep_pkg_name})

    print "\nManifest contents:\n%s" % manifest
    print "\nPublishing %s" % incorp_pkg_name
    cmd = [PKGSEND, "-s", args.repo, "publish"]
    pkgsend = Popen(cmd, stdin=Popen.PIPE, stdout=Popen.PIPE,
                    stderr=Popen.PIPE)
    stdout, stderr = pkgsend.communicate(manifest)
    if stderr.strip() or pkgsend.returncode:
        pkgsend.stdout = stdout
        pkgsend.stderr = stderr
        raise CalledProcessError(pkgsend.returncode, cmd, popen=pkgsend)
    else:
        print stdout.strip()

    # Refresh the repository
    cmd = [PKGREPO, "-s", args.repo, "refresh"]
    run(cmd)

    print "Finished at " + time.asctime()
예제 #6
0
    def execute(self, dry_run=False):
        '''Validate script and then run it.'''

        script_name = os.path.abspath(self.dmd.script)

        # Verify type of script.  Assumes this module is being run with enough
        # privilege to read the script.
        linecache.checkcache(script_name)
        first_line = linecache.getline(script_name, 1)
        if (first_line == ""):
            errmsg = (MSG_HEADER + "Error opening scriptfile %s" % script_name)
            self.logger.critical(errmsg)
            raise DMMScriptAccessError(errmsg)

        # Look for appropriate shebang line to denote a supported script.
        # Note their appearance may have "/usr" prepended to them.
        first_line = first_line.strip()
        if not first_line.startswith("#!"):
            errmsg = (
                MSG_HEADER +
                'File %s: first line does not start with "#!".' % script_name)
            self.logger.critical(errmsg)
            raise DMMScriptInvalidError(errmsg)

        # Verify accessibility of script.

        # Owner must be aiuser, or file mode must include o+rx.
        script_stat = os.stat(script_name)
        mode = stat.S_IMODE(script_stat.st_mode)

        self.logger.info(MSG_HEADER + "Script to run: " + script_name)
        self.logger.info(MSG_HEADER +
                         "script mode is 0%o, uid is %d, gid is %d\n" %
                         (mode, script_stat.st_uid, script_stat.st_gid))
        self.logger.info(MSG_HEADER +
                         "Script validated.  Running in subprocess...")

        # Verify that the aiuser can access the script.
        cmdlist = [
            SU, AIUSER_ACCOUNT_NAME, "-c",
            TEST + " -r " + script_name + " -a -x " + script_name
        ]
        try:
            Popen.check_call(cmdlist)
        except CalledProcessError:
            errmsg = MSG_HEADER + \
                "Error accessing Derived Manifest script as aiuser"
            self.logger.critical(errmsg)
            raise DMMScriptInvalidError(errmsg)

        cmdlist = [SU, AIUSER_ACCOUNT_NAME, "-c", script_name]
        subproc = Popen(cmdlist,
                        stderr=Popen.STDOUT,
                        stdout=Popen.PIPE,
                        preexec_fn=self.subproc_env_setup)

        self.logger.info(MSG_HEADER + "script output follows: ")

        outerr, dummy = subproc.communicate()
        while (subproc.returncode is None):
            outerr = outerr.split("\n")
            for line in outerr:
                self.logger.info("> " + line)
            outerr, dummy = subproc.communicate()

        outerr = outerr.split("\n")
        for line in outerr:
            self.logger.info("> " + line)

        self.logger.info(MSG_HEADER + "aimanifest logfile output follows: ")
        try:
            with open(self.aim_logfile, 'r') as aim_log:
                for line in aim_log:
                    self.logger.info(">> " + line.strip())
        except (OSError, IOError) as err:
            self.logger.error("Error reading aimanifest logfile: %s:%s" %
                              (err.filename, err.strerror))

        try:
            os.unlink(self.aim_logfile)
        except OSError as err:
            self.logger.warning("MSG_HEADER: Warning: Could not delete "
                                "aimanifest logfile %s: %s" %
                                (self.aim_logfile, err.strerror))

        if subproc.returncode < 0:
            # Would be nice to convert number to signal string, but no
            # facility for this exists in python.
            errmsg = (
                MSG_HEADER +
                "Script was terminated by signal %d" % -subproc.returncode)
        elif subproc.returncode > 0:
            # Note: can't get 128 or 129 (as can be returned by a shell when it
            # cannot access or run a script) because that has already been
            # checked for.
            errmsg = (MSG_HEADER + "Script \"" + self.dmd.script + \
                    "\" terminated on error.")
        if subproc.returncode != 0:
            self.logger.critical(errmsg)
            raise DMMExecutionError(errmsg)
        else:
            self.logger.info(MSG_HEADER + "script completed successfully")

        # Try to validate against a schema specified in the manifest DOCTYPE
        # header, if it is there.  Else fallback to a hardwired default.
        try:
            tree = etree.parse(self.mpd.manifest)
        except etree.XMLSyntaxError as err:
            self.logger.critical(MSG_HEADER + "Error parsing final manifest")
            self.logger.critical(str(err))
            errmsg = MSG_HEADER + "Final manifest failed XML validation"
            self.logger.critical(errmsg)
            raise DMMValidationError(errmsg)

        if ((tree.docinfo is not None)
                and (tree.docinfo.system_url is not None)
                and os.access(tree.docinfo.system_url, os.R_OK)):
            dtd = tree.docinfo.system_url
            self.logger.info(MSG_HEADER + "Using DTD from header of manifest.")
        else:
            dtd = SYS_AI_MANIFEST_DTD
            self.logger.info(MSG_HEADER + "Manifest header refers to no DTD.")
        self.logger.info(MSG_HEADER + "Validating against DTD: %s" % dtd)

        try:
            validate_manifest(tree, dtd, self.logger)
        except (ManifestError) as err:
            # Note: validate_manifest already logged the errors.
            errmsg = MSG_HEADER + "Final manifest failed XML validation"
            self.logger.critical(errmsg)
            raise DMMValidationError(errmsg)
        else:
            self.logger.info(MSG_HEADER +
                             "XML validation completed successfully ")
예제 #7
0
    def create_repository(self):
        """ class method to create the repository
        """
        self.logger.info("Creating repository")

        # Create the repository (as needed) if it's a local path (no scheme)
        # or file:/// scheme.
        scheme = urlparse.urlsplit(self.pkg_repo).scheme
        if scheme in ("file", ""):
            # Try to create the repo (it may already exist)
            cmd = [cli.PKGREPO, "create", self.pkg_repo]
            repo = run(cmd, check_result=Popen.ANY)

            if repo.returncode == 0:
                # New repo was created. Add the publisher and make it default
                cmd = [
                    cli.PKGREPO, "-s", self.pkg_repo, "add-publisher",
                    self.publisher
                ]
                run(cmd)
                cmd = [
                    cli.PKGREPO, "-s", self.pkg_repo, "set",
                    "publisher/prefix=%s" % self.publisher
                ]
                run(cmd)

        # Generate a manifest file
        cmd = [cli.PKGSEND, "generate", self.pkg_img_path]
        generate = run(cmd)
        manifest = [generate.stdout]

        manifest.append('license lic_OTN license=lic_OTN must-accept=true\n')
        manifest.append('set name=pkg.summary '
                        'value="Automated Installation boot image"\n')
        manifest.append("set name=org.opensolaris.consolidation "
                        "value=install\n")
        manifest.append('set name=info.classification '
                        'value="org.opensolaris.category.2008:'
                        'System/Administration and Configuration"\n')
        arch = platform.processor()
        manifest.append("set name=variant.arch value=%s\n" % arch)
        manifest.append("set name=%s value=%s variant.arch=%s\n" %
                        (self.SVC_NAME_ATTR, self.service_name, arch))
        manifest.append("set name=pkg.fmri value=%s\n" % self.pkg_name)
        manifest.append("depend fmri=pkg:/system/core-os type=exclude\n")
        manifest = "".join(manifest)

        self.logger.info("Publishing %s", self.pkg_name)
        cmd = [
            cli.PKGSEND, "-s", self.pkg_repo, "publish", "-d",
            self.pkg_img_path, "-d", self.tmp_dir
        ]
        pkgsend = Popen(cmd,
                        stdin=Popen.PIPE,
                        stdout=Popen.PIPE,
                        stderr=Popen.PIPE)
        stdout, stderr = pkgsend.communicate(manifest)
        if stderr.strip() or pkgsend.returncode:
            pkgsend.stdout = stdout
            pkgsend.stderr = stderr
            raise CalledProcessError(pkgsend.returncode, cmd, popen=pkgsend)
        else:
            self.logger.info(stdout.strip())
예제 #8
0
    def execute(self, dry_run=False):
        '''Validate script and then run it.'''

        script_name = os.path.abspath(self.dmd.script)

        # Verify type of script.  Assumes this module is being run with enough
        # privilege to read the script.
        linecache.checkcache(script_name)
        first_line = linecache.getline(script_name, 1)
        if (first_line == ""):
            errmsg = (MSG_HEADER + "Error opening scriptfile %s" % script_name)
            self.logger.critical(errmsg)
            raise DMMScriptAccessError(errmsg)

        # Look for appropriate shebang line to denote a supported script.
        # Note their appearance may have "/usr" prepended to them.
        first_line = first_line.strip()
        if not first_line.startswith("#!"):
            errmsg = (MSG_HEADER +
                      'File %s: first line does not start with "#!".' %
                      script_name)
            self.logger.critical(errmsg)
            raise DMMScriptInvalidError(errmsg)

        # Verify accessibility of script.

        # Owner must be aiuser, or file mode must include o+rx.
        script_stat = os.stat(script_name)
        mode = stat.S_IMODE(script_stat.st_mode)

        self.logger.info(MSG_HEADER + "Script to run: " + script_name)
        self.logger.info(MSG_HEADER +
                         "script mode is 0%o, uid is %d, gid is %d\n" %
                         (mode, script_stat.st_uid, script_stat.st_gid))
        self.logger.info(MSG_HEADER +
                         "Script validated.  Running in subprocess...")

        # Verify that the aiuser can access the script.
        cmdlist = [SU, AIUSER_ACCOUNT_NAME, "-c",
                   TEST + " -r " + script_name + " -a -x " + script_name]
        try:
            Popen.check_call(cmdlist)
        except CalledProcessError:
            errmsg = MSG_HEADER + \
                "Error accessing Derived Manifest script as aiuser"
            self.logger.critical(errmsg)
            raise DMMScriptInvalidError(errmsg)

        cmdlist = [SU, AIUSER_ACCOUNT_NAME, "-c", script_name]
        subproc = Popen(cmdlist, stderr=Popen.STDOUT, stdout=Popen.PIPE,
                        preexec_fn=self.subproc_env_setup)

        self.logger.info(MSG_HEADER + "script output follows: ")

        outerr, dummy = subproc.communicate()
        while (subproc.returncode is None):
            outerr = outerr.split("\n")
            for line in outerr:
                self.logger.info("> " + line)
            outerr, dummy = subproc.communicate()

        outerr = outerr.split("\n")
        for line in outerr:
            self.logger.info("> " + line)

        self.logger.info(MSG_HEADER + "aimanifest logfile output follows: ")
        try:
            with open(self.aim_logfile, 'r') as aim_log:
                for line in aim_log:
                    self.logger.info(">> " + line.strip())
        except (OSError, IOError) as err:
            self.logger.error("Error reading aimanifest logfile: %s:%s" %
                              (err.filename, err.strerror))

        try:
            os.unlink(self.aim_logfile)
        except OSError as err:
            self.logger.warning("MSG_HEADER: Warning: Could not delete "
                                "aimanifest logfile %s: %s" %
                                (self.aim_logfile, err.strerror))

        if subproc.returncode < 0:
            # Would be nice to convert number to signal string, but no
            # facility for this exists in python.
            errmsg = (MSG_HEADER +
                      "Script was terminated by signal %d" %
                      -subproc.returncode)
        elif subproc.returncode > 0:
            # Note: can't get 128 or 129 (as can be returned by a shell when it
            # cannot access or run a script) because that has already been
            # checked for.
            errmsg = (MSG_HEADER + "Script \"" + self.dmd.script + \
                    "\" terminated on error.")
        if subproc.returncode != 0:
            self.logger.critical(errmsg)
            raise DMMExecutionError(errmsg)
        else:
            self.logger.info(MSG_HEADER + "script completed successfully")

        # Try to validate against a schema specified in the manifest DOCTYPE
        # header, if it is there.  Else fallback to a hardwired default.
        try:
            tree = etree.parse(self.mpd.manifest)
        except etree.XMLSyntaxError as err:
            self.logger.critical(MSG_HEADER + "Error parsing final manifest")
            self.logger.critical(str(err))
            errmsg = MSG_HEADER + "Final manifest failed XML validation"
            self.logger.critical(errmsg)
            raise DMMValidationError(errmsg)

        if ((tree.docinfo is not None) and
            (tree.docinfo.system_url is not None) and
            os.access(tree.docinfo.system_url, os.R_OK)):
            dtd = tree.docinfo.system_url
            self.logger.info(MSG_HEADER + "Using DTD from header of manifest.")
        else:
            dtd = SYS_AI_MANIFEST_DTD
            self.logger.info(MSG_HEADER + "Manifest header refers to no DTD.")
        self.logger.info(MSG_HEADER + "Validating against DTD: %s" % dtd)

        try:
            validate_manifest(tree, dtd, self.logger)
        except (ManifestError) as err:
            # Note: validate_manifest already logged the errors.
            errmsg = MSG_HEADER + "Final manifest failed XML validation"
            self.logger.critical(errmsg)
            raise DMMValidationError(errmsg)
        else:
            self.logger.info(MSG_HEADER +
                             "XML validation completed successfully ")