Ejemplo n.º 1
0
 def __init__(self,
              ip_address,
              username,
              password,
              ssh_timeout=600,
              prompt=None):
     self.ssh_client = SSHBaseClient(ip_address, username, password,
                                     ssh_timeout)
     self.prompt = prompt
     if not self.ssh_client.test_connection_auth():
         raise
Ejemplo n.º 2
0
 def reboot(self, timeout=100):
     """
     @timeout: max timeout for the machine to reboot
     """
     ssh_connector = SSHBaseClient(self.ip_address, self.username, self.password)
     response, prompt = ssh_connector.exec_shell_command("sudo reboot")
     response, prompt = ssh_connector.exec_shell_command(self.password)
     self.client_log.info("Reboot response for %s: %s" % (self.ip_address, response))
     max_time = time.time() + timeout
     while time.time() < max_time:
         time.sleep(5)
         if self.ssh_client.test_connection_auth():
             self.client_log.info("Reboot successful for %s" % (self.ip_address))
             return True
Ejemplo n.º 3
0
    def __init__(self, ip_address=None, server_id=None, username=None,
                 password=None, config=None, os_distro=None, key=None):
        self.client_log = cclogging.getLogger(
            cclogging.get_object_namespace(self.__class__))

        ssh_timeout = config.connection_timeout
        if ip_address is None:
            raise ServerUnreachable("None")
        self.ip_address = ip_address
        self.username = username
        if self.username is None:
            self.username = '******'
        self.password = password
        self.server_id = server_id

        start = int(time.time())
        reachable = False
        while not reachable:
            reachable = PingClient.ping(ip_address,
                                        config.ip_address_version_for_ssh)
            time.sleep(config.connection_retry_interval)
            if int(time.time()) - start >= config.connection_timeout:
                raise ServerUnreachable(ip_address)

        self.ssh_client = SSHBaseClient(self.ip_address,
                                        self.username,
                                        self.password,
                                        timeout=ssh_timeout,
                                        key=key)
        if not self.ssh_client.test_connection_auth():
            self.client_log.error("Ssh connection failed for: IP:{0} \
                    Username:{1} Password: {2}".format(self.ip_address,
                                                       self.username,
                                                       self.password))
            raise SshConnectionException("ssh connection failed")
Ejemplo n.º 4
0
 def __init__(self, ip_address, username, password,
              ssh_timeout=600, prompt=None):
     self.ssh_client = SSHBaseClient(ip_address, username,
                                     password, ssh_timeout)
     self.prompt = prompt
     if not self.ssh_client.test_connection_auth():
         raise
Ejemplo n.º 5
0
 def reboot(self, timeout=100):
     '''
     @timeout: max timeout for the machine to reboot
     '''
     ssh_connector = SSHBaseClient(self.ip_address, self.username,
                                   self.password)
     response, prompt = ssh_connector.exec_shell_command("sudo reboot")
     response, prompt = ssh_connector.exec_shell_command(self.password)
     self.client_log.info("Reboot response for %s: %s" %
                          (self.ip_address, response))
     max_time = time.time() + timeout
     while time.time() < max_time:
         time.sleep(5)
         if self.ssh_client.test_connection_auth():
             self.client_log.info("Reboot successful for %s" %
                                  (self.ip_address))
             return True
Ejemplo n.º 6
0
    def __init__(self,
                 ip_address=None,
                 server_id=None,
                 username=None,
                 password=None,
                 config=None,
                 os_distro=None,
                 key=None):
        self.client_log = cclogging.getLogger(
            cclogging.get_object_namespace(self.__class__))

        ssh_timeout = config.connection_timeout
        if ip_address is None:
            raise ServerUnreachable("None")
        self.ip_address = ip_address
        self.username = username
        if self.username is None:
            self.username = '******'
        self.password = password
        self.server_id = server_id

        start = int(time.time())
        reachable = False
        while not reachable:
            reachable = PingClient.ping(ip_address,
                                        config.ip_address_version_for_ssh)
            time.sleep(config.connection_retry_interval)
            if int(time.time()) - start >= config.connection_timeout:
                raise ServerUnreachable(ip_address)

        self.ssh_client = SSHBaseClient(self.ip_address,
                                        self.username,
                                        self.password,
                                        timeout=ssh_timeout,
                                        key=key)
        if not self.ssh_client.test_connection_auth():
            self.client_log.error("Ssh connection failed for: IP:{0} \
                    Username:{1} Password: {2}".format(self.ip_address,
                                                       self.username,
                                                       self.password))
            raise SshConnectionException("ssh connection failed")
