Example #1
0
    def CopyFiles(self):
        """This sets up the template directory."""

        build_dir = config.CONFIG.Get("PyInstaller.dpkg_root",
                                      context=self.context)
        # Copy files needed for rpmbuild.
        shutil.move(os.path.join(build_dir, "debian"),
                    os.path.join(build_dir, "rpmbuild"))
        shutil.copy(
            config_lib.Resource().Filter("install_data/centos/grr.spec.in"),
            os.path.join(build_dir, "rpmbuild/grr.spec.in"))
        shutil.copy(
            config_lib.Resource().Filter(
                "install_data/centos/grr-client.initd.in"),
            os.path.join(build_dir, "rpmbuild/grr-client.initd.in"))

        # Copy systemd unit file
        shutil.copy(
            config_lib.Resource().Filter(
                "install_data/systemd/client/grr-client.service"),
            os.path.join(build_dir, "rpmbuild/grr-client.service.in"))

        # Copy prelink blacklist file
        shutil.copy(
            config_lib.Resource().Filter(
                "install_data/centos/prelink_blacklist.conf.in"),
            os.path.join(build_dir, "rpmbuild/prelink_blacklist.conf.in"))
Example #2
0
def TestInit():
    """Only used in tests and will rerun all the hooks to create a clean state."""
    # Tests use both the server template grr_server.yaml as a primary config file
    # (this file does not contain all required options, e.g. private keys), and
    # additional configuration in test_data/grr_test.yaml which contains typical
    # values for a complete installation.
    if stats.STATS is None:
        stats.STATS = stats.StatsCollector()

    flags.FLAGS.config = config_lib.Resource().Filter(
        "install_data/etc/grr-server.yaml")

    flags.FLAGS.secondary_configs = [
        config_lib.Resource().Filter(
            "test_data/grr_test.yaml@grr-response-test")
    ]

    # We are running a test so let the config system know that.
    config_lib.CONFIG.AddContext("Test Context",
                                 "Context applied when we run tests.")

    AddConfigContext()
    ConfigInit()

    # Tests additionally add a test configuration file.
    ServerLoggingStartupInit()
    registry.TestInit()
Example #3
0
    def CopyFiles(self):
        """This sets up the template directory."""

        dpkg_dir = config_lib.CONFIG.Get("PyInstaller.dpkg_root",
                                         context=self.context)

        # Copy files needed for dpkg-buildpackage.
        shutil.copytree(
            config_lib.Resource().Filter(
                "install_data/debian/dpkg_client/debian"),
            os.path.join(dpkg_dir, "debian/debian.in"))

        # Copy upstart files
        outdir = os.path.join(dpkg_dir, "debian/upstart.in")
        utils.EnsureDirExists(outdir)
        shutil.copy(
            config_lib.Resource().Filter(
                "install_data/debian/dpkg_client/upstart/grr-client.conf"),
            outdir)

        # Copy init files
        outdir = os.path.join(dpkg_dir, "debian/initd.in")
        utils.EnsureDirExists(outdir)
        shutil.copy(
            config_lib.Resource().Filter(
                "install_data/debian/dpkg_client/initd/grr-client"), outdir)

        # Copy systemd files
        outdir = os.path.join(dpkg_dir, "debian/systemd.in")
        utils.EnsureDirExists(outdir)
        shutil.copy(
            config_lib.Resource().Filter(
                "install_data/systemd/client/grr-client.service"), outdir)
