tox: fix testing issues after VM build
[nfvbench.git] / nfvbench / compute.py
1 # Copyright 2016 Cisco Systems, Inc.  All rights reserved.
2 #
3 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
4 #    not use this file except in compliance with the License. You may obtain
5 #    a copy of the License at
6 #
7 #         http://www.apache.org/licenses/LICENSE-2.0
8 #
9 #    Unless required by applicable law or agreed to in writing, software
10 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 #    License for the specific language governing permissions and limitations
13 #    under the License.
14 """Module to interface with nova and glance."""
15
16 import time
17 import traceback
18
19 from glanceclient import exc as glance_exception
20 try:
21     from glanceclient.openstack.common.apiclient.exceptions import NotFound as GlanceImageNotFound
22 except ImportError:
23     from glanceclient.v1.apiclient.exceptions import NotFound as GlanceImageNotFound
24 import keystoneauth1
25 import novaclient
26 from novaclient.exceptions import NotFound
27
28 from .log import LOG
29 from . import utils
30
31
32 class Compute(object):
33     """Class to interface with nova and glance."""
34
35     def __init__(self, nova_client, glance_client, config):
36         """Create a new compute instance to interact with nova and glance."""
37         self.novaclient = nova_client
38         self.glance_client = glance_client
39         self.config = config
40
41     def find_image(self, image_name):
42         """Find an image by name."""
43         try:
44             return next(self.glance_client.images.list(filters={'name': image_name}), None)
45         except (novaclient.exceptions.NotFound, keystoneauth1.exceptions.http.NotFound,
46                 GlanceImageNotFound):
47             pass
48         return None
49
50     def upload_image_via_url(self, final_image_name, image_file, retry_count=60):
51         """Directly upload image to Nova via URL if image is not present."""
52         retry = 0
53         try:
54             # check image is file/url based.
55             with open(image_file, 'rb') as f_image:
56                 img = self.glance_client.images.create(name=str(final_image_name),
57                                                        disk_format="qcow2",
58                                                        container_format="bare",
59                                                        visibility="public")
60                 self.glance_client.images.upload(img.id, image_data=f_image)
61             # Check for the image in glance
62             while img.status in ['queued', 'saving'] and retry < retry_count:
63                 img = self.glance_client.images.get(img.id)
64                 retry += 1
65                 LOG.debug("Image not yet active, retrying %s of %s...", retry, retry_count)
66                 time.sleep(self.config.generic_poll_sec)
67             if img.status != 'active':
68                 LOG.error("Image uploaded but too long to get to active state")
69                 raise Exception("Image update active state timeout")
70         except glance_exception.HTTPForbidden:
71             LOG.error("Cannot upload image without admin access. Please make "
72                       "sure the image is uploaded and is either public or owned by you.")
73             return False
74         except IOError:
75             # catch the exception for file based errors.
76             LOG.error("Failed while uploading the image. Please make sure the "
77                       "image at the specified location %s is correct.", image_file)
78             return False
79         except keystoneauth1.exceptions.http.NotFound as exc:
80             LOG.error("Authentication error while uploading the image: %s", str(exc))
81             return False
82         except Exception:
83             LOG.error(traceback.format_exc())
84             LOG.error("Failed to upload image %s.", image_file)
85             return False
86         return True
87
88     def delete_image(self, img_name):
89         """Delete an image by name."""
90         try:
91             LOG.log("Deleting image %s...", img_name)
92             img = self.find_image(image_name=img_name)
93             self.glance_client.images.delete(img.id)
94         except Exception:
95             LOG.error("Failed to delete the image %s.", img_name)
96             return False
97
98         return True
99
100     def image_multiqueue_enabled(self, img):
101         """Check if multiqueue property is enabled on given image."""
102         try:
103             return img['hw_vif_multiqueue_enabled'] == 'true'
104         except KeyError:
105             return False
106
107     def image_set_multiqueue(self, img, enabled):
108         """Set multiqueue property as enabled or disabled on given image."""
109         cur_mqe = self.image_multiqueue_enabled(img)
110         LOG.info('Image %s hw_vif_multiqueue_enabled property is "%s"',
111                  img.name, str(cur_mqe).lower())
112         if cur_mqe != enabled:
113             mqe = str(enabled).lower()
114             self.glance_client.images.update(img.id, hw_vif_multiqueue_enabled=mqe)
115             img['hw_vif_multiqueue_enabled'] = mqe
116             LOG.info('Image %s hw_vif_multiqueue_enabled property changed to "%s"', img.name, mqe)
117
118     # Create a server instance with name vmname
119     # and check that it gets into the ACTIVE state
120     def create_server(self, vmname, image, flavor, key_name,
121                       nic, sec_group, avail_zone=None, user_data=None,
122                       config_drive=None, files=None):
123         """Create a new server."""
124         if sec_group:
125             security_groups = [sec_group['id']]
126         else:
127             security_groups = None
128
129         # Also attach the created security group for the test
130         LOG.info('Creating instance %s with AZ: "%s"', vmname, avail_zone)
131         instance = self.novaclient.servers.create(name=vmname,
132                                                   image=image,
133                                                   flavor=flavor,
134                                                   key_name=key_name,
135                                                   nics=nic,
136                                                   availability_zone=avail_zone,
137                                                   userdata=user_data,
138                                                   config_drive=config_drive,
139                                                   files=files,
140                                                   security_groups=security_groups)
141         return instance
142
143     def poll_server(self, instance):
144         """Poll a server from its reference."""
145         return self.novaclient.servers.get(instance.id)
146
147     def get_server_list(self):
148         """Get the list of all servers."""
149         servers_list = self.novaclient.servers.list()
150         return servers_list
151
152     def instance_exists(self, server):
153         try:
154             self.novaclient.servers.get(server)
155         except NotFound:
156             return False
157         return True
158
159     def delete_server(self, server):
160         """Delete a server from its object reference."""
161         utils.delete_server(self.novaclient, server)
162         utils.waiting_servers_deletion(self.novaclient, [server])
163
164     def find_flavor(self, flavor_type):
165         """Find a flavor by name."""
166         try:
167             flavor = self.novaclient.flavors.find(name=flavor_type)
168             return flavor
169         except Exception:
170             return None
171
172     def create_flavor(self, name, ram, vcpus, disk, ephemeral=0):
173         """Create a flavor."""
174         return self.novaclient.flavors.create(name=name, ram=ram, vcpus=vcpus, disk=disk,
175                                               ephemeral=ephemeral)
176
177     def get_hypervisor(self, hyper_name):
178         """Get the hypervisor from its name.
179
180         Can raise novaclient.exceptions.NotFound
181         """
182         # first get the id from name
183         hyper = self.novaclient.hypervisors.search(hyper_name)[0]
184         # get full hypervisor object
185         return self.novaclient.hypervisors.get(hyper.id)