Merge "Removing the remote_instance client"
This commit is contained in:
commit
993cea8de9
@ -1,15 +0,0 @@
|
||||
"""
|
||||
Copyright 2013 Rackspace
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
@ -1,21 +0,0 @@
|
||||
"""
|
||||
Copyright 2013 Rackspace
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
|
||||
class InstanceClientConstants:
|
||||
LAST_REBOOT_TIME_FORMAT = '%Y-%m-%d %H:%M'
|
||||
LAST_REBOOT_TIME_FORMAT_GENTOO = '%b %d %H:%M %Y'
|
||||
LINUX_OS_FAMILY = 'linux'
|
@ -1,23 +0,0 @@
|
||||
"""
|
||||
Copyright 2013 Rackspace
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
|
||||
class DirectoryNotFoundException(Exception):
|
||||
def __init__(self, message):
|
||||
self.message = message
|
||||
|
||||
def __str__(self):
|
||||
return repr(self.message)
|
@ -1,165 +0,0 @@
|
||||
"""
|
||||
Copyright 2013 Rackspace
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
from cafe.common.reporting import cclogging
|
||||
from cafe.engine.clients.remote_instance.linux.linux_instance_client \
|
||||
import LinuxClient
|
||||
from cafe.engine.clients.remote_instance.windows.windows_instance_client \
|
||||
import WindowsClient
|
||||
|
||||
|
||||
class InstanceClientFactory(object):
|
||||
"""
|
||||
@summary: Factory class which will create appropriate utility object
|
||||
based on the operating system of the server.
|
||||
"""
|
||||
clientList = {'windows': 'WindowsClient', 'linux': 'LinuxClient',
|
||||
'gentoo': 'LinuxClient', 'arch': 'LinuxClient',
|
||||
'freebsd': 'FreeBSDClient'}
|
||||
|
||||
@classmethod
|
||||
def get_instance_client(cls, ip_address=None, username=None, password=None,
|
||||
os_distro=None, server_id=None, config=None,
|
||||
key=None):
|
||||
"""
|
||||
@summary: Returns utility class based on the OS type of server
|
||||
@param ip_address: IP Address of the server
|
||||
@type ip_address: string
|
||||
@param password: The administrator user password
|
||||
@type password: string
|
||||
@param username: The administrator user name
|
||||
@type username: string
|
||||
@return: Utility class based on the OS type of server
|
||||
@rtype: LinuxClient or WindowsClient
|
||||
"""
|
||||
|
||||
instanceClient = cls.clientList.get(os_distro.lower())
|
||||
if instanceClient is None:
|
||||
instanceClient = cls.clientList.get(cls.os_type.lower())
|
||||
|
||||
target_str = "globals().get('" + instanceClient + "')"
|
||||
instanceClient = eval(target_str)
|
||||
|
||||
return instanceClient(ip_address=ip_address, username=username,
|
||||
password=password, os_distro=os_distro,
|
||||
server_id=server_id, config=config, key=key)
|
||||
|
||||
|
||||
class InstanceClient(object):
|
||||
"""
|
||||
@summary: Wrapper class around different operating system utilities.
|
||||
"""
|
||||
|
||||
def __init__(self, ip_address=None, password=None, os_distro=None,
|
||||
config=None, username=None, server_id=None, key=None):
|
||||
self._client = InstanceClientFactory.get_instance_client(
|
||||
ip_address=ip_address, password=password, os_distro=os_distro,
|
||||
username=username, server_id=server_id, config=config, key=key)
|
||||
self.client_log = cclogging.getLogger(
|
||||
cclogging.get_object_namespace(self.__class__))
|
||||
|
||||
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._client.test_connection_auth()
|
||||
|
||||
def get_hostname(self):
|
||||
"""
|
||||
@summary: Gets the host name of the server
|
||||
@return: The host name of the server
|
||||
@rtype: string
|
||||
"""
|
||||
return self._client.get_hostname()
|
||||
|
||||
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
|
||||
"""
|
||||
return self._client.get_files(path)
|
||||
|
||||
def get_ram_size_in_mb(self):
|
||||
"""
|
||||
@summary: Returns the RAM size in MB
|
||||
@return: The RAM size in MB
|
||||
@rtype: string
|
||||
"""
|
||||
return self._client.get_ram_size_in_mb()
|
||||
|
||||
def get_disk_size_in_gb(self):
|
||||
"""
|
||||
@summary: Returns the disk size in GB
|
||||
@return: The disk size in GB
|
||||
@rtype: int
|
||||
"""
|
||||
return self._client.get_disk_size_in_gb()
|
||||
|
||||
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
|
||||
"""
|
||||
return self._client.get_number_of_vcpus()
|
||||
|
||||
def get_partitions(self):
|
||||
"""
|
||||
@summary: Returns the contents of /proc/partitions
|
||||
@return: The partitions attached to the instance
|
||||
@rtype: string
|
||||
"""
|
||||
return self._client.get_partitions()
|
||||
|
||||
def get_uptime(self):
|
||||
"""
|
||||
@summary: Get the boot time of the server
|
||||
@return: The boot time of the server
|
||||
@rtype: time.struct_time
|
||||
"""
|
||||
return self._client.get_uptime()
|
||||
|
||||
def create_file(self, filedetails):
|
||||
'''
|
||||
@summary: Create a new file
|
||||
@param filedetails: File details such as content, name
|
||||
@type filedetails; FileDetails
|
||||
'''
|
||||
return self._client.create_file()
|
||||
|
||||
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
|
||||
"""
|
||||
return self._client.get_file_details()
|
||||
|
||||
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
|
||||
"""
|
||||
return self._client.is_file_present()
|
@ -1,20 +0,0 @@
|
||||
"""
|
||||
Copyright 2013 Rackspace
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
LAST_REBOOT_TIME_FORMAT = '%Y-%m-%d %H:%M:%S'
|
||||
PING_IPV4_COMMAND = 'ping -c 3 '
|
||||
PING_IPV6_COMMAND = 'ping6 -c 3 '
|
||||
PING_PACKET_LOSS_REGEX = '(\d{1,3})\.?\d*\% packet loss'
|
@ -1,58 +0,0 @@
|
||||
"""
|
||||
Copyright 2013 Rackspace
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
import time
|
||||
import re
|
||||
|
||||
from cafe.engine.clients.remote_instance.constants import \
|
||||
InstanceClientConstants
|
||||
from cafe.engine.clients.remote_instance.linux.linux_instance_client \
|
||||
import LinuxClient
|
||||
|
||||
|
||||
class FreeBSDClient(LinuxClient):
|
||||
def get_boot_time(self):
|
||||
"""
|
||||
@summary: Get the boot time of the server
|
||||
@return: The boot time of the server
|
||||
@rtype: time.struct_time
|
||||
"""
|
||||
uptime_string = self.ssh_client.execute_command('uptime').stdout
|
||||
uptime = uptime_string.replace('\n', '').split(',')[0].split()[2]
|
||||
uptime_unit = uptime_string.replace('\n', '').split(',')[0].split()[3]
|
||||
if uptime_unit == 'mins':
|
||||
uptime_unit_format = 'M'
|
||||
else:
|
||||
uptime_unit_format = 'S'
|
||||
|
||||
command = 'date -v -{uptime}{unit_format} "+%Y-%m-%d %H:%M"'.format(
|
||||
uptime=uptime, uptime_unit_format=uptime_unit_format)
|
||||
reboot_time = self.ssh_client.execute_command(
|
||||
command).stdout.replace('\n', '')
|
||||
|
||||
return time.strptime(reboot_time,
|
||||
InstanceClientConstants.LAST_REBOOT_TIME_FORMAT)
|
||||
|
||||
def get_disk_size_in_gb(self):
|
||||
"""
|
||||
@summary: Returns the disk size in GB
|
||||
@return: The disk size in GB
|
||||
@rtype: int
|
||||
"""
|
||||
output = self.ssh_client.execute_command(
|
||||
'gpart show -p | grep "GPT"').stdout.replace('\n', '')
|
||||
disk_size = re.search(r'([0-9]+)G', output).group(1)
|
||||
return int(disk_size)
|
@ -1,39 +0,0 @@
|
||||
"""
|
||||
Copyright 2013 Rackspace
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
import time
|
||||
|
||||
from cafe.engine.clients.remote_instance.constants import \
|
||||
InstanceClientConstants
|
||||
from cafe.engine.clients.remote_instance.linux.linux_instance_client \
|
||||
import LinuxClient
|
||||
|
||||
|
||||
class GentooArchClient(LinuxClient):
|
||||
def get_boot_time(self):
|
||||
"""
|
||||
@summary: Get the boot time of the server
|
||||
@return: The boot time of the server
|
||||
@rtype: time.struct_time
|
||||
"""
|
||||
boot_time_string = self.ssh_client.execute_command(
|
||||
'who -b | grep -o "[A-Za-z]* [0-9].*"').replace('\n', ' ').stdout
|
||||
year = self.ssh_client.execute_command(
|
||||
'date | grep -o "[0-9]\{4\}$"').replace('\n', '').stdout
|
||||
boot_time = boot_time_string + year
|
||||
|
||||
time_format = InstanceClientConstants.LAST_REBOOT_TIME_FORMAT_GENTOO
|
||||
return time.strptime(boot_time, time_format)
|
@ -1,465 +0,0 @@
|
||||
"""
|
||||
Copyright 2013 Rackspace
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
import time
|
||||
import re
|
||||
|
||||
from cafe.common.reporting import cclogging
|
||||
from cafe.engine.clients.base import BaseClient
|
||||
from cafe.engine.clients.remote_instance.models.dir_details \
|
||||
import DirectoryDetails
|
||||
from cafe.engine.clients.remote_instance.exceptions \
|
||||
import DirectoryNotFoundException
|
||||
from cafe.engine.clients.remote_instance.models.file_details \
|
||||
import FileDetails
|
||||
from cafe.engine.clients.remote_instance.models.partition import \
|
||||
Partition, DiskSize
|
||||
from cafe.engine.clients.ssh import SSHAuthStrategy, SSHBehaviors
|
||||
from cafe.engine.clients.ping import PingClient
|
||||
from cloudcafe.compute.common.exceptions import FileNotFoundException, \
|
||||
ServerUnreachable, SshConnectionException
|
||||
|
||||
|
||||
class LinuxClient(BaseClient):
|
||||
|
||||
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 = 'root'
|
||||
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)
|
||||
|
||||
if key is not None:
|
||||
auth_strategy = SSHAuthStrategy.KEY_STRING
|
||||
else:
|
||||
auth_strategy = SSHAuthStrategy.PASSWORD
|
||||
|
||||
self.ssh_client = SSHBehaviors(
|
||||
username=self.username, password=self.password,
|
||||
host=self.ip_address, tcp_timeout=20, auth_strategy=auth_strategy,
|
||||
look_for_keys=False, key=key)
|
||||
self.ssh_client.connect_with_timeout(cooldown=20, timeout=ssh_timeout)
|
||||
if not self.ssh_client.is_connected():
|
||||
message = ('SSH timeout after {timeout} seconds: '
|
||||
'Could not connect to {ip_address}.')
|
||||
raise SshConnectionException(message.format(
|
||||
timeout=ssh_timeout, ip_address=ip_address))
|
||||
|
||||
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.is_connected()
|
||||
|
||||
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.execute_command("hostname").stdout.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.execute_command(
|
||||
command).stdout.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.execute_command('free -m | grep Mem').stdout
|
||||
# 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.execute_command(
|
||||
'fdisk -l /dev/xvdc1 2>/dev/null | grep '
|
||||
'"Disk.*bytes"').stdout.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.execute_command(command).stdout
|
||||
size = output.split()[1]
|
||||
|
||||
def is_decimal(char):
|
||||
return str.isdigit(char) or char == "."
|
||||
size = list(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.execute_command(command).stdout
|
||||
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.execute_command(command).stdout
|
||||
return output
|
||||
|
||||
def get_uptime(self):
|
||||
"""
|
||||
@summary: Get the uptime time of the server
|
||||
@return: The uptime of the server
|
||||
"""
|
||||
result = self.ssh_client.execute_command('cat /proc/uptime').stdout
|
||||
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.execute_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.execute_command(command).stdout
|
||||
if not output.rstrip('\n') == 'File exists':
|
||||
raise FileNotFoundException(
|
||||
"File:" + filepath + " not found on instance.")
|
||||
|
||||
file_permissions = self.ssh_client.execute_command(
|
||||
'stat -c %a ' + filepath).stdout.rstrip("\n")
|
||||
file_contents = self.ssh_client.execute_command(
|
||||
'cat ' + filepath).stdout
|
||||
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.execute_command(command).stdout
|
||||
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.execute_command(
|
||||
'blkid').stdout.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(list(partition_types.keys()))
|
||||
|
||||
partition_size_output = self.ssh_client.execute_command(
|
||||
'fdisk -l %s 2>/dev/null | '
|
||||
'grep "Disk.*bytes"' % partition_names).stdout
|
||||
partition_size_output = partition_size_output.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.execute_command(
|
||||
'mount ' + source_path + ' ' + destination_path)
|
||||
|
||||
def get_xen_user_metadata(self):
|
||||
command = 'xenstore-ls vm-data/user-metadata'
|
||||
output = self.ssh_client.execute_command(command).stdout
|
||||
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 get_xenstore_disk_config_value(self):
|
||||
"""Returns the xenstore value for disk config (True/False)"""
|
||||
command = 'xenstore-read vm-data/auto-disk-config'
|
||||
output = self.ssh_client.execute_command(command).stdout
|
||||
return output.strip().lower() == 'true'
|
||||
|
||||
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.execute_command(command).stdout
|
||||
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.execute_command(command)
|
||||
return output.rstrip('\n') == 'Directory found'
|
||||
|
||||
def get_directory_details(self, dirpath):
|
||||
"""
|
||||
@summary: Get the directory details
|
||||
@param direpath: Path to the directory
|
||||
@type dirpath: string
|
||||
@return: Directory details including permissions and content
|
||||
@rtype: DirectoryDetails
|
||||
"""
|
||||
output = self.is_directory_present(dirpath)
|
||||
if not output:
|
||||
raise DirectoryNotFoundException(
|
||||
"Directory: {0} not found.".format(dirpath))
|
||||
dir_permissions = self.ssh_client.execute_command(
|
||||
"stat -c %a {0}".format(dirpath)).stdout.rstrip("\n")
|
||||
dir_size = float(self.ssh_client.execute_command(
|
||||
"du -s {0}".format(dirpath)).stdout.split('\t', 1)[0])
|
||||
return DirectoryDetails(dir_permissions, dir_size, dirpath)
|
||||
|
||||
def get_block_devices(self):
|
||||
disks_raw = self.ssh_client.execute_command('lsblk -dn').stdout
|
||||
disks_raw_list = disks_raw.split('\n')
|
||||
devices = []
|
||||
for disk in disks_raw_list:
|
||||
disk_params = disk.split()
|
||||
if disk_params:
|
||||
devices.append({'name': disk_params[0],
|
||||
'size': disk_params[3]})
|
||||
return devices
|
@ -1,15 +0,0 @@
|
||||
"""
|
||||
Copyright 2013 Rackspace
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
@ -1,33 +0,0 @@
|
||||
"""
|
||||
Copyright 2013 Rackspace
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
from cloudcafe.compute.common.equality_tools import EqualityTools
|
||||
|
||||
|
||||
class DirectoryDetails:
|
||||
"""
|
||||
@summary: Represents Directory details
|
||||
"""
|
||||
def __init__(self, absolute_permissions, size, name):
|
||||
self.absolute_permissions = absolute_permissions
|
||||
self.size = size
|
||||
self.name = name
|
||||
|
||||
def __eq__(self, other):
|
||||
return EqualityTools.are_objects_equal(self, other)
|
||||
|
||||
def __ne__(self, other):
|
||||
return not self == other
|
@ -1,30 +0,0 @@
|
||||
"""
|
||||
Copyright 2013 Rackspace
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
from cloudcafe.compute.common.equality_tools import EqualityTools
|
||||
|
||||
|
||||
class FileDetails:
|
||||
"""
|
||||
@summary: Represents File details
|
||||
"""
|
||||
def __init__(self, absolute_permissions, content, name):
|
||||
self.absolute_permissions = absolute_permissions
|
||||
self.content = content
|
||||
self.name = name
|
||||
|
||||
def __eq__(self, other):
|
||||
return EqualityTools.are_objects_equal(self, other)
|
@ -1,98 +0,0 @@
|
||||
"""
|
||||
Copyright 2013 Rackspace
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
from cloudcafe.compute.common.equality_tools import EqualityTools
|
||||
|
||||
|
||||
class Partition:
|
||||
"""
|
||||
@summary: Represents a Disk Partition
|
||||
"""
|
||||
def __init__(self, name, size, type):
|
||||
self.name = name
|
||||
self.size = size
|
||||
self.type = type
|
||||
|
||||
def __eq__(self, other):
|
||||
"""
|
||||
@summary: Overrides the default equals
|
||||
@param other: Partition object to compare with
|
||||
@type other: Partition
|
||||
@return: True if Partition objects are equal, False otherwise
|
||||
@rtype: bool
|
||||
"""
|
||||
return EqualityTools.are_objects_equal(self, other)
|
||||
|
||||
def __ne__(self, other):
|
||||
"""
|
||||
@summary: Overrides the default not-equals
|
||||
@param other: Partition object to compare with
|
||||
@type other: Partition
|
||||
@return: True if Partition objects are not equal, False otherwise
|
||||
@rtype: bool
|
||||
"""
|
||||
return not self == other
|
||||
|
||||
def __repr__(self):
|
||||
"""
|
||||
@summary: Return string representation of Partition
|
||||
@return: String representation of Partition
|
||||
@rtype: string
|
||||
"""
|
||||
return "Partition Name : %s, Size: %s, Type : %s" % (self.name,
|
||||
self.size,
|
||||
self.type)
|
||||
|
||||
|
||||
class DiskSize:
|
||||
"""
|
||||
@summary: Represents a Disk Size
|
||||
"""
|
||||
|
||||
def __init__(self, value, unit, leeway_for_disk_size=2):
|
||||
self.value = float(value)
|
||||
self.unit = unit
|
||||
self.leeway_for_disk_size = leeway_for_disk_size
|
||||
|
||||
def __eq__(self, other):
|
||||
"""
|
||||
@summary: Overrides the default equals
|
||||
@param other: DiskSize object to compare with
|
||||
@type other: DiskSize
|
||||
@return: True if DiskSize objects are equal, False otherwise
|
||||
@rtype: bool
|
||||
"""
|
||||
return self.unit == other.unit and EqualityTools.are_sizes_equal(
|
||||
self.value, other.value,
|
||||
self.leeway_for_disk_size)
|
||||
|
||||
def __ne__(self, other):
|
||||
"""
|
||||
@summary: Overrides the default not-equals
|
||||
@param other: DiskSize object to compare with
|
||||
@type other: DiskSize
|
||||
@return: True if DiskSize objects are not equal, False otherwise
|
||||
@rtype: bool
|
||||
"""
|
||||
return not self == other
|
||||
|
||||
def __repr__(self):
|
||||
"""
|
||||
@summary: Return string representation of DiskSize
|
||||
@return: String representation of DiskSize
|
||||
@rtype: string
|
||||
"""
|
||||
return "Disk Size : %s %s" % (self.value, self.unit)
|
@ -1,15 +0,0 @@
|
||||
"""
|
||||
Copyright 2013 Rackspace
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
@ -1,19 +0,0 @@
|
||||
"""
|
||||
Copyright 2013 Rackspace
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
|
||||
class WindowsClient:
|
||||
pass
|
Loading…
x
Reference in New Issue
Block a user