Ejemplo n.º 7
0
    def __init__(self, ip_address, server_id, os_distro, username, password):
        self.client_log = cclogging.getLogger \
                (cclogging.get_object_namespace(self.__class__))
        ssh_timeout = 600
        if ip_address is None:
            raise ServerUnreachable("None")
        self.ip_address = ip_address
        self.username = username
        if self.username is None:
            self.username = '******'
        self.password = password
        self.server_id = server_id

        self.ssh_client = SSHBaseClient(self.ip_address,
                                        self.username,
                                        self.password,
                                        timeout=ssh_timeout)
        if not self.ssh_client.test_connection_auth():
            self.client_log.error("Ssh connection failed for: IP:{0} \
                    Username:{1} Password: {2}".format(self.ip_address,
                                                       self.username, self.password))
            raise SshConnectionException("ssh connection failed")
Ejemplo n.º 8
0
class LinuxClient(BasePersistentLinuxClient):
    def __init__(self,
                 ip_address=None,
                 server_id=None,
                 username=None,
                 password=None,
                 config=None,
                 os_distro=None):
        self.client_log = cclogging.getLogger(
            cclogging.get_object_namespace(self.__class__))
        ssh_timeout = config.connection_timeout
        if ip_address is None:
            raise ServerUnreachable("None")
        self.ip_address = ip_address
        self.username = username
        if self.username is None:
            self.username = '******'
        self.password = password
        self.server_id = server_id

        start = int(time.time())
        reachable = False
        while not reachable:
            reachable = PingClient.ping(ip_address,
                                        config.ip_address_version_for_ssh)
            time.sleep(config.connection_retry_interval)
            if int(time.time()) - start >= config.connection_timeout:
                raise ServerUnreachable(ip_address)

        self.ssh_client = SSHBaseClient(self.ip_address,
                                        self.username,
                                        self.password,
                                        timeout=ssh_timeout)
        if not self.ssh_client.test_connection_auth():
            self.client_log.error("Ssh connection failed for: IP:{0} \
                    Username:{1} Password: {2}".format(self.ip_address,
                                                       self.username,
                                                       self.password))
            raise SshConnectionException("ssh connection failed")

    def can_connect_to_public_ip(self):
        """
        @summary: Checks if you can connect to server using public ip
        @return: True if you can connect, False otherwise
        @rtype: bool
        """
        # This returns true since the connection has already been tested in the
        # init method

        return self.ssh_client is not None

    def can_ping_public_ip(self, public_addresses, ip_address_version_for_ssh):
        """
        @summary: Checks if you can ping a public ip
        @param addresses: List of public addresses
        @type addresses: Address List
        @return: True if you can ping, False otherwise
        @rtype: bool
        """
        for public_address in public_addresses:
            if public_address.version == 4 and not PingClient.ping(
                    public_address.addr, ip_address_version_for_ssh):
                return False
        return True

    def can_authenticate(self):
        """
        @summary: Checks if you can authenticate to the server
        @return: True if you can connect, False otherwise
        @rtype: bool
        """
        return self.ssh_client.test_connection_auth()

    def reboot(self, timeout=100):
        '''
        @timeout: max timeout for the machine to reboot
        '''
        ssh_connector = SSHConnector(self.ip_address, self.username,
                                     self.password)
        response, prompt = ssh_connector.exec_shell_command("sudo reboot")
        response, prompt = ssh_connector.exec_shell_command(self.password)
        self.client_log.info("Reboot response for %s: %s" %
                             (self.ip_address, response))
        max_time = time.time() + timeout
        while time.time() < max_time:
            time.sleep(5)
            if self.ssh_client.test_connection_auth():
                self.client_log.info("Reboot successful for %s" %
                                     (self.ip_address))
                return True

    def get_hostname(self):
        """
        @summary: Gets the host name of the server
        @return: The host name of the server
        @rtype: string
        """
        return self.ssh_client.exec_command("hostname").rstrip()

    def can_remote_ping_private_ip(self, private_addresses):
        """
        @summary: Checks if you can ping a private ip from this server.
        @param private_addresses: List of private addresses
        @type private_addresses: Address List
        @return: True if you can ping, False otherwise
        @rtype: bool
        """
        for private_address in private_addresses:
            if private_address.version == 4 and not PingClient.ping_using_remote_machine(
                    self.ssh_client, private_address.addr):
                return False
        return True

    def get_files(self, path):
        """
        @summary: Gets the list of filenames from the path
        @param path: Path from where to get the filenames
        @type path: string
        @return: List of filenames
        @rtype: List of strings
        """
        command = "ls -m " + path
        return self.ssh_client.exec_command(command).rstrip('\n').split(', ')

    def get_ram_size_in_mb(self):
        """
        @summary: Returns the RAM size in MB
        @return: The RAM size in MB
        @rtype: string
        """
        output = self.ssh_client.exec_command('free -m | grep Mem')
        # TODO (dwalleck): We should handle the failure case here
        if output:
            return output.split()[1]

    def get_swap_size_in_mb(self):
        """
        @summary: Returns the Swap size in MB
        @return: The Swap size in MB
        @rtype: int
        """
        output = self.ssh_client.exec_command(
            'fdisk -l /dev/xvdc1 2>/dev/null | grep "Disk.*bytes"').rstrip(
                '\n')
        if output:
            return int(output.split()[2])

    def get_disk_size_in_gb(self, disk_path):
        """
        @summary: Returns the disk size in GB
        @return: The disk size in GB
        @rtype: int
        """
        command = "df -h | grep '{0}'".format(disk_path)
        output = self.ssh_client.exec_command(command)
        size = output.split()[1]

        def is_decimal(char):
            return str.isdigit(char) or char == "."

        size = filter(is_decimal, size)
        return float(size)

    def get_number_of_vcpus(self):
        """
        @summary: Get the number of vcpus assigned to the server
        @return: The number of vcpus assigned to the server
        @rtype: int
        """
        command = 'cat /proc/cpuinfo | grep processor | wc -l'
        output = self.ssh_client.exec_command(command)
        return int(output)

    def get_partitions(self):
        """
        @summary: Returns the contents of /proc/partitions
        @return: The partitions attached to the instance
        @rtype: string
        """
        command = 'cat /proc/partitions'
        output = self.ssh_client.exec_command(command)
        return output

    def get_uptime(self):
        """
        @summary: Get the uptime time of the server
        @return: The uptime of the server
        """
        result = self.ssh_client.exec_command('cat /proc/uptime')
        uptime = float(result.split(' ')[0])
        return uptime

    def create_file(self, file_name, file_content, file_path=None):
        '''
        @summary: Create a new file
        @param file_name: File Name
        @type file_name: String
        @param file_content: File Content
        @type file_content: String
        @return filedetails: File details such as content, name and path
        @rtype filedetails; FileDetails
        '''
        if file_path is None:
            file_path = "/root/" + file_name
        self.ssh_client.exec_command('echo -n ' + file_content + '>>' +
                                     file_path)
        return FileDetails("644", file_content, file_path)

    def get_file_details(self, filepath):
        """
        @summary: Get the file details
        @param filepath: Path to the file
        @type filepath: string
        @return: File details including permissions and content
        @rtype: FileDetails
        """
        output = self.ssh_client.exec_command(
            '[ -f ' + filepath +
            ' ] && echo "File exists" || echo "File does not exist"')
        if not output.rstrip('\n') == 'File exists':
            raise FileNotFoundException("File:" + filepath +
                                        " not found on instance.")

        file_permissions = self.ssh_client.exec_command('stat -c %a ' +
                                                        filepath).rstrip("\n")
        file_contents = self.ssh_client.exec_command('cat ' + filepath)
        return FileDetails(file_permissions, file_contents, filepath)

    def is_file_present(self, filepath):
        """
        @summary: Check if the given file is present
        @param filepath: Path to the file
        @type filepath: string
        @return: True if File exists, False otherwise
        """
        output = self.ssh_client.exec_command(
            '[ -f ' + filepath +
            ' ] && echo "File exists" || echo "File does not exist"')
        return output.rstrip('\n') == 'File exists'

    def get_partition_types(self):
        """
        @summary: Return the partition types for all partitions
        @return: The partition types for all partitions
        @rtype: Dictionary
        """
        partitions_list = self.ssh_client.exec_command('blkid').rstrip(
            '\n').split('\n')
        partition_types = {}
        for row in partitions_list:
            partition_name = row.split()[0].rstrip(':')
            partition_types[partition_name] = re.findall(
                r'TYPE="([^"]+)"', row)[0]
        return partition_types

    def get_partition_details(self):
        """
        @summary: Return the partition details
        @return: The partition details
        @rtype: Partition List
        """
        # Return a list of partition objects that each contains the name and
        # size of the partition in bytes and the type of the partition
        partition_types = self.get_partition_types()
        partition_names = ' '.join(partition_types.keys())

        partition_size_output = self.ssh_client.exec_command(
            'fdisk -l %s 2>/dev/null | grep "Disk.*bytes"' %
            (partition_names)).rstrip('\n').split('\n')
        partitions = []
        for row in partition_size_output:
            row_details = row.split()
            partition_name = row_details[1].rstrip(':')
            partition_type = partition_types[partition_name]
            if partition_type == 'swap':
                partition_size = DiskSize(float(row_details[2]),
                                          row_details[3].rstrip(','))
            else:
                partition_size = DiskSize(
                    int(row_details[4]) / 1073741824, 'GB')
            partitions.append(
                Partition(partition_name, partition_size, partition_type))
        return partitions

    def verify_partitions(self, expected_disk_size, expected_swap_size,
                          server_status, actual_partitions):
        """
        @summary: Verify the partition details of the server
        @param expected_disk_size: The expected value of the Disk size in GB
        @type expected_disk_size: string
        @param expected_swap_size: The expected value of the Swap size in GB
        @type expected_swap_size: string
        @param server_status: The status of the server
        @type server_status: string
        @param actual_partitions: The actual partition details of the server
        @type actual_partitions: Partition List
        @return: The result of verification and the message to be displayed
        @rtype: Tuple (bool,string)
        """
        expected_partitions = self._get_expected_partitions(
            expected_disk_size, expected_swap_size, server_status)
        if actual_partitions is None:
            actual_partitions = self.get_partition_details()

        for partition in expected_partitions:
            if partition not in actual_partitions:
                return False, self._construct_partition_mismatch_message(
                    expected_partitions, actual_partitions)
        return True, "Partitions Matched"

    def _get_expected_partitions(self, expected_disk_size, expected_swap_size,
                                 server_status):
        """
        @summary: Returns the expected partitions for a server based on server status
        @param expected_disk_size: The Expected disk size of the server in GB
        @type expected_disk_size: string
        @param expected_swap_size: The Expected swap size of the server in MB
        @type expected_swap_size: string
        @param server_status: Status of the server (ACTIVE or RESCUE)
        @type server_status: string
        @return: The expected partitions
        @rtype: Partition List
        """
        # ignoring swap untill the rescue functionality is clarified

        expected_partitions = [
            Partition('/dev/xvda1', DiskSize(expected_disk_size, 'GB'),
                      'ext3'),
            Partition('/dev/xvdc1', DiskSize(expected_swap_size, 'MB'), 'swap')
        ]
        if str.upper(server_status) == 'RESCUE':
            expected_partitions = [
                Partition('/dev/xvdb1', DiskSize(expected_disk_size, 'GB'),
                          'ext3')
            ]
            # expected_partitions.append(Partition('/dev/xvdd1',
            # DiskSize(expected_swap_size, 'MB'), 'swap'))
        return expected_partitions

    def _construct_partition_mismatch_message(self, expected_partitions,
                                              actual_partitions):
        """
        @summary: Constructs the partition mismatch message based on
                  expected_partitions and actual_partitions
        @param expected_partitions: Expected partitions of the server
        @type expected_partitions: Partition List
        @param actual_partitions: Actual Partitions of the server
        @type actual_partitions: Partition List
        @return: The partition mismatch message
        @rtype: string
        """
        message = 'Partitions Mismatch \n Expected Partitions:\n'
        for partition in expected_partitions:
            message += str(partition) + '\n'
        message += ' Actual Partitions:\n'
        for partition in actual_partitions:
            message += str(partition) + '\n'
        return message

    def mount_file_to_destination_directory(self, source_path,
                                            destination_path):
        '''
        @summary: Mounts the file to destination directory
        @param source_path: Path to file source
        @type source_path: String
        @param destination_path: Path to mount destination
        @type destination_path: String
        '''
        self.ssh_client.exec_command('mount ' + source_path + ' ' +
                                     destination_path)