Example #4
0
File: osx.py Project: tkuennen/grr
    def InterpolateFiles(self):
        if config.CONFIG["ClientBuilder.fleetspeak_enabled"]:
            build_files_dir = config_lib.Resource().Filter(
                "install_data/macosx/client/fleetspeak")
        else:
            build_files_dir = config_lib.Resource().Filter(
                "install_data/macosx/client")
            self.GenerateFile(
                input_filename=os.path.join(build_files_dir, "grr.plist.in"),
                output_filename=os.path.join(self.pkg_root,
                                             "Library/LaunchDaemons",
                                             self.plist_name))
        # We pass in scripts separately with --scripts so they don't go in pkg_root
        self.GenerateFile(input_filename=os.path.join(build_files_dir,
                                                      "preinstall.sh.in"),
                          output_filename=os.path.join(self.script_dir,
                                                       "preinstall"))

        self.GenerateFile(input_filename=os.path.join(build_files_dir,
                                                      "postinstall.sh.in"),
                          output_filename=os.path.join(self.script_dir,
                                                       "postinstall"))
        self.GenerateFile(input_filename=os.path.join(build_files_dir,
                                                      "Distribution.xml.in"),
                          output_filename=os.path.join(self.build_dir,
                                                       "Distribution.xml"))
Example #5
0
def TestInit():
    """Only used in tests and will rerun all the hooks to create a clean state."""
    global INIT_RAN

    if stats.STATS is None:
        stats.STATS = stats.StatsCollector()

    # Tests use both the server template grr_server.yaml as a primary config file
    # (this file does not contain all required options, e.g. private keys), and
    # additional configuration in test_data/grr_test.yaml which contains typical
    # values for a complete installation.
    flags.FLAGS.config = config_lib.Resource().Filter(
        "install_data/etc/grr-server.yaml")

    flags.FLAGS.secondary_configs.append(config_lib.Resource().Filter(
        "test_data/grr_test.yaml@grr-response-test"))

    # This config contains non-public settings that should be applied during
    # tests.
    extra_test_config = config.CONFIG["Test.additional_test_config"]
    if os.path.exists(extra_test_config):
        flags.FLAGS.secondary_configs.append(extra_test_config)

    # Tests additionally add a test configuration file.
    config_lib.SetPlatformArchContext()
    config_lib.ParseConfigCommandLine()

    # We are running a test so let the config system know that.
    config.CONFIG.AddContext(contexts.TEST_CONTEXT,
                             "Context applied when we run tests.")

    test_ds = flags.FLAGS.test_data_store
    if test_ds is None:
        test_ds = fake_data_store.FakeDataStore.__name__

    if not INIT_RAN:
        config.CONFIG.Set("Datastore.implementation", test_ds)
        config.CONFIG.Set("Blobstore.implementation",
                          memory_stream_bs.MemoryStreamBlobstore.__name__)

        server_logging.ServerLoggingStartupInit()
        server_logging.SetTestVerbosity()

    registry.TestInit()

    db = data_store.DB.SetupTestDB()
    if db:
        data_store.DB = db
    data_store.DB.Initialize()
    aff4.AFF4InitHook().Run()

    INIT_RAN = True
Example #6
0
def SetConfigOptions():
    """Set location of configuration flags.

  All GRR tools must use the same configuration files so they could all work
  together. This needs to happen even before the configuration subsystem is
  loaded so it must be bootstrapped by this code (all other options are
  tweakable via the configuration system).

  There are two main parts for the config system:

  1) The main config file is shipped with the package and controls general
     parameters. Note that this file is highly dependent on the exact version of
     the grr package which is using it because it might have options which are
     not understood by another version. We typically always use the config file
     from package resources because in most cases this is the right thing to do
     as this file matches exactly the running version. If you really have a good
     reason you can override with the --config flag.

  2) The writeback location. If any GRR component updates the configuration,
     changes will be written back to a different locally modified config
     file. This file specifies overrides of the main configuration file. The
     main reason is that typically the same locally written config file may be
     used with multiple versions of the GRR server because it specifies a very
     small and rarely changing set of options.

  """
    # The writeback config file is searched in the following order:

    # 1. Specified on the command line with the "--config XXXX" option.
    # 2. Use the default config file from the grr-response package.
    flags.PARSER.set_defaults(config=config_lib.Resource().Filter(
        "install_data/etc/grr-server.yaml"))
