kloudbuster/kloudbuster/base_compute.py

293 lines
10 KiB
Python

# Copyright 2015 Cisco Systems, Inc. All rights reserved.
#
# 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 os
import time
import log as logging
LOG = logging.getLogger(__name__)
class KBVolAttachException(Exception):
pass
class BaseCompute(object):
"""
The Base class for nova compute resources
1. Creates virtual machines with specific configs
"""
def __init__(self, vm_name, network):
self.novaclient = network.router.user.nova_client
self.network = network
self.res_logger = network.res_logger
self.vm_name = vm_name
self.instance = None
self.host = None
self.fip = None
self.fip_ip = None
self.subnet_ip = None
self.fixed_ip = None
self.ssh_ip = None
# Shared interface ip for tested and testing cloud
self.shared_interface_ip = None
self.vol = None
# Create a server instance with associated
# security group, keypair with a provided public key
def create_server(self, image_name, flavor_type, keyname,
nic, sec_group, avail_zone=None, user_data=None,
config_drive=None, retry_count=100):
"""
Create a VM instance given following parameters
1. VM Name
2. Image Name
3. Flavor name
4. key pair name
5. Security group instance
6. Optional parameters: availability zone, user data, config drive
"""
# Get the image id and flavor id from their logical names
image = self.find_image(image_name)
flavor_type = self.find_flavor(flavor_type)
# Also attach the created security group for the test
instance = self.novaclient.servers.create(name=self.vm_name,
image=image,
flavor=flavor_type,
key_name=keyname,
nics=nic,
availability_zone=avail_zone,
userdata=user_data,
config_drive=config_drive,
security_groups=[sec_group.id])
self.res_logger.log('instances', self.vm_name, instance.id)
if not instance:
return None
# Verify that the instance gets into the ACTIVE state
for _ in range(retry_count):
instance = self.novaclient.servers.get(instance.id)
if instance.status == 'ACTIVE':
self.instance = instance
if 'OS-EXT-SRV-ATTR:hypervisor_hostname' in vars(instance):
self.host = vars(instance)['OS-EXT-SRV-ATTR:hypervisor_hostname']
else:
self.host = "Unknown"
return instance
if instance.status == 'ERROR':
LOG.error('Instance creation error:' + instance.fault['message'])
return None
time.sleep(2)
def attach_vol(self):
if self.vol.status != 'available':
raise KBVolAttachException('Volume must be in available status before attaching.')
for _ in range(10):
try:
self.novaclient.volumes.create_server_volume(self.instance.id, self.vol.id)
break
except Exception:
time.sleep(1)
def get_server_list(self):
servers_list = self.novaclient.servers.list()
return servers_list
def delete_server(self):
# First delete the instance
if self.instance:
self.novaclient.servers.delete(self.instance)
self.instance = None
def detach_vol(self):
if self.instance and self.vol:
attached_vols = self.novaclient.volumes.get_server_volumes(self.instance.id)
if len(attached_vols):
self.novaclient.volumes.delete_server_volume(self.instance.id, self.vol.id)
def find_image(self, image_name):
"""
Given a image name return the image id
"""
try:
image = self.novaclient.images.find(name=image_name)
return image
except Exception:
return None
def find_flavor(self, flavor_type):
"""
Given a named flavor return the flavor
"""
flavor = self.novaclient.flavors.find(name=flavor_type)
return flavor
class SecGroup(object):
def __init__(self, novaclient):
self.secgroup = None
self.secgroup_name = None
self.novaclient = novaclient
def create_secgroup_with_rules(self, group_name):
group = self.novaclient.security_groups.create(name=group_name,
description="Test sec group")
# Allow ping traffic
self.novaclient.security_group_rules.create(group.id,
ip_protocol="icmp",
from_port=-1,
to_port=-1)
# Allow SSH traffic
self.novaclient.security_group_rules.create(group.id,
ip_protocol="tcp",
from_port=22,
to_port=22)
# Allow HTTP traffic
self.novaclient.security_group_rules.create(group.id,
ip_protocol="tcp",
from_port=80,
to_port=80)
# Allow Redis traffic
self.novaclient.security_group_rules.create(group.id,
ip_protocol="tcp",
from_port=6379,
to_port=6379)
# Allow Nuttcp traffic
self.novaclient.security_group_rules.create(group.id,
ip_protocol="tcp",
from_port=5001,
to_port=5002)
self.novaclient.security_group_rules.create(group.id,
ip_protocol="udp",
from_port=5001,
to_port=5001)
self.secgroup = group
self.secgroup_name = group_name
def delete_secgroup(self):
"""
Delete the security group
Sometimes this maybe in use if instance is just deleted
Add a retry mechanism
"""
if not self.secgroup:
return True
for _ in range(10):
try:
self.novaclient.security_groups.delete(self.secgroup)
return True
except Exception:
time.sleep(2)
LOG.error('Failed while deleting security group %s.' % self.secgroup.id)
return False
class KeyPair(object):
def __init__(self, novaclient):
self.keypair = None
self.keypair_name = None
self.novaclient = novaclient
def add_public_key(self, name, public_key_file=None):
"""
Add the KloudBuster public key to openstack
"""
public_key = None
try:
with open(os.path.expanduser(public_key_file)) as pkf:
public_key = pkf.read()
except IOError as exc:
LOG.error("Cannot open public key file %s: %s" % (public_key_file,
exc))
LOG.info("Adding public key %s" % name)
keypair = self.novaclient.keypairs.create(name, public_key)
self.keypair = keypair
self.keypair_name = name
def remove_public_key(self):
"""
Remove the keypair created by KloudBuster
"""
if self.keypair:
self.novaclient.keypairs.delete(self.keypair)
class Flavor(object):
def __init__(self, novaclient):
self.novaclient = novaclient
def get(self, name):
flavor = None
try:
flavor = vars(self.novaclient.flavors.find(name=name))
except Exception:
pass
return flavor
def list(self):
return self.novaclient.flavors.list()
def create_flavor(self, name, ram, vcpus, disk, ephemeral, override=False):
# Creating flavors
if override:
self.delete_flavor(name)
return self.novaclient.flavors.create(name=name, ram=ram, vcpus=vcpus,
disk=disk, ephemeral=ephemeral)
def delete_flavor(self, name):
try:
flavor = self.novaclient.flavors.find(name=name)
flavor.delete()
except Exception:
pass
class NovaQuota(object):
def __init__(self, novaclient, tenant_id):
self.novaclient = novaclient
self.tenant_id = tenant_id
def get(self):
return vars(self.novaclient.quotas.get(self.tenant_id))
def update_quota(self, **kwargs):
self.novaclient.quotas.update(self.tenant_id, **kwargs)
class CinderQuota(object):
def __init__(self, cinderclient, tenant_id):
self.cinderclient = cinderclient
self.tenant_id = tenant_id
def get(self):
return vars(self.cinderclient.quotas.get(self.tenant_id))
def update_quota(self, **kwargs):
self.cinderclient.quotas.update(self.tenant_id, **kwargs)