Ejemplo n.º 9
0
class BasePersistentLinuxClient(object):

    def __init__(self, ip_address, username, password, ssh_timeout=600, prompt=None):
        self.ssh_client = SSHBaseClient(ip_address, username, password, ssh_timeout)
        self.prompt = prompt
        if not self.ssh_client.test_connection_auth():
            raise

    def format_disk_device(self, device, fstype):
        '''Formats entire device, does not create partitions'''
        return self.ssh_client.exec_command(
            "mkfs.%s %s\n" % (str(fstype).lower(), str(device)))

    def mount_disk_device(self, device, mountpoint, fstype, create_mountpoint=True):
        '''
        Mounts a disk at a specified mountpoint.
        Performs 'touch mountpoint' before executing
        '''
        self.ssh_client.exec_command("mkdir %s" % str(mountpoint))
        return self.ssh_client.exec_command(
            "mount -t %s %s %s\n" % (str(fstype).lower(),
                                     str(device), str(mountpoint)))

    def unmount_disk_device(self, mountpoint):
        '''
        Forces unmounts (umount -f) a disk at a specified mountpoint.
        '''
        return self.ssh_client.exec_command(
            "umount -f %s\n" % (str(mountpoint)))

    def write_random_data_to_disk(self, dir_path, filename, blocksize=1024,
                                  count=1024):
        '''Uses dd command to write blocksize*count bytes to dir_path/filename
           via ssh on remote machine.

           By default writes one mebibyte (2^20 bytes) if blocksize and count
           are not defined.
           NOTE:  1 MEBIbyte (2^20) != 1 MEGAbyte (10^6) for all contexts

           Note: dd if=/dev/urandom
        '''

        dd_of = os.path.join(dir_path, str(filename))
        return self.ssh_client.exec_command(
            "dd if=/dev/urandom of=%s bs=%s count=%s\n" %
            (str(dd_of), str(blocksize), str(count)))

    def write_zeroes_data_to_disk(self, disk_mountpoint, filename,
                                  blocksize=1024, count=1024):
        '''By default writes one mebibyte (2^20 bytes)'''

        of = '%s/%s' % (disk_mountpoint, str(filename))
        return self.ssh_client.exec_command(
            "dd if=/dev/zero of=%s bs=%s count=%s\n" %
            (str(of), str(blocksize), str(count)))

    def execute_resource_bomb(self):
        '''By default executes :(){ :|:& };:'''
        return self.ssh_client.exec_command(":(){ :|:& };:")

    def stat_file(self, filepath):
        sshresp = self.ssh_client.exec_command("stat %s\n" % str(filepath))
        return  sshresp

    def get_file_size_bytes(self, filepath):
        '''
           Performs wc -c on path provided, returning the numerical count in
           the result
        '''
        sshresp = self.ssh_client.exec_command("wc -c %s\n" % str(filepath))
        result = re.search('^(.*)\s', sshresp)
        try:
            return result.groups()[0]
        except:
            return None

    def get_file_md5hash(self, filepath):
        '''
            Performs binary mode md5sum of file and returns hash.
            (md5sum -b <file>)
        '''
        sshresp = self.ssh_client.exec_command("md5sum -b %s\n" % str(filepath))
        result = re.search('^(.*)\s', sshresp)
        try:
            return result.groups()[0]
        except:
            return None
