Esempio n. 1
0
    def get_ssh_client_command(self, ip_address=None, port_number=None):
        """
        Generate an SSH_ client command line that connects to the container
        (assumed to be running).

        :param ip_address: This optional argument overrides the default IP
                           address (which is otherwise automatically
                           discovered).
        :param port_number: This optional argument overrides the default port
                            number (which is otherwise automatically
                            discovered).
        :returns: The SSH client command line as a list of strings containing
                  the command and its arguments.
        """
        command = ['ssh']
        # Connect as the root user inside the container.
        command.extend(['-l', 'root'])
        # Connect using the generated SSH private key.
        command.extend(['-i', PRIVATE_SSH_KEY])
        # Don't check or store the host key (it's pointless).
        command.extend(['-o', 'StrictHostKeyChecking=no'])
        command.extend(['-o', 'UserKnownHostsFile=/dev/null'])
        # Silence the message "Warning: Permanently added ... to the list of known hosts."
        command.append('-q')
        # Connect through a NAT port on the local system.
        if not (ip_address and port_number):
            ip_address, port_number = self.ssh_endpoint
        command.extend(['-p', str(port_number)])
        # Make the SSH connection binary safe.
        command.extend(['-e', 'none'])
        # Finish the command by including the IP address.
        command.append(ip_address)
        self.logger.debug("Generated SSH command: %s", quote_command_line(command))
        # Return the generated command.
        return command
Esempio n. 2
0
    def rsync(self, local_directory, remote_directory, cvs_exclude=True, delete=True):
        """
        Copy a directory on the host to the container using rsync over SSH.

        Raises :py:exc:`ExternalCommandFailed` if the remote command ends with a
        nonzero exit code.

        :param local_directory: The pathname of the source directory on the host.
        :param remote_directory: The pathname of the target directory in the container.
        :param cvs_exclude: Exclude version control files (enabled by default).
        :param delete: Delete remote files that don't exist locally (enabled by default).
        """
        rsync_timer = Timer()
        self.install_packages("rsync")

        def normalize(directory):
            """ Make sure a directory path ends with a trailing slash. """
            return "%s/" % directory.rstrip("/")

        location = "%s:%s" % (self.ssh_alias, normalize(remote_directory))
        self.logger.debug("Uploading %s to %s ..", local_directory, location)
        command = ["rsync", "-a"]
        command.extend(["--rsync-path", "mkdir -p %s && rsync" % pipes.quote(remote_directory)])
        if cvs_exclude:
            command.append("--cvs-exclude")
            command.extend(["--exclude", ".hgignore"])
        if delete:
            command.append("--delete")
        command.append(normalize(local_directory))
        command.append(location)
        self.logger.debug("Generated rsync command: %s", quote_command_line(command))
        exit_code = os.spawnvp(os.P_WAIT, command[0], command)
        if exit_code == 0:
            self.logger.debug("Finished upload using rsync in %s.", rsync_timer)
        self.logger.debug("rsync exited with status %d.", exit_code)
        if exit_code != 0:
            msg = "Failed to upload directory %s to %s, rsync exited with nonzero status %d! (command: %s)"
            raise ExternalCommandFailed, msg % (local_directory, location, exit_code, quote_command_line(command))