Example #7
0
    def BuildWithPyInstaller(self):
        """Use pyinstaller to build a client package."""
        self.CleanDirectory(
            config.CONFIG.Get("PyInstaller.distpath", context=self.context))

        logging.info("Copying pyinstaller support files")
        self.spec_file = os.path.join(self.build_dir, "grr.spec")

        with open(self.spec_file, "wb") as fd:
            fd.write(
                config.CONFIG.Get("PyInstaller.spec", context=self.context))

        with open(os.path.join(self.build_dir, "version.txt"), "wb") as fd:
            fd.write(
                config.CONFIG.Get("PyInstaller.version", context=self.context))

        with open(os.path.join(self.build_dir, "grr.ico"), "wb") as fd:
            fd.write(
                config.CONFIG.Get("PyInstaller.icon", context=self.context))

        # We expect the onedir output at this location.
        self.output_dir = os.path.join(
            config.CONFIG.Get("PyInstaller.distpath", context=self.context),
            "grr-client")

        # Pyinstaller doesn't handle unicode strings.
        args = [
            "--distpath",
            str(config.CONFIG.Get("PyInstaller.distpath",
                                  context=self.context)), "--workpath",
            str(
                config.CONFIG.Get("PyInstaller.workpath_dir",
                                  context=self.context)),
            str(self.spec_file)
        ]
        logging.info("Running pyinstaller: %s", args)
        PyInstallerMain.run(pyi_args=[utils.SmartStr(x) for x in args])

        # Clear out some crud that pyinstaller includes.
        for path in ["tcl", "tk", "pytz"]:
            dir_path = os.path.join(self.output_dir, path)
            try:
                shutil.rmtree(dir_path)
                os.mkdir(dir_path)
                # Create an empty file so the directories get put in the installers.
                with open(os.path.join(dir_path, path), "wb"):
                    pass
            except OSError:
                pass

        version_ini = config_lib.Resource().Filter("version.ini")
        if not os.path.exists(version_ini):
            raise RuntimeError(
                "Couldn't find version_ini in virtual env root: %s" %
                version_ini)
        shutil.copy(version_ini, os.path.join(self.output_dir, "version.ini"))

        with open(os.path.join(self.output_dir, "build.yaml"), "wb") as fd:
            self.WriteBuildYaml(fd)
Example #8
0
def main(argv):
    """Sets up all the component in their own threads."""
    config_lib.CONFIG.AddContext(
        "Demo Context",
        "The demo runs all functions in a single process using the "
        "in memory data store.")

    config_lib.CONFIG.AddContext("Test Context",
                                 "Context applied when we run tests.")

    flags.FLAGS.config = config_lib.Resource().Filter(
        "install_data/etc/grr-server.yaml")

    flags.FLAGS.secondary_configs = [
        config_lib.Resource().Filter(
            "test_data/grr_test.yaml@grr-response-test")
    ]

    startup.Init()

    # pylint: disable=unused-import,unused-variable,g-import-not-at-top
    from grr.gui import gui_plugins
    # pylint: enable=unused-import,unused-variable,g-import-not-at-top

    # This is the worker thread.
    worker_thread = threading.Thread(target=worker.main,
                                     args=[argv],
                                     name="Worker")
    worker_thread.daemon = True
    worker_thread.start()

    # This is the http server Frontend that clients communicate with.
    http_thread = threading.Thread(target=http_server.main,
                                   args=[argv],
                                   name="HTTP Server")
    http_thread.daemon = True
    http_thread.start()

    client_thread = threading.Thread(target=client.main,
                                     args=[argv],
                                     name="Client")
    client_thread.daemon = True
    client_thread.start()

    # The UI is running in the main thread.
    runtests.main(argv)
Example #9
0
def UploadBinaryIfAbsent(server_paths, bin_name, server_path):
    if server_path in server_paths:
        return
    logging.info("Binary %s not uploaded yet. Will upload.", server_path)
    package_dir = config_lib.Resource().Filter(
        "grr_response_test@grr-response-test")
    with open(os.path.join(package_dir, "test_data", bin_name), "rb") as f:
        maintenance_utils.UploadSignedConfigBlob(
            f.read(), "aff4:/config/executables/%s" % server_path)
Example #10
0
 def _UploadBinary(self, bin_name, server_path):
   """Uploads a binary from the GRR installation dir to the datastore."""
   # TODO(user): Upload binaries via the GRR API.
   logging.info("Uploading %s binary to server.", server_path)
   package_dir = config_lib.Resource().Filter(
       "grr_response_test@grr-response-test")
   with open(os.path.join(package_dir, "test_data", bin_name), "rb") as f:
     maintenance_utils.UploadSignedConfigBlob(
         f.read(), "aff4:/config/executables/%s" % server_path)
Example #11
0
    def testConfigOptionsDefined(self):
        """Test that all config options in use are defined."""
        # We need to use the actual config.CONFIG variable since that is where
        # all the variables are already defined.
        conf = config.CONFIG.MakeNewConfig()

        # Check our actual config validates
        configpath = config_lib.Resource().Filter(
            "install_data/etc/grr-server.yaml")
        conf.Initialize(filename=configpath)
Example #12
0
    def testRepackAll(self):
        """Test repacking all binaries."""
        self.executables_dir = config_lib.Resource().Filter("executables")
        with utils.TempDirectory() as tmp_dir:
            new_dir = os.path.join(tmp_dir, "grr", "executables")
            os.makedirs(new_dir)

            # Copy unzipsfx so it can be used in repacking/
            shutil.copy(
                os.path.join(self.executables_dir,
                             "windows/templates/unzipsfx/unzipsfx-i386.exe"),
                new_dir)
            shutil.copy(
                os.path.join(self.executables_dir,
                             "windows/templates/unzipsfx/unzipsfx-amd64.exe"),
                new_dir)

            with test_lib.ConfigOverrider({
                    "ClientBuilder.executables_dir":
                    new_dir,
                    "ClientBuilder.unzipsfx_stub_dir":
                    new_dir
            }):
                repacking.TemplateRepacker().RepackAllTemplates()

            self.assertEqual(
                len(glob.glob(os.path.join(new_dir, "installers/*.deb"))), 2)
            self.assertEqual(
                len(glob.glob(os.path.join(new_dir, "installers/*.rpm"))), 2)
            self.assertEqual(
                len(glob.glob(os.path.join(new_dir, "installers/*.exe"))), 4)
            self.assertEqual(
                len(glob.glob(os.path.join(new_dir, "installers/*.pkg"))), 1)

            # Validate the config appended to the OS X package.
            zf = zipfile.ZipFile(glob.glob(
                os.path.join(new_dir, "installers/*.pkg")).pop(),
                                 mode="r")
            fd = zf.open("config.yaml")

            # We can't load the included build.yaml because the package hasn't been
            # installed.
            loaded = yaml.safe_load(fd)
            loaded.pop("Config.includes")

            packaged_config = config.CONFIG.MakeNewConfig()
            packaged_config.Initialize(parser=config_lib.YamlParser,
                                       data=yaml.safe_dump(loaded))
            packaged_config.Validate(
                sections=build.ClientRepacker.CONFIG_SECTIONS)
            repacker = build.ClientRepacker()
            repacker.ValidateEndConfig(packaged_config)
Example #13
0
def SetConfigOptions():
    """Set location of configuration flags.

  All GRR tools must use the same configuration files so they could all work
  together. This needs to happen even before the configuration subsystem is
  loaded so it must be bootstrapped by this code (all other options are
  tweakable via the configuration system).

  There are two main parts for the config system:

  1) The main config file is shipped with the package and controls general
     parameters. Note that this file is highly dependent on the exact version of
     the grr package which is using it because it might have options which are
     not understood by another version. We typically always use the config file
     from package resources because in most cases this is the right thing to do
     as this file matches exactly the running version. If you really have a good
     reason you can override with the --config flag.

  2) The writeback location. If any GRR component updates the configuration,
     changes will be written back to a different locally modified config
     file. This file specifies overrides of the main configuration file. The
     main reason is that typically the same locally written config file may be
     used with multiple versions of the GRR server because it specifies a very
     small and rarely changing set of options.

  """
    config_opts = {}
    flag_defaults = {}

    # Allow the installer to override the platform defaults for the location of
    # the writeback config file. The writeback config file is therefore searched
    # in the following order:

    # 1. Specified on the command line with the "--config XXXX" option.
    # 2. Specified in the environment variable GRR_CONFIG_FILE.
    # 3. Specified during installation with:
    #     "python setup.py install --config-file=XXXX"
    # 4. Use the default config file from the grr-response package.
    if os.environ.get("GRR_CONFIG_FILE"):
        flag_defaults["config"] = os.environ.get("GRR_CONFIG_FILE")

    elif defaults.CONFIG_FILE:
        flag_defaults["config"] = defaults.CONFIG_FILE

    else:
        flag_defaults["config"] = config_lib.Resource().Filter(
            "install_data/etc/grr-server.yaml")

    for option, value in config_opts.items():
        config_lib.CONFIG.Set(option, value)

    flags.PARSER.set_defaults(**flag_defaults)
Example #14
0
def version():
    # Delay imports until we have the config system to find the version.ini file.
    # pylint: disable=g-import-not-at-top
    import ConfigParser
    from grr.lib import config_lib

    config = ConfigParser.SafeConfigParser()
    config.read(config_lib.Resource().Filter("version.ini"))
    return dict(packageversion=config.get("Version", "packageversion"),
                major=config.getint("Version", "major"),
                minor=config.getint("Version", "minor"),
                revision=config.getint("Version", "revision"),
                release=config.getint("Version", "release"))
Example #15
0
def TestInit():
  """Only used in tests and will rerun all the hooks to create a clean state."""
  global INIT_RAN

  if stats.STATS is None:
    stats.STATS = stats.StatsCollector()

  # Tests use both the server template grr_server.yaml as a primary config file
  # (this file does not contain all required options, e.g. private keys), and
  # additional configuration in test_data/grr_test.yaml which contains typical
  # values for a complete installation.
  flags.FLAGS.config = config_lib.Resource().Filter(
      "install_data/etc/grr-server.yaml")

  flags.FLAGS.secondary_configs = [
      config_lib.Resource().Filter("test_data/grr_test.yaml@grr-response-test")
  ]

  # This config contains non-public settings that should be applied during
  # tests.
  extra_test_config = config_lib.CONFIG["Test.additional_test_config"]
  if os.path.exists(extra_test_config):
    flags.FLAGS.secondary_configs.append(extra_test_config)

  # We are running a test so let the config system know that.
  config_lib.CONFIG.AddContext("Test Context",
                               "Context applied when we run tests.")

  # Tests additionally add a test configuration file.
  config_lib.SetPlatformArchContext()
  config_lib.ParseConfigCommandLine()

  if not INIT_RAN:
    log.ServerLoggingStartupInit()

  registry.TestInit()

  INIT_RAN = True
Example #16
0
def version():
    """Return a dict with GRR version information."""
    # Delay import until we have the config system to find the version.ini file.
    # pylint: disable=g-import-not-at-top
    from grr.lib import config_lib

    version_ini = config_lib.Resource().Filter("version.ini")
    if not os.path.exists(version_ini):
        raise RuntimeError("Can't find version.ini at %s" % version_ini)

    config = ConfigParser.SafeConfigParser()
    config.read(version_ini)
    return dict(packageversion=config.get("Version", "packageversion"),
                major=config.getint("Version", "major"),
                minor=config.getint("Version", "minor"),
                revision=config.getint("Version", "revision"),
                release=config.getint("Version", "release"))
Example #17
0
    def disabled_testRepackAll(self):
        """Test repacking all binaries."""
        self.executables_dir = config_lib.Resource().Filter("executables")
        with utils.TempDirectory() as tmp_dir:
            new_dir = os.path.join(tmp_dir, "grr", "executables")
            os.makedirs(new_dir)

            # Copy unzipsfx so it can be used in repacking/
            shutil.copy(
                os.path.join(self.executables_dir,
                             "windows/templates/unzipsfx/unzipsfx-i386.exe"),
                new_dir)
            shutil.copy(
                os.path.join(self.executables_dir,
                             "windows/templates/unzipsfx/unzipsfx-amd64.exe"),
                new_dir)

            with test_lib.ConfigOverrider({
                    "ClientBuilder.executables_dir":
                    new_dir,
                    "ClientBuilder.unzipsfx_stub_dir":
                    new_dir
            }):
                repacking.TemplateRepacker().RepackAllTemplates()

            self.assertEqual(
                len(glob.glob(os.path.join(new_dir,
                                           "linux/installers/*.deb"))), 2)
            self.assertEqual(
                len(glob.glob(os.path.join(new_dir,
                                           "linux/installers/*.rpm"))), 2)
            self.assertEqual(
                len(
                    glob.glob(os.path.join(new_dir,
                                           "windows/installers/*.exe"))), 2)
            self.assertEqual(
                len(glob.glob(os.path.join(new_dir,
                                           "darwin/installers/*.pkg"))), 1)
Example #18
0
def SetConfigOptions():
  """Set location of configuration flags."""
  flags.PARSER.set_defaults(
      config=config_lib.Resource().Filter("install_data/etc/grr-server.yaml"))
Example #19
0
def SetConfigOptions():
    """Sets the default value for the config flag."""
    flags.PARSER.set_defaults(config=config_lib.Resource().Filter(
        "install_data/etc/grr-server.yaml"))
Example #20
0
 def setUp(self):
   super(BuildTests, self).setUp()
   self.executables_dir = config_lib.Resource().Filter("executables")
Example #21
0
    def BuildInstallerPkg(self, output_file):
        """Builds a package (.pkg) using PackageMaker."""
        build_files_dir = config_lib.Resource().Filter(
            "install_data/macosx/client")

        pmdoc_dir = os.path.join(build_files_dir, "grr.pmdoc")

        client_name = config_lib.CONFIG.Get("Client.name",
                                            context=self.context)
        plist_name = config_lib.CONFIG.Get("Client.plist_filename",
                                           context=self.context)

        out_build_files_dir = build_files_dir.replace(
            config_lib.Resource().Filter("grr"), self.build_dir)
        out_pmdoc_dir = os.path.join(self.build_dir, "%s.pmdoc" % client_name)

        utils.EnsureDirExists(out_build_files_dir)
        utils.EnsureDirExists(out_pmdoc_dir)
        utils.EnsureDirExists(
            config_lib.CONFIG.Get("ClientBuilder.package_dir",
                                  context=self.context))

        self.GenerateFile(input_filename=os.path.join(build_files_dir,
                                                      "grr.plist.in"),
                          output_filename=os.path.join(self.build_dir,
                                                       plist_name))
        self.GenerateFile(input_filename=os.path.join(pmdoc_dir,
                                                      "index.xml.in"),
                          output_filename=os.path.join(out_pmdoc_dir,
                                                       "index.xml"))
        self.GenerateFile(input_filename=os.path.join(pmdoc_dir,
                                                      "01grr.xml.in"),
                          output_filename=os.path.join(
                              out_pmdoc_dir, "01%s.xml" % client_name))
        self.GenerateFile(input_filename=os.path.join(pmdoc_dir,
                                                      "01grr-contents.xml"),
                          output_filename=os.path.join(
                              out_pmdoc_dir,
                              "01%s-contents.xml" % client_name))
        self.GenerateFile(input_filename=os.path.join(pmdoc_dir,
                                                      "02com.xml.in"),
                          output_filename=os.path.join(out_pmdoc_dir,
                                                       "02com.xml"))
        self.GenerateFile(input_filename=os.path.join(pmdoc_dir,
                                                      "02com-contents.xml"),
                          output_filename=os.path.join(out_pmdoc_dir,
                                                       "02com-contents.xml"))

        self.GenerateFile(input_filename=os.path.join(build_files_dir,
                                                      "preinstall.sh.in"),
                          output_filename=os.path.join(self.build_dir,
                                                       "preinstall.sh"))
        self.GenerateFile(input_filename=os.path.join(build_files_dir,
                                                      "postinstall.sh.in"),
                          output_filename=os.path.join(self.build_dir,
                                                       "postinstall.sh"))

        output_basename = config_lib.CONFIG.Get(
            "ClientBuilder.output_basename", context=self.context)

        # Rename the generated binaries to the correct name.
        template_binary_dir = os.path.join(
            config_lib.CONFIG.Get("PyInstaller.distpath",
                                  context=self.context), "grr-client")
        target_binary_dir = os.path.join(self.build_dir,
                                         "%s" % output_basename)

        if template_binary_dir != target_binary_dir:
            shutil.move(template_binary_dir, target_binary_dir)

        shutil.move(
            os.path.join(target_binary_dir, "grr-client"),
            os.path.join(
                target_binary_dir,
                config_lib.CONFIG.Get("Client.binary_name",
                                      context=self.context)))

        deployer = build.ClientDeployer(context=self.context)
        deployer.context = self.context

        # Generate a config file.
        with open(
                os.path.join(
                    target_binary_dir,
                    config_lib.CONFIG.Get("ClientBuilder.config_filename",
                                          context=self.context)), "wb") as fd:
            fd.write(
                deployer.GetClientConfig(["Client Context"] + self.context,
                                         validate=False))

        print "Fixing file ownership and permissions"

        command = [
            "sudo", "/usr/sbin/chown", "-R", "root:wheel", self.build_dir
        ]
        # Change the owner, group and permissions of the binaries
        print "Running: %s" % " ".join(command)
        subprocess.call(command)

        command = ["sudo", "/bin/chmod", "-R", "755", self.build_dir]

        print "Running: %s" % " ".join(command)
        subprocess.call(command)

        print "Building a package with PackageMaker"
        pkg = "%s-%s.pkg" % (config_lib.CONFIG.Get("Client.name",
                                                   context=self.context),
                             config_lib.CONFIG.Get("Client.version_string",
                                                   context=self.context))

        output_pkg_path = os.path.join(self.pkg_dir, pkg)
        command = [
            config_lib.CONFIG.Get("ClientBuilder.package_maker_path",
                                  context=self.context), "--doc",
            out_pmdoc_dir, "--out", output_pkg_path
        ]

        print "Running: %s " % " ".join(command)
        ret = subprocess.call(command)
        if ret != 0:
            msg = "PackageMaker returned an error (%d)." % ret
            print msg
            raise RuntimeError(msg)

        print "Copying output to templates location: %s -> %s" % (
            output_pkg_path, output_file)
        utils.EnsureDirExists(os.path.dirname(output_file))
        shutil.copyfile(output_pkg_path, output_file)

        # Change the owner, group and permissions of the binaries back.
        command = [
            "sudo", "/usr/sbin/chown", "-R",
            "%s:staff" % getpass.getuser(), self.build_dir
        ]
        print "Running: %s" % " ".join(command)
        subprocess.call(command)