Ejemplo n.º 10
0
class LinuxClient(BasePersistentLinuxClient):

    def __init__(self, ip_address=None, server_id=None, username=None,
                 password=None, config=None, os_distro=None, key=None):
        self.client_log = cclogging.getLogger(
            cclogging.get_object_namespace(self.__class__))

        ssh_timeout = config.connection_timeout
        if ip_address is None:
            raise ServerUnreachable("None")
        self.ip_address = ip_address
        self.username = username
        if self.username is None:
            self.username = '******'
        self.password = password
        self.server_id = server_id

        start = int(time.time())
        reachable = False
        while not reachable:
            reachable = PingClient.ping(ip_address,
                                        config.ip_address_version_for_ssh)
            time.sleep(config.connection_retry_interval)
            if int(time.time()) - start >= config.connection_timeout:
                raise ServerUnreachable(ip_address)

        self.ssh_client = SSHBaseClient(self.ip_address,
                                        self.username,
                                        self.password,
                                        timeout=ssh_timeout,
                                        key=key)
        if not self.ssh_client.test_connection_auth():
            self.client_log.error("Ssh connection failed for: IP:{0} \
                    Username:{1} Password: {2}".format(self.ip_address,
                                                       self.username,
                                                       self.password))
            raise SshConnectionException("ssh connection failed")

    def can_connect_to_public_ip(self):
        """
        @summary: Checks if you can connect to server using public ip
        @return: True if you can connect, False otherwise
        @rtype: bool
        """
        # This returns true since the connection has already been tested in the
        # init method

        return self.ssh_client is not None

    def can_ping_public_ip(self, public_addresses, ip_address_version_for_ssh):
        """
        @summary: Checks if you can ping a public ip
        @param addresses: List of public addresses
        @type addresses: Address List
        @return: True if you can ping, False otherwise
        @rtype: bool
        """
        for public_address in public_addresses:
            if public_address.version == 4 and not PingClient.ping(
                    public_address.addr, ip_address_version_for_ssh):
                return False
        return True

    def can_authenticate(self):
        """
        @summary: Checks if you can authenticate to the server
        @return: True if you can connect, False otherwise
        @rtype: bool
        """
        return self.ssh_client.test_connection_auth()

    def reboot(self, timeout=100):
        '''
        @timeout: max timeout for the machine to reboot
        '''
        ssh_connector = SSHBaseClient(self.ip_address, self.username,
                                      self.password)
        response, prompt = ssh_connector.exec_shell_command("sudo reboot")
        response, prompt = ssh_connector.exec_shell_command(self.password)
        self.client_log.info("Reboot response for %s: %s" % (self.ip_address,
                                                             response))
        max_time = time.time() + timeout
        while time.time() < max_time:
            time.sleep(5)
            if self.ssh_client.test_connection_auth():
                self.client_log.info("Reboot successful for %s"
                                     % (self.ip_address))
                return True

    def get_hostname(self):
        """
        @summary: Gets the host name of the server
        @return: The host name of the server
        @rtype: string
        """
        return self.ssh_client.exec_command("hostname").rstrip()

    def can_remote_ping_private_ip(self, private_addresses):
        """
        @summary: Checks if you can ping a private ip from this server.
        @param private_addresses: List of private addresses
        @type private_addresses: Address List
        @return: True if you can ping, False otherwise
        @rtype: bool
        """
        for private_address in private_addresses:
            remote = PingClient.ping_using_remote_machine(self.ssh_client,
                                                          private_address.addr)
            if private_address.version == 4 and not remote:
                return False
        return True

    def get_files(self, path):
        """
        @summary: Gets the list of filenames from the path
        @param path: Path from where to get the filenames
        @type path: string
        @return: List of filenames
        @rtype: List of strings
        """
        command = "ls -m " + path
        return self.ssh_client.exec_command(command).rstrip('\n').split(', ')

    def get_ram_size_in_mb(self):
        """
        @summary: Returns the RAM size in MB
        @return: The RAM size in MB
        @rtype: string
        """
        output = self.ssh_client.exec_command('free -m | grep Mem')
        # TODO (dwalleck): We should handle the failure case here
        if output:
            return output.split()[1]

    def get_swap_size_in_mb(self):
        """
        @summary: Returns the Swap size in MB
        @return: The Swap size in MB
        @rtype: int
        """
        output = self.ssh_client.exec_command(
            'fdisk -l /dev/xvdc1 2>/dev/null | grep '
            '"Disk.*bytes"').rstrip('\n')
        if output:
            return int(output.split()[2])

    def get_disk_size_in_gb(self, disk_path):
        """
        @summary: Returns the disk size in GB
        @return: The disk size in GB
        @rtype: int
        """
        command = "df -h | grep '{0}'".format(disk_path)
        output = self.ssh_client.exec_command(command)
        size = output.split()[1]

        def is_decimal(char):
            return str.isdigit(char) or char == "."
        size = filter(is_decimal, size)
        return float(size)

    def get_number_of_vcpus(self):
        """
        @summary: Get the number of vcpus assigned to the server
        @return: The number of vcpus assigned to the server
        @rtype: int
        """
        command = 'cat /proc/cpuinfo | grep processor | wc -l'
        output = self.ssh_client.exec_command(command)
        return int(output)

    def get_partitions(self):
        """
        @summary: Returns the contents of /proc/partitions
        @return: The partitions attached to the instance
        @rtype: string
        """
        command = 'cat /proc/partitions'
        output = self.ssh_client.exec_command(command)
        return output

    def get_uptime(self):
        """
        @summary: Get the uptime time of the server
        @return: The uptime of the server
        """
        result = self.ssh_client.exec_command('cat /proc/uptime')
        uptime = float(result.split(' ')[0])
        return uptime

    def create_file(self, file_name, file_content, file_path=None):
        '''
        @summary: Create a new file
        @param file_name: File Name
        @type file_name: String
        @param file_content: File Content
        @type file_content: String
        @return filedetails: File details such as content, name and path
        @rtype filedetails; FileDetails
        '''
        if file_path is None:
            file_path = "/root/" + file_name
        self.ssh_client.exec_command(
            'echo -n ' + file_content + '>>' + file_path)
        return FileDetails("644", file_content, file_path)

    def get_file_details(self, filepath):
        """
        @summary: Get the file details
        @param filepath: Path to the file
        @type filepath: string
        @return: File details including permissions and content
        @rtype: FileDetails
        """
        command = ('[ -f ' + filepath + ' ] && echo "File exists" || '
                                        'echo "File does not exist"')
        output = self.ssh_client.exec_command(command)
        if not output.rstrip('\n') == 'File exists':
            raise FileNotFoundException(
                "File:" + filepath + " not found on instance.")

        file_permissions = self.ssh_client.exec_command(
            'stat -c %a ' + filepath).rstrip("\n")
        file_contents = self.ssh_client.exec_command('cat ' + filepath)
        return FileDetails(file_permissions, file_contents, filepath)

    def is_file_present(self, filepath):
        """
        @summary: Check if the given file is present
        @param filepath: Path to the file
        @type filepath: string
        @return: True if File exists, False otherwise
        """
        command = ('[ -f ' + filepath + ' ] && echo "File exists" || '
                                        'echo "File does not exist"')
        output = self.ssh_client.exec_command(command)
        return output.rstrip('\n') == 'File exists'

    def get_partition_types(self):
        """
        @summary: Return the partition types for all partitions
        @return: The partition types for all partitions
        @rtype: Dictionary
        """
        partitions_list = self.ssh_client.exec_command(
            'blkid').rstrip('\n').split('\n')
        partition_types = {}
        for row in partitions_list:
            partition_name = row.split()[0].rstrip(':')
            partition_types[partition_name] = re.findall(
                r'TYPE="([^"]+)"', row)[0]
        return partition_types

    def get_partition_details(self):
        """
        @summary: Return the partition details
        @return: The partition details
        @rtype: Partition List
        """
        # Return a list of partition objects that each contains the name and
        # size of the partition in bytes and the type of the partition
        partition_types = self.get_partition_types()
        partition_names = ' '.join(partition_types.keys())

        partition_size_output = self.ssh_client.exec_command(
            'fdisk -l %s 2>/dev/null | '
            'grep "Disk.*bytes"' % partition_names).rstrip('\n').split('\n')
        partitions = []
        for row in partition_size_output:
            row_details = row.split()
            partition_name = row_details[1].rstrip(':')
            partition_type = partition_types[partition_name]
            if partition_type == 'swap':
                partition_size = DiskSize(
                    float(row_details[2]), row_details[3].rstrip(','))
            else:
                partition_size = DiskSize(
                    int(row_details[4]) / 1073741824, 'GB')
            partitions.append(
                Partition(partition_name, partition_size, partition_type))
        return partitions

    def verify_partitions(self, expected_disk_size, expected_swap_size,
                          server_status, actual_partitions):
        """
        @summary: Verify the partition details of the server
        @param expected_disk_size: The expected value of the Disk size in GB
        @type expected_disk_size: string
        @param expected_swap_size: The expected value of the Swap size in GB
        @type expected_swap_size: string
        @param server_status: The status of the server
        @type server_status: string
        @param actual_partitions: The actual partition details of the server
        @type actual_partitions: Partition List
        @return: The result of verification and the message to be displayed
        @rtype: Tuple (bool,string)
        """
        expected_partitions = self._get_expected_partitions(
            expected_disk_size, expected_swap_size, server_status)
        if actual_partitions is None:
            actual_partitions = self.get_partition_details()

        for partition in expected_partitions:
            if partition not in actual_partitions:
                return False, self._construct_partition_mismatch_message(
                    expected_partitions, actual_partitions)
        return True, "Partitions Matched"

    def _get_expected_partitions(self, expected_disk_size, expected_swap_size,
                                 server_status):
        """
        @summary: Returns the expected partitions for a server based on status
        @param expected_disk_size: The Expected disk size of the server in GB
        @type expected_disk_size: string
        @param expected_swap_size: The Expected swap size of the server in MB
        @type expected_swap_size: string
        @param server_status: Status of the server (ACTIVE or RESCUE)
        @type server_status: string
        @return: The expected partitions
        @rtype: Partition List
        """
        # ignoring swap untill the rescue functionality is clarified

        expected_partitions = [Partition('/dev/xvda1',
                                         DiskSize(expected_disk_size, 'GB'),
                                         'ext3'),
                               Partition('/dev/xvdc1',
                                         DiskSize(expected_swap_size, 'MB'),
                                         'swap')]
        if str.upper(server_status) == 'RESCUE':
            expected_partitions = [Partition(
                '/dev/xvdb1', DiskSize(expected_disk_size, 'GB'), 'ext3')]
            # expected_partitions.append(Partition('/dev/xvdd1',
            # DiskSize(expected_swap_size, 'MB'), 'swap'))
        return expected_partitions

    def _construct_partition_mismatch_message(self, expected_partitions,
                                              actual_partitions):
        """
        @summary: Constructs the partition mismatch message based on
                  expected_partitions and actual_partitions
        @param expected_partitions: Expected partitions of the server
        @type expected_partitions: Partition List
        @param actual_partitions: Actual Partitions of the server
        @type actual_partitions: Partition List
        @return: The partition mismatch message
        @rtype: string
        """
        message = 'Partitions Mismatch \n Expected Partitions:\n'
        for partition in expected_partitions:
            message += str(partition) + '\n'
        message += ' Actual Partitions:\n'
        for partition in actual_partitions:
            message += str(partition) + '\n'
        return message

    def mount_file_to_destination_directory(self, source_path,
                                            destination_path):
        '''
        @summary: Mounts the file to destination directory
        @param source_path: Path to file source
        @type source_path: String
        @param destination_path: Path to mount destination
        @type destination_path: String
        '''
        self.ssh_client.exec_command(
            'mount ' + source_path + ' ' + destination_path)

    def get_xen_user_metadata(self):
        command = 'xenstore-ls vm-data/user-metadata'
        output = self.ssh_client.exec_command(command)
        meta_list = output.split('\n')
        meta = {}
        for item in meta_list:
            # Skip any blank lines
            if item:
                meta_item = item.split("=")
                key = meta_item[0].strip()
                value = meta_item[1].strip('" ')
                meta[key] = value
        return meta

    def create_directory(self, path):
        '''
        @summary: Creates Directory
        @param path: Directory path
        @type path: string
        '''
        command = "{0} {1}".format("mkdir -p", path)
        output = self.ssh_client.exec_command(command)
        return output

    def is_directory_present(self, directory_path):
        '''
        @summary: Check if directory is present
        @param path: Path for the directory
        @type path: string
        '''
        cmd_str = "{0} {1} {2} {3} {4}"
        args = ["[ -d",
                directory_path,
                "] && echo 'Directory found' || echo 'Directory",
                directory_path, "not found'"]
        command = cmd_str.format(*args)
        output = self.ssh_client.exec_command(command)
        return output.rstrip('\n') == 'Directory found'
Ejemplo n.º 11
0
class BasePersistentLinuxClient(object):
    def __init__(self,
                 ip_address,
                 username,
                 password,
                 ssh_timeout=600,
                 prompt=None):
        self.ssh_client = SSHBaseClient(ip_address, username, password,
                                        ssh_timeout)
        self.prompt = prompt
        if not self.ssh_client.test_connection_auth():
            raise

    def format_disk_device(self, device, fstype):
        '''Formats entire device, does not create partitions'''
        return self.ssh_client.exec_command("mkfs.%s %s\n" %
                                            (str(fstype).lower(), str(device)))

    def mount_disk_device(self,
                          device,
                          mountpoint,
                          fstype,
                          create_mountpoint=True):
        '''
        Mounts a disk at a specified mountpoint.
        Performs 'touch mountpoint' before executing
        '''
        self.ssh_client.exec_command("mkdir %s" % str(mountpoint))
        return self.ssh_client.exec_command(
            "mount -t %s %s %s\n" %
            (str(fstype).lower(), str(device), str(mountpoint)))

    def unmount_disk_device(self, mountpoint):
        '''
        Forces unmounts (umount -f) a disk at a specified mountpoint.
        '''
        return self.ssh_client.exec_command("umount -f %s\n" %
                                            (str(mountpoint)))

    def write_random_data_to_disk(self,
                                  dir_path,
                                  filename,
                                  blocksize=1024,
                                  count=1024):
        '''Uses dd command to write blocksize*count bytes to dir_path/filename
           via ssh on remote machine.

           By default writes one mebibyte (2^20 bytes) if blocksize and count
           are not defined.
           NOTE:  1 MEBIbyte (2^20) != 1 MEGAbyte (10^6) for all contexts

           Note: dd if=/dev/urandom
        '''

        dd_of = os.path.join(dir_path, str(filename))
        return self.ssh_client.exec_command(
            "dd if=/dev/urandom of=%s bs=%s count=%s\n" %
            (str(dd_of), str(blocksize), str(count)))

    def write_zeroes_data_to_disk(self,
                                  disk_mountpoint,
                                  filename,
                                  blocksize=1024,
                                  count=1024):
        '''By default writes one mebibyte (2^20 bytes)'''

        of = '%s/%s' % (disk_mountpoint, str(filename))
        return self.ssh_client.exec_command(
            "dd if=/dev/zero of=%s bs=%s count=%s\n" %
            (str(of), str(blocksize), str(count)))

    def execute_resource_bomb(self):
        '''By default executes :(){ :|:& };:'''
        return self.ssh_client.exec_command(":(){ :|:& };:")

    def stat_file(self, filepath):
        sshresp = self.ssh_client.exec_command("stat %s\n" % str(filepath))
        return sshresp

    def get_file_size_bytes(self, filepath):
        '''
           Performs wc -c on path provided, returning the numerical count in
           the result
        '''
        sshresp = self.ssh_client.exec_command("wc -c %s\n" % str(filepath))
        result = re.search('^(.*)\s', sshresp)
        try:
            return result.groups()[0]
        except:
            return None

    def get_file_md5hash(self, filepath):
        '''
            Performs binary mode md5sum of file and returns hash.
            (md5sum -b <file>)
        '''
        sshresp = self.ssh_client.exec_command("md5sum -b %s\n" %
                                               str(filepath))
        result = re.search('^(.*)\s', sshresp)
        try:
            return result.groups()[0]
        except:
            return None