"Fossies" - the Fresh Open Source Software Archive

Member "horizon-20.1.2/openstack_dashboard/dashboards/project/instances/tests.py" (29 Apr 2022, 243255 Bytes) of package /linux/misc/openstack/horizon-20.1.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "tests.py": 20.1.1_vs_20.1.2.

    1 # Copyright 2012 United States Government as represented by the
    2 # Administrator of the National Aeronautics and Space Administration.
    3 # All Rights Reserved.
    4 #
    5 # Copyright 2012 Nebula, Inc.
    6 #
    7 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
    8 #    not use this file except in compliance with the License. You may obtain
    9 #    a copy of the License at
   10 #
   11 #         http://www.apache.org/licenses/LICENSE-2.0
   12 #
   13 #    Unless required by applicable law or agreed to in writing, software
   14 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
   15 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
   16 #    License for the specific language governing permissions and limitations
   17 #    under the License.
   18 
   19 import collections
   20 import json
   21 import logging
   22 import sys
   23 from unittest import mock
   24 
   25 from django.conf import settings
   26 from django.forms import widgets
   27 from django import http
   28 import django.test
   29 from django.test.utils import override_settings
   30 from django.urls import reverse
   31 from django.utils.http import urlencode
   32 from novaclient import api_versions
   33 
   34 from horizon import exceptions
   35 from horizon import forms
   36 from horizon.workflows import views
   37 from openstack_dashboard import api
   38 from openstack_dashboard.api import cinder
   39 from openstack_dashboard.dashboards.project.instances import console
   40 from openstack_dashboard.dashboards.project.instances import tables
   41 from openstack_dashboard.dashboards.project.instances import tabs
   42 from openstack_dashboard.dashboards.project.instances import workflows
   43 from openstack_dashboard.test import helpers
   44 from openstack_dashboard.usage import quotas
   45 from openstack_dashboard.views import get_url_with_pagination
   46 
   47 
   48 INDEX_TEMPLATE = 'horizon/common/_data_table_view.html'
   49 INDEX_URL = reverse('horizon:project:instances:index')
   50 SEC_GROUP_ROLE_PREFIX = \
   51     workflows.update_instance.INSTANCE_SEC_GROUP_SLUG + "_role_"
   52 AVAILABLE = api.cinder.VOLUME_STATE_AVAILABLE
   53 VOLUME_SEARCH_OPTS = dict(status=AVAILABLE, bootable=True)
   54 VOLUME_BOOTABLE_SEARCH_OPTS = dict(bootable=True)
   55 SNAPSHOT_SEARCH_OPTS = dict(status=AVAILABLE)
   56 
   57 
   58 class InstanceTestBase(helpers.ResetImageAPIVersionMixin,
   59                        helpers.TestCase):
   60     def _assert_mock_image_list_detailed_calls(self):
   61         expected_calls = [
   62             mock.call(helpers.IsHttpRequest()),
   63             mock.call(
   64                 helpers.IsHttpRequest(),
   65                 filters={'visibility': 'community'}
   66             )
   67         ]
   68         self.mock_image_list_detailed.assert_has_calls(expected_calls, False)
   69 
   70     def _assert_mock_image_list_detailed_calls_double(self):
   71         expected_calls = [
   72             mock.call(helpers.IsHttpRequest()),
   73             mock.call(
   74                 helpers.IsHttpRequest(),
   75                 filters={'visibility': 'community'}
   76             ),
   77             mock.call(helpers.IsHttpRequest()),
   78             mock.call(
   79                 helpers.IsHttpRequest(),
   80                 filters={'visibility': 'community'}
   81             )
   82         ]
   83         self.mock_image_list_detailed.assert_has_calls(expected_calls, False)
   84 
   85     def setUp(self):
   86         super().setUp()
   87         if api.glance.VERSIONS.active < 2:
   88             self.versioned_images = self.images
   89             self.versioned_snapshots = self.snapshots
   90         else:
   91             self.versioned_images = self.imagesV2
   92             self.versioned_snapshots = self.snapshotsV2
   93 
   94 
   95 class InstanceTableTestMixin(object):
   96 
   97     def _mock_glance_image_list_detailed(self, image_list):
   98         self.mock_image_list_detailed.side_effect = [
   99             [image_list, False, False],
  100             [[], False, False],
  101         ]
  102 
  103     def _check_glance_image_list_detailed(self, count=None):
  104         if count is None:
  105             count = 2
  106         self.mock_image_list_detailed.assert_has_calls([
  107             mock.call(helpers.IsHttpRequest(),
  108                       filters={'is_public': True, 'status': 'active'}),
  109             mock.call(helpers.IsHttpRequest(),
  110                       filters={'property-owner_id': self.tenant.id,
  111                                'status': 'active'}),
  112         ])
  113         self.assertEqual(count, self.mock_image_list_detailed.call_count)
  114 
  115     def _mock_neutron_network_and_port_list(self):
  116         self.mock_network_list.side_effect = [
  117             self.networks.list()[:1],
  118             self.networks.list()[1:],
  119             self.networks.list()[:1],
  120             self.networks.list()[1:],
  121         ]
  122         self.mock_port_list_with_trunk_types.return_value = self.ports.list()
  123 
  124     def _check_neutron_network_and_port_list(self):
  125         self.assertEqual(4, self.mock_network_list.call_count)
  126         self.mock_network_list.assert_has_calls([
  127             mock.call(helpers.IsHttpRequest(), tenant_id=self.tenant.id,
  128                       shared=False),
  129             mock.call(helpers.IsHttpRequest(), shared=True),
  130             mock.call(helpers.IsHttpRequest(), tenant_id=self.tenant.id,
  131                       shared=False),
  132             mock.call(helpers.IsHttpRequest(), shared=True),
  133         ])
  134         self.assertEqual(len(self.networks.list()),
  135                          self.mock_port_list_with_trunk_types.call_count)
  136         self.mock_port_list_with_trunk_types(
  137             [mock.call(helpers.IsHttpRequest(),
  138                        network_id=net.id,
  139                        tenant_id=self.tenant.id)
  140              for net in self.networks.list()])
  141 
  142     def _mock_nova_lists(self):
  143         self.mock_flavor_list.return_value = self.flavors.list()
  144         self.mock_keypair_list.return_value = self.keypairs.list()
  145         self.mock_security_group_list.return_value = \
  146             self.security_groups.list()
  147         self.mock_availability_zone_list.return_value = \
  148             self.availability_zones.list()
  149         self.mock_server_group_list.return_value = self.server_groups.list()
  150 
  151     def _check_nova_lists(self, flavor_count=None):
  152         if flavor_count is None:
  153             flavor_count = 1
  154         self.assert_mock_multiple_calls_with_same_arguments(
  155             self.mock_flavor_list, flavor_count,
  156             mock.call(helpers.IsHttpRequest()))
  157         self.mock_keypair_list.assert_called_once_with(helpers.IsHttpRequest())
  158         self.mock_security_group_list.assert_called_once_with(
  159             helpers.IsHttpRequest())
  160         self.mock_availability_zone_list.assert_called_once_with(
  161             helpers.IsHttpRequest())
  162         self.mock_server_group_list.assert_called_once_with(
  163             helpers.IsHttpRequest())
  164 
  165     def _mock_nova_glance_neutron_lists(self):
  166         self._mock_nova_lists()
  167         self._mock_glance_image_list_detailed(
  168             self.versioned_images.list())
  169         self._mock_neutron_network_and_port_list()
  170 
  171     def _check_nova_glance_neutron_lists(self, return_value=True,
  172                                          flavor_count=None,
  173                                          image_count=None):
  174         self._check_nova_lists(flavor_count=flavor_count)
  175         self._check_glance_image_list_detailed(count=image_count)
  176         self._check_neutron_network_and_port_list()
  177 
  178 
  179 class InstanceTableTests(InstanceTestBase, InstanceTableTestMixin):
  180 
  181     @helpers.create_mocks({
  182         api.nova: (
  183             'flavor_list',
  184             'server_list_paged',
  185             'tenant_absolute_limits',
  186             'is_feature_available',
  187         ),
  188         api.glance: ('image_list_detailed',),
  189         api.neutron: (
  190             'floating_ip_simple_associate_supported',
  191             'floating_ip_supported',
  192         ),
  193         api.network: (
  194             'servers_update_addresses',
  195         ),
  196         api.cinder: ('volume_list',),
  197     }, stop_mock=False)
  198     # NOTE: _get_index() and _check_get_index() are used as pair
  199     # and the test logic will be placed between these calls,
  200     # so we cannot stop mocking when exiting this method.
  201     def _get_index(self, use_servers_update_address=True):
  202         servers = self.servers.list()
  203         self.mock_is_feature_available.return_value = True
  204         self.mock_flavor_list.return_value = self.flavors.list()
  205         self.mock_image_list_detailed.return_value = \
  206             (self.images.list(), False, False)
  207         self.mock_server_list_paged.return_value = [servers, False, False]
  208         self.mock_servers_update_addresses.return_value = None
  209         self.mock_tenant_absolute_limits.return_value = \
  210             self.limits['absolute']
  211         self.mock_floating_ip_supported.return_value = True
  212         self.mock_floating_ip_simple_associate_supported.return_value = True
  213         return self.client.get(INDEX_URL)
  214 
  215     def _check_get_index(self, use_servers_update_address=True,
  216                          multiplier=5):
  217         expected_feature_count = 2 * multiplier
  218         expected_fip_supported_count = 2 * multiplier
  219         expected_simple_fip_supported = 1 * multiplier
  220 
  221         self.assert_mock_multiple_calls_with_same_arguments(
  222             self.mock_is_feature_available, expected_feature_count,
  223             mock.call(helpers.IsHttpRequest(), 'locked_attribute'))
  224         self.mock_flavor_list.assert_called_once_with(helpers.IsHttpRequest())
  225         self._assert_mock_image_list_detailed_calls()
  226 
  227         search_opts = {'marker': None, 'paginate': True}
  228         self.mock_server_list_paged.assert_called_once_with(
  229             helpers.IsHttpRequest(),
  230             sort_dir='desc',
  231             search_opts=search_opts)
  232         if use_servers_update_address:
  233             servers = self.servers.list()
  234             self.mock_servers_update_addresses.assert_called_once_with(
  235                 helpers.IsHttpRequest(), servers)
  236         else:
  237             self.assertEqual(0, self.mock_servers_update_addresses.call_count)
  238         self.assert_mock_multiple_calls_with_same_arguments(
  239             self.mock_tenant_absolute_limits, 2,
  240             mock.call(helpers.IsHttpRequest(), reserved=True))
  241         if expected_fip_supported_count is None:
  242             expected_fip_supported_count = 8
  243         self.assert_mock_multiple_calls_with_same_arguments(
  244             self.mock_floating_ip_supported, expected_fip_supported_count,
  245             mock.call(helpers.IsHttpRequest()))
  246         self.assert_mock_multiple_calls_with_same_arguments(
  247             self.mock_floating_ip_simple_associate_supported,
  248             expected_simple_fip_supported,
  249             mock.call(helpers.IsHttpRequest()))
  250 
  251     def test_index(self):
  252 
  253         res = self._get_index()
  254 
  255         self.assertTemplateUsed(res, INDEX_TEMPLATE)
  256         instances = res.context['instances_table'].data
  257 
  258         self.assertCountEqual(instances, self.servers.list())
  259         self.assertNotContains(res, "Launch Instance (Quota exceeded)")
  260         self._check_get_index()
  261 
  262     @override_settings(OPENSTACK_INSTANCE_RETRIEVE_IP_ADDRESSES=False)
  263     def test_index_without_servers_update_addresses(self):
  264         res = self._get_index(use_servers_update_address=False)
  265 
  266         self.assertTemplateUsed(res, INDEX_TEMPLATE)
  267         instances = res.context['instances_table'].data
  268 
  269         self.assertCountEqual(instances, self.servers.list())
  270         self.assertNotContains(res, "Launch Instance (Quota exceeded)")
  271         self._check_get_index(use_servers_update_address=False)
  272 
  273     @helpers.create_mocks({
  274         api.nova: ('server_list_paged',
  275                    'tenant_absolute_limits',
  276                    'flavor_list'),
  277         api.glance: ('image_list_detailed',),
  278         api.cinder: ('volume_list',),
  279     })
  280     def test_index_server_list_exception(self):
  281         search_opts = {'marker': None, 'paginate': True}
  282         flavors = self.flavors.list()
  283         images = self.images.list()
  284         self.mock_flavor_list.return_value = flavors
  285         self.mock_image_list_detailed.return_value = (images, False, False)
  286         self.mock_server_list_paged.side_effect = self.exceptions.nova
  287         self.mock_tenant_absolute_limits.return_value = self.limits['absolute']
  288 
  289         res = self.client.get(INDEX_URL)
  290 
  291         self.assertTemplateUsed(res, INDEX_TEMPLATE)
  292         self.assertEqual(len(res.context['instances_table'].data), 0)
  293         self.assertMessageCount(res, error=1)
  294         self.mock_flavor_list.assert_called_once_with(helpers.IsHttpRequest())
  295         self._assert_mock_image_list_detailed_calls()
  296 
  297         self.mock_server_list_paged.assert_called_once_with(
  298             helpers.IsHttpRequest(),
  299             sort_dir='desc',
  300             search_opts=search_opts)
  301         self.assert_mock_multiple_calls_with_same_arguments(
  302             self.mock_tenant_absolute_limits, 2,
  303             mock.call(helpers.IsHttpRequest(), reserved=True))
  304 
  305     @helpers.create_mocks({
  306         api.nova: ('flavor_list',
  307                    'server_list_paged',
  308                    'flavor_get',
  309                    'tenant_absolute_limits',
  310                    'is_feature_available',),
  311         api.glance: ('image_list_detailed',),
  312         api.neutron: ('floating_ip_simple_associate_supported',
  313                       'floating_ip_supported',),
  314         api.network: ('servers_update_addresses',),
  315         api.cinder: ('volume_list',),
  316     })
  317     def test_index_flavor_list_exception(self):
  318         servers = self.servers.list()
  319         search_opts = {'marker': None, 'paginate': True}
  320 
  321         self.mock_is_feature_available.return_value = True
  322         self.mock_server_list_paged.return_value = [servers, False, False]
  323         self.mock_servers_update_addresses.return_value = None
  324         self.mock_flavor_list.side_effect = self.exceptions.nova
  325         self.mock_image_list_detailed.return_value = (self.images.list(),
  326                                                       False, False)
  327         self.mock_tenant_absolute_limits.return_value = self.limits['absolute']
  328         self.mock_floating_ip_supported.return_value = True
  329         self.mock_floating_ip_simple_associate_supported.return_value = True
  330 
  331         res = self.client.get(INDEX_URL)
  332 
  333         self.assertTemplateUsed(res, INDEX_TEMPLATE)
  334         instances = res.context['instances_table'].data
  335 
  336         self.assertCountEqual(instances, self.servers.list())
  337 
  338         self.assert_mock_multiple_calls_with_same_arguments(
  339             self.mock_is_feature_available, 10,
  340             mock.call(helpers.IsHttpRequest(), 'locked_attribute'))
  341         self.mock_server_list_paged.assert_called_once_with(
  342             helpers.IsHttpRequest(),
  343             sort_dir='desc',
  344             search_opts=search_opts)
  345         self.mock_servers_update_addresses.assert_called_once_with(
  346             helpers.IsHttpRequest(), servers)
  347         self.mock_flavor_list.assert_called_once_with(helpers.IsHttpRequest())
  348         self._assert_mock_image_list_detailed_calls()
  349 
  350         self.assert_mock_multiple_calls_with_same_arguments(
  351             self.mock_tenant_absolute_limits, 2,
  352             mock.call(helpers.IsHttpRequest(), reserved=True))
  353         self.assert_mock_multiple_calls_with_same_arguments(
  354             self.mock_floating_ip_supported, 10,
  355             mock.call(helpers.IsHttpRequest()))
  356         self.assert_mock_multiple_calls_with_same_arguments(
  357             self.mock_floating_ip_simple_associate_supported, 5,
  358             mock.call(helpers.IsHttpRequest()))
  359 
  360     @helpers.create_mocks({
  361         api.nova: ('flavor_list',
  362                    'server_list_paged',
  363                    'tenant_absolute_limits',
  364                    'is_feature_available',),
  365         api.glance: ('image_list_detailed',),
  366         api.neutron: ('floating_ip_simple_associate_supported',
  367                       'floating_ip_supported',),
  368         api.network: ('servers_update_addresses',),
  369         api.cinder: ('volume_list',),
  370     })
  371     def _test_index_with_instance_booted_from_volume(
  372             self, volume_image_metadata, expected_image_name):
  373         servers = self.servers.list()
  374         volume_server = servers[0]
  375         # Override the server is booted from a volume.
  376         volume_server.image = ""
  377         # NOTE(amotoki): openstack_dashboard.api.nova.server_list should return
  378         # a list of api.nova.Server instances, but the current test code
  379         # returns a list of novaclient.v2.servers.Server instances.
  380         # This leads to a situation that image_name property of api.nova.Server
  381         # is not handled in our test case properly.
  382         # TODO(amotoki): Refactor test_data/nova_data.py to use api.nova.Server
  383         # (horizon API wrapper class).
  384         volume_server = api.nova.Server(volume_server, self.request)
  385         servers[0] = volume_server
  386 
  387         volumes = self.cinder_volumes.list()
  388         # 3rd volume in the list is attached to server with ID 1.
  389         volume = volumes[2]
  390         volume.volume_image_metadata = volume_image_metadata
  391 
  392         self.mock_is_feature_available.return_value = True
  393         self.mock_server_list_paged.return_value = [servers, False, False]
  394         self.mock_servers_update_addresses.return_value = None
  395         self.mock_flavor_list.return_value = self.flavors.list()
  396         self.mock_image_list_detailed.return_value = (self.images.list(),
  397                                                       False, False)
  398         self.mock_tenant_absolute_limits.return_value = self.limits['absolute']
  399         self.mock_floating_ip_supported.return_value = True
  400         self.mock_floating_ip_simple_associate_supported.return_value = True
  401         self.mock_volume_list.return_value = volumes
  402 
  403         res = self.client.get(INDEX_URL)
  404 
  405         self.assertTemplateUsed(res, INDEX_TEMPLATE)
  406         instances = res.context['instances_table'].data
  407         self.assertEqual(len(instances), len(servers))
  408         if expected_image_name:
  409             self.assertContains(res, expected_image_name)
  410 
  411         self.assert_mock_multiple_calls_with_same_arguments(
  412             self.mock_is_feature_available, 10,
  413             mock.call(helpers.IsHttpRequest(), 'locked_attribute'))
  414         self.mock_flavor_list.assert_called_once_with(helpers.IsHttpRequest())
  415         self._assert_mock_image_list_detailed_calls()
  416 
  417         search_opts = {'marker': None, 'paginate': True}
  418         self.mock_server_list_paged.assert_called_once_with(
  419             helpers.IsHttpRequest(),
  420             sort_dir='desc',
  421             search_opts=search_opts)
  422         self.mock_servers_update_addresses.assert_called_once_with(
  423             helpers.IsHttpRequest(), servers)
  424         self.assert_mock_multiple_calls_with_same_arguments(
  425             self.mock_tenant_absolute_limits, 2,
  426             mock.call(helpers.IsHttpRequest(), reserved=True))
  427         self.assert_mock_multiple_calls_with_same_arguments(
  428             self.mock_floating_ip_supported, 10,
  429             mock.call(helpers.IsHttpRequest()))
  430         self.assert_mock_multiple_calls_with_same_arguments(
  431             self.mock_floating_ip_simple_associate_supported, 5,
  432             mock.call(helpers.IsHttpRequest()))
  433         self.mock_volume_list.assert_called_once_with(helpers.IsHttpRequest())
  434 
  435         return instances
  436 
  437     def test_index_with_instance_booted_from_volume(self):
  438         base_image = self.images.get(name='private_image')
  439         image_metadata = {
  440             "image_id": base_image.id
  441         }
  442         servers = self._test_index_with_instance_booted_from_volume(
  443             image_metadata, expected_image_name=base_image.name)
  444         self.assertEqual(base_image.name, servers[0].image.name)
  445 
  446     def test_index_with_instance_booted_from_volume_no_image_info(self):
  447         # Borrowed from bug #1834747
  448         image_metadata = {
  449             'hw_qemu_guest_agent': 'yes',
  450             'hw_vif_multiqueue_enabled': 'true',
  451             'os_require_quiesce': 'yes',
  452         }
  453         servers = self._test_index_with_instance_booted_from_volume(
  454             image_metadata, expected_image_name=None)
  455         self.assertEqual('', servers[0].image)
  456 
  457     def test_index_with_console_link(self):
  458         res = self._get_index()
  459 
  460         instances_table = res.context['instances_table']
  461         instances = res.context['instances_table'].data
  462         console_link_rendered = False
  463         for instance in instances:
  464             for action in instances_table.get_row_actions(instance):
  465                 if isinstance(action, tables.ConsoleLink):
  466                     console_link_rendered = True
  467                     break
  468             if console_link_rendered:
  469                 break
  470             self.assertTrue(console_link_rendered)
  471         self._check_get_index(multiplier=6)
  472 
  473     @django.test.utils.override_settings(CONSOLE_TYPE=None)
  474     def test_index_without_console_link(self):
  475         res = self._get_index()
  476 
  477         instances_table = res.context['instances_table']
  478         instances = res.context['instances_table'].data
  479         for instance in instances:
  480             for action in instances_table.get_row_actions(instance):
  481                 self.assertNotIsInstance(action, tables.ConsoleLink)
  482         self._check_get_index(multiplier=10)
  483 
  484     @helpers.create_mocks({api.nova: ('server_list_paged',
  485                                       'flavor_list',
  486                                       'server_delete',),
  487                            api.glance: ('image_list_detailed',),
  488                            api.network: ('servers_update_addresses',),
  489                            api.cinder: ('volume_list',)})
  490     def test_delete_instance(self):
  491         servers = self.servers.list()
  492         server = servers[0]
  493 
  494         self.mock_server_list_paged.return_value = [servers, False, False]
  495         self.mock_servers_update_addresses.return_value = None
  496         self.mock_flavor_list.return_value = self.flavors.list()
  497         self.mock_image_list_detailed.return_value = (self.images.list(),
  498                                                       False, False)
  499         self.mock_server_delete.return_value = None
  500         formData = {'action': 'instances__delete__%s' % server.id}
  501         res = self.client.post(INDEX_URL, formData)
  502 
  503         self.assertRedirectsNoFollow(res, INDEX_URL)
  504 
  505         search_opts = {'marker': None, 'paginate': True}
  506         self.mock_server_list_paged.assert_called_once_with(
  507             helpers.IsHttpRequest(),
  508             sort_dir='desc',
  509             search_opts=search_opts)
  510         self.mock_servers_update_addresses.assert_called_once_with(
  511             helpers.IsHttpRequest(), servers)
  512         self.mock_flavor_list.assert_called_once_with(helpers.IsHttpRequest())
  513         self._assert_mock_image_list_detailed_calls()
  514 
  515         self.mock_server_delete.assert_called_once_with(
  516             helpers.IsHttpRequest(), server.id)
  517 
  518     @helpers.create_mocks({api.nova: ('server_list_paged',
  519                                       'flavor_list',
  520                                       'server_delete',),
  521                            api.glance: ('image_list_detailed',),
  522                            api.network: ('servers_update_addresses',),
  523                            api.cinder: ('volume_list',)})
  524     def test_delete_instance_error_state(self):
  525         servers = self.servers.list()
  526         server = servers[0]
  527         server.status = 'ERROR'
  528 
  529         self.mock_server_list_paged.return_value = [servers, False, False]
  530         self.mock_servers_update_addresses.return_value = None
  531         self.mock_flavor_list.return_value = self.flavors.list()
  532         self.mock_image_list_detailed.return_value = (self.images.list(),
  533                                                       False, False)
  534         self.mock_server_delete.return_value = None
  535 
  536         formData = {'action': 'instances__delete__%s' % server.id}
  537         res = self.client.post(INDEX_URL, formData)
  538 
  539         self.assertRedirectsNoFollow(res, INDEX_URL)
  540 
  541         search_opts = {'marker': None, 'paginate': True}
  542         self.mock_server_list_paged.assert_called_once_with(
  543             helpers.IsHttpRequest(),
  544             sort_dir='desc',
  545             search_opts=search_opts)
  546         self.mock_servers_update_addresses.assert_called_once_with(
  547             helpers.IsHttpRequest(), servers)
  548         self.mock_flavor_list.assert_called_once_with(helpers.IsHttpRequest())
  549         self._assert_mock_image_list_detailed_calls()
  550         self.mock_server_delete.assert_called_once_with(
  551             helpers.IsHttpRequest(), server.id)
  552 
  553     @helpers.create_mocks({api.nova: ('server_list_paged',
  554                                       'flavor_list',
  555                                       'server_delete',),
  556                            api.glance: ('image_list_detailed',),
  557                            api.network: ('servers_update_addresses',),
  558                            api.cinder: ('volume_list',)})
  559     def test_delete_instance_exception(self):
  560         servers = self.servers.list()
  561         server = servers[0]
  562 
  563         self.mock_server_list_paged.return_value = [servers, False, False]
  564         self.mock_servers_update_addresses.return_value = None
  565         self.mock_flavor_list.return_value = self.flavors.list()
  566         self.mock_image_list_detailed.return_value = (self.images.list(),
  567                                                       False, False)
  568         self.mock_server_delete.side_effect = self.exceptions.nova
  569 
  570         formData = {'action': 'instances__delete__%s' % server.id}
  571         res = self.client.post(INDEX_URL, formData)
  572 
  573         self.assertRedirectsNoFollow(res, INDEX_URL)
  574 
  575         search_opts = {'marker': None, 'paginate': True}
  576         self.mock_server_list_paged.assert_called_once_with(
  577             helpers.IsHttpRequest(),
  578             sort_dir='desc',
  579             search_opts=search_opts)
  580         self.mock_servers_update_addresses.assert_called_once_with(
  581             helpers.IsHttpRequest(), servers)
  582         self.mock_flavor_list.assert_called_once_with(helpers.IsHttpRequest())
  583         self._assert_mock_image_list_detailed_calls()
  584         self.mock_server_delete.assert_called_once_with(
  585             helpers.IsHttpRequest(), server.id)
  586 
  587     @helpers.create_mocks({api.nova: ('server_pause',
  588                                       'server_list_paged',
  589                                       'flavor_list',
  590                                       'is_feature_available',),
  591                            api.glance: ('image_list_detailed',),
  592                            api.network: ('servers_update_addresses',),
  593                            api.cinder: ('volume_list',)})
  594     def test_pause_instance(self):
  595         servers = self.servers.list()
  596         server = servers[0]
  597 
  598         self.mock_flavor_list.return_value = self.flavors.list()
  599         self.mock_image_list_detailed.return_value = (self.images.list(),
  600                                                       False, False)
  601         self.mock_server_list_paged.return_value = [servers, False, False]
  602         self.mock_servers_update_addresses.return_value = None
  603         self.mock_server_pause.return_value = None
  604 
  605         formData = {'action': 'instances__pause__%s' % server.id}
  606         res = self.client.post(INDEX_URL, formData)
  607 
  608         self.assertRedirectsNoFollow(res, INDEX_URL)
  609 
  610         self.mock_flavor_list.assert_called_once_with(helpers.IsHttpRequest())
  611         self._assert_mock_image_list_detailed_calls()
  612         search_opts = {'marker': None, 'paginate': True}
  613         self.mock_server_list_paged.assert_called_once_with(
  614             helpers.IsHttpRequest(),
  615             sort_dir='desc',
  616             search_opts=search_opts)
  617         self.mock_servers_update_addresses.assert_called_once_with(
  618             helpers.IsHttpRequest(), servers)
  619         self.mock_server_pause.assert_called_once_with(
  620             helpers.IsHttpRequest(), server.id)
  621 
  622     @helpers.create_mocks({api.nova: ('server_pause',
  623                                       'server_list_paged',
  624                                       'flavor_list',
  625                                       'is_feature_available',),
  626                            api.glance: ('image_list_detailed',),
  627                            api.network: ('servers_update_addresses',),
  628                            api.cinder: ('volume_list',)})
  629     def test_pause_instance_exception(self):
  630         servers = self.servers.list()
  631         server = servers[0]
  632 
  633         self.mock_flavor_list.return_value = self.flavors.list()
  634         self.mock_image_list_detailed.return_value = (self.images.list(),
  635                                                       False, False)
  636         self.mock_server_list_paged.return_value = [servers, False, False]
  637         self.mock_servers_update_addresses.return_value = None
  638         self.mock_server_pause.side_effect = self.exceptions.nova
  639 
  640         formData = {'action': 'instances__pause__%s' % server.id}
  641         res = self.client.post(INDEX_URL, formData)
  642 
  643         self.assertRedirectsNoFollow(res, INDEX_URL)
  644 
  645         self.mock_flavor_list.assert_called_once_with(helpers.IsHttpRequest())
  646         self._assert_mock_image_list_detailed_calls()
  647         search_opts = {'marker': None, 'paginate': True}
  648         self.mock_server_list_paged.assert_called_once_with(
  649             helpers.IsHttpRequest(),
  650             sort_dir='desc',
  651             search_opts=search_opts)
  652         self.mock_servers_update_addresses.assert_called_once_with(
  653             helpers.IsHttpRequest(), servers)
  654         self.mock_server_pause.assert_called_once_with(
  655             helpers.IsHttpRequest(), server.id)
  656 
  657     @helpers.create_mocks({api.nova: ('server_unpause',
  658                                       'server_list_paged',
  659                                       'flavor_list',
  660                                       'is_feature_available',),
  661                            api.glance: ('image_list_detailed',),
  662                            api.network: ('servers_update_addresses',),
  663                            api.cinder: ('volume_list',)})
  664     def test_unpause_instance(self):
  665         servers = self.servers.list()
  666         server = servers[0]
  667         server.status = "PAUSED"
  668         self.mock_flavor_list.return_value = self.flavors.list()
  669         self.mock_image_list_detailed.return_value = (self.images.list(),
  670                                                       False, False)
  671         self.mock_server_list_paged.return_value = [servers, False, False]
  672         self.mock_servers_update_addresses.return_value = None
  673         self.mock_server_unpause.return_value = None
  674 
  675         formData = {'action': 'instances__pause__%s' % server.id}
  676         res = self.client.post(INDEX_URL, formData)
  677 
  678         self.assertRedirectsNoFollow(res, INDEX_URL)
  679 
  680         self.mock_flavor_list.assert_called_once_with(helpers.IsHttpRequest())
  681         self._assert_mock_image_list_detailed_calls()
  682 
  683         search_opts = {'marker': None, 'paginate': True}
  684         self.mock_server_list_paged.assert_called_once_with(
  685             helpers.IsHttpRequest(),
  686             sort_dir='desc',
  687             search_opts=search_opts)
  688         self.mock_servers_update_addresses.assert_called_once_with(
  689             helpers.IsHttpRequest(), servers)
  690         self.mock_server_unpause.assert_called_once_with(
  691             helpers.IsHttpRequest(), server.id)
  692 
  693     @helpers.create_mocks({api.nova: ('server_unpause',
  694                                       'server_list_paged',
  695                                       'flavor_list',
  696                                       'is_feature_available',),
  697                            api.glance: ('image_list_detailed',),
  698                            api.network: ('servers_update_addresses',),
  699                            api.cinder: ('volume_list',)})
  700     def test_unpause_instance_exception(self):
  701         servers = self.servers.list()
  702         server = servers[0]
  703         server.status = "PAUSED"
  704 
  705         self.mock_flavor_list.return_value = self.flavors.list()
  706         self.mock_image_list_detailed.return_value = (self.images.list(),
  707                                                       False, False)
  708         self.mock_server_list_paged.return_value = [servers, False, False]
  709         self.mock_servers_update_addresses.return_value = None
  710         self.mock_server_unpause.side_effect = self.exceptions.nova
  711 
  712         formData = {'action': 'instances__pause__%s' % server.id}
  713         res = self.client.post(INDEX_URL, formData)
  714 
  715         self.assertRedirectsNoFollow(res, INDEX_URL)
  716 
  717         self.mock_flavor_list.assert_called_once_with(helpers.IsHttpRequest())
  718         self._assert_mock_image_list_detailed_calls()
  719 
  720         search_opts = {'marker': None, 'paginate': True}
  721         self.mock_server_list_paged.assert_called_once_with(
  722             helpers.IsHttpRequest(),
  723             sort_dir='desc',
  724             search_opts=search_opts)
  725         self.mock_servers_update_addresses.assert_called_once_with(
  726             helpers.IsHttpRequest(), servers)
  727         self.mock_server_unpause.assert_called_once_with(
  728             helpers.IsHttpRequest(), server.id)
  729 
  730     @helpers.create_mocks({api.nova: ('server_reboot',
  731                                       'server_list_paged',
  732                                       'flavor_list',),
  733                            api.glance: ('image_list_detailed',),
  734                            api.network: ('servers_update_addresses',),
  735                            api.cinder: ('volume_list',)})
  736     def test_reboot_instance(self):
  737         servers = self.servers.list()
  738         server = servers[0]
  739 
  740         self.mock_flavor_list.return_value = self.flavors.list()
  741         self.mock_image_list_detailed.return_value = (self.images.list(),
  742                                                       False, False)
  743         self.mock_server_list_paged.return_value = [servers, False, False]
  744         self.mock_servers_update_addresses.return_value = None
  745         self.mock_server_reboot.return_value = None
  746 
  747         formData = {'action': 'instances__reboot__%s' % server.id}
  748         res = self.client.post(INDEX_URL, formData)
  749 
  750         self.assertRedirectsNoFollow(res, INDEX_URL)
  751 
  752         self.mock_flavor_list.assert_called_once_with(helpers.IsHttpRequest())
  753         self._assert_mock_image_list_detailed_calls()
  754 
  755         search_opts = {'marker': None, 'paginate': True}
  756         self.mock_server_list_paged.assert_called_once_with(
  757             helpers.IsHttpRequest(),
  758             sort_dir='desc',
  759             search_opts=search_opts)
  760         self.mock_servers_update_addresses.assert_called_once_with(
  761             helpers.IsHttpRequest(), servers)
  762         self.mock_server_reboot.assert_called_once_with(
  763             helpers.IsHttpRequest(), server.id, soft_reboot=False)
  764 
  765     @helpers.create_mocks({api.nova: ('server_reboot',
  766                                       'server_list_paged',
  767                                       'flavor_list',),
  768                            api.glance: ('image_list_detailed',),
  769                            api.network: ('servers_update_addresses',),
  770                            api.cinder: ('volume_list',)})
  771     def test_reboot_instance_exception(self):
  772         servers = self.servers.list()
  773         server = servers[0]
  774 
  775         self.mock_flavor_list.return_value = self.flavors.list()
  776         self.mock_image_list_detailed.return_value = (self.images.list(),
  777                                                       False, False)
  778         self.mock_server_list_paged.return_value = [servers, False, False]
  779         self.mock_servers_update_addresses.return_value = None
  780         self.mock_server_reboot.side_effect = self.exceptions.nova
  781 
  782         formData = {'action': 'instances__reboot__%s' % server.id}
  783         res = self.client.post(INDEX_URL, formData)
  784 
  785         self.assertRedirectsNoFollow(res, INDEX_URL)
  786 
  787         self.mock_flavor_list.assert_called_once_with(helpers.IsHttpRequest())
  788         self._assert_mock_image_list_detailed_calls()
  789 
  790         search_opts = {'marker': None, 'paginate': True}
  791         self.mock_server_list_paged.assert_called_once_with(
  792             helpers.IsHttpRequest(),
  793             sort_dir='desc',
  794             search_opts=search_opts)
  795         self.mock_servers_update_addresses.assert_called_once_with(
  796             helpers.IsHttpRequest(), servers)
  797         self.mock_server_reboot.assert_called_once_with(
  798             helpers.IsHttpRequest(), server.id, soft_reboot=False)
  799 
  800     @helpers.create_mocks({api.nova: ('server_reboot',
  801                                       'server_list_paged',
  802                                       'flavor_list',),
  803                            api.glance: ('image_list_detailed',),
  804                            api.network: ('servers_update_addresses',),
  805                            api.cinder: ('volume_list',)})
  806     def test_soft_reboot_instance(self):
  807         servers = self.servers.list()
  808         server = servers[0]
  809 
  810         self.mock_flavor_list.return_value = self.flavors.list()
  811         self.mock_image_list_detailed.return_value = (self.images.list(),
  812                                                       False, False)
  813         self.mock_server_list_paged.return_value = [servers, False, False]
  814         self.mock_servers_update_addresses.return_value = None
  815         self.mock_server_reboot.return_value = None
  816 
  817         formData = {'action': 'instances__soft_reboot__%s' % server.id}
  818         res = self.client.post(INDEX_URL, formData)
  819 
  820         self.assertRedirectsNoFollow(res, INDEX_URL)
  821 
  822         self.mock_flavor_list.assert_called_once_with(helpers.IsHttpRequest())
  823         self._assert_mock_image_list_detailed_calls()
  824 
  825         search_opts = {'marker': None, 'paginate': True}
  826         self.mock_server_list_paged.assert_called_once_with(
  827             helpers.IsHttpRequest(),
  828             sort_dir='desc',
  829             search_opts=search_opts)
  830         self.mock_servers_update_addresses.assert_called_once_with(
  831             helpers.IsHttpRequest(), servers)
  832         self.mock_server_reboot.assert_called_once_with(
  833             helpers.IsHttpRequest(), server.id, soft_reboot=True)
  834 
  835     @helpers.create_mocks({api.nova: ('server_suspend',
  836                                       'server_list_paged',
  837                                       'flavor_list',
  838                                       'is_feature_available',),
  839                            api.glance: ('image_list_detailed',),
  840                            api.network: ('servers_update_addresses',),
  841                            api.cinder: ('volume_list',)})
  842     def test_suspend_instance(self):
  843         servers = self.servers.list()
  844         server = servers[0]
  845 
  846         self.mock_flavor_list.return_value = self.flavors.list()
  847         self.mock_image_list_detailed.return_value = (self.images.list(),
  848                                                       False, False)
  849         self.mock_server_list_paged.return_value = [servers, False, False]
  850         self.mock_servers_update_addresses.return_value = None
  851         self.mock_server_suspend.return_value = None
  852 
  853         formData = {'action': 'instances__suspend__%s' % server.id}
  854         url = get_url_with_pagination(
  855             self.request, 'next', 'prev', 'horizon:project:instances:index')
  856         res = self.client.post(url, formData)
  857 
  858         self.assertRedirectsNoFollow(res, INDEX_URL)
  859 
  860         self.mock_flavor_list.assert_called_once_with(
  861             helpers.IsHttpRequest())
  862         self._assert_mock_image_list_detailed_calls()
  863 
  864         search_opts = {'marker': None, 'paginate': True}
  865         self.mock_server_list_paged.assert_called_once_with(
  866             helpers.IsHttpRequest(),
  867             sort_dir='desc',
  868             search_opts=search_opts)
  869         self.mock_servers_update_addresses.assert_called_once_with(
  870             helpers.IsHttpRequest(), servers)
  871         self.mock_server_suspend.assert_called_once_with(
  872             helpers.IsHttpRequest(), server.id)
  873 
  874     @django.test.utils.override_settings(API_RESULT_PAGE_SIZE=2)
  875     @helpers.create_mocks({api.nova: ('server_suspend',
  876                                       'server_list_paged',
  877                                       'flavor_list',
  878                                       'is_feature_available',),
  879                            api.glance: ('image_list_detailed',),
  880                            api.network: ('servers_update_addresses',),
  881                            api.cinder: ('volume_list',)})
  882     def test_suspend_instance_if_placed_on_2nd_page(self):
  883         page_size = settings.API_RESULT_PAGE_SIZE
  884         servers = self.servers.list()[:3]
  885 
  886         self.mock_flavor_list.return_value = self.flavors.list()
  887         self.mock_image_list_detailed.return_value = (self.images.list(),
  888                                                       False, False)
  889         self.mock_server_list_paged.return_value = [
  890             servers[page_size:], False, True]
  891         self.mock_servers_update_addresses.return_value = None
  892         self.mock_server_suspend.return_value = None
  893 
  894         self.request.GET['marker'] = servers[-2].id
  895         params = "=".join([tables.InstancesTable._meta.pagination_param,
  896                            servers[page_size - 1].id])
  897         url = "?".join([reverse('horizon:project:instances:index'),
  898                         params])
  899         formData = {'action': 'instances__suspend__%s' % servers[-1].id}
  900 
  901         self.client.post(url, formData)
  902 
  903         self.mock_flavor_list.assert_called_once_with(helpers.IsHttpRequest())
  904         self._assert_mock_image_list_detailed_calls()
  905 
  906         self.mock_server_list_paged.assert_called_once_with(
  907             helpers.IsHttpRequest(),
  908             sort_dir='desc',
  909             search_opts={'marker': servers[page_size - 1].id,
  910                          'paginate': True})
  911         self.mock_servers_update_addresses.assert_called_once_with(
  912             helpers.IsHttpRequest(), servers[page_size:])
  913         self.mock_server_suspend.assert_called_once_with(
  914             helpers.IsHttpRequest(), servers[-1].id)
  915 
  916     @helpers.create_mocks({api.nova: ('server_suspend',
  917                                       'server_list_paged',
  918                                       'flavor_list',
  919                                       'is_feature_available',),
  920                            api.glance: ('image_list_detailed',),
  921                            api.network: ('servers_update_addresses',),
  922                            api.cinder: ('volume_list',)})
  923     def test_suspend_instance_exception(self):
  924         servers = self.servers.list()
  925         server = servers[0]
  926 
  927         self.mock_flavor_list.return_value = self.flavors.list()
  928         self.mock_image_list_detailed.return_value = (self.images.list(),
  929                                                       False, False)
  930         self.mock_server_list_paged.return_value = [servers, False, False]
  931         self.mock_servers_update_addresses.return_value = None
  932         self.mock_server_suspend.side_effect = self.exceptions.nova
  933 
  934         formData = {'action': 'instances__suspend__%s' % server.id}
  935         res = self.client.post(INDEX_URL, formData)
  936 
  937         self.assertRedirectsNoFollow(res, INDEX_URL)
  938 
  939         self.mock_flavor_list.assert_called_once_with(helpers.IsHttpRequest())
  940         self._assert_mock_image_list_detailed_calls()
  941 
  942         search_opts = {'marker': None, 'paginate': True}
  943         self.mock_server_list_paged.assert_called_once_with(
  944             helpers.IsHttpRequest(),
  945             sort_dir='desc',
  946             search_opts=search_opts)
  947         self.mock_servers_update_addresses.assert_called_once_with(
  948             helpers.IsHttpRequest(), servers)
  949         self.mock_server_suspend.assert_called_once_with(
  950             helpers.IsHttpRequest(), server.id)
  951 
  952     @helpers.create_mocks({api.nova: ('server_resume',
  953                                       'server_list_paged',
  954                                       'flavor_list',
  955                                       'is_feature_available',),
  956                            api.glance: ('image_list_detailed',),
  957                            api.network: ('servers_update_addresses',),
  958                            api.cinder: ('volume_list',)})
  959     def test_resume_instance(self):
  960         servers = self.servers.list()
  961         server = servers[0]
  962         server.status = "SUSPENDED"
  963 
  964         self.mock_flavor_list.return_value = self.flavors.list()
  965         self.mock_image_list_detailed.return_value = (self.images.list(),
  966                                                       False, False)
  967         self.mock_server_list_paged.return_value = [servers, False, False]
  968         self.mock_servers_update_addresses.return_value = None
  969         self.mock_server_resume.return_value = None
  970 
  971         formData = {'action': 'instances__suspend__%s' % server.id}
  972         res = self.client.post(INDEX_URL, formData)
  973 
  974         self.assertRedirectsNoFollow(res, INDEX_URL)
  975 
  976         self.mock_flavor_list.assert_called_once_with(helpers.IsHttpRequest())
  977         self._assert_mock_image_list_detailed_calls()
  978 
  979         search_opts = {'marker': None, 'paginate': True}
  980         self.mock_server_list_paged.assert_called_once_with(
  981             helpers.IsHttpRequest(),
  982             sort_dir='desc',
  983             search_opts=search_opts)
  984         self.mock_servers_update_addresses.assert_called_once_with(
  985             helpers.IsHttpRequest(), servers)
  986         self.mock_server_resume.assert_called_once_with(
  987             helpers.IsHttpRequest(), server.id)
  988 
  989     @helpers.create_mocks({api.nova: ('server_resume',
  990                                       'server_list_paged',
  991                                       'flavor_list',
  992                                       'is_feature_available'),
  993                            api.glance: ('image_list_detailed',),
  994                            api.network: ('servers_update_addresses',),
  995                            api.cinder: ('volume_list',)})
  996     def test_resume_instance_exception(self):
  997         servers = self.servers.list()
  998         server = servers[0]
  999         server.status = "SUSPENDED"
 1000 
 1001         self.mock_flavor_list.return_value = self.flavors.list()
 1002         self.mock_image_list_detailed.return_value = (self.images.list(),
 1003                                                       False, False)
 1004         self.mock_server_list_paged.return_value = [servers, False, False]
 1005         self.mock_servers_update_addresses.return_value = None
 1006         self.mock_server_resume.side_effect = self.exceptions.nova
 1007 
 1008         formData = {'action': 'instances__suspend__%s' % server.id}
 1009         res = self.client.post(INDEX_URL, formData)
 1010 
 1011         self.assertRedirectsNoFollow(res, INDEX_URL)
 1012 
 1013         self.mock_flavor_list.assert_called_once_with(helpers.IsHttpRequest())
 1014         self._assert_mock_image_list_detailed_calls()
 1015 
 1016         search_opts = {'marker': None, 'paginate': True}
 1017         self.mock_server_list_paged.assert_called_once_with(
 1018             helpers.IsHttpRequest(),
 1019             sort_dir='desc',
 1020             search_opts=search_opts)
 1021         self.mock_servers_update_addresses.assert_called_once_with(
 1022             helpers.IsHttpRequest(), servers)
 1023         self.mock_server_resume.assert_called_once_with(
 1024             helpers.IsHttpRequest(), server.id)
 1025 
 1026     @helpers.create_mocks({api.nova: ('server_shelve',
 1027                                       'server_list_paged',
 1028                                       'flavor_list',
 1029                                       'is_feature_available',),
 1030                            api.glance: ('image_list_detailed',),
 1031                            api.network: ('servers_update_addresses',),
 1032                            api.cinder: ('volume_list',)})
 1033     def test_shelve_instance(self):
 1034         servers = self.servers.list()
 1035         server = servers[0]
 1036 
 1037         self.mock_flavor_list.return_value = self.flavors.list()
 1038         self.mock_image_list_detailed.return_value = (self.images.list(),
 1039                                                       False, False)
 1040         self.mock_server_list_paged.return_value = [servers, False, False]
 1041         self.mock_servers_update_addresses.return_value = None
 1042         self.mock_server_shelve.return_value = None
 1043         formData = {'action': 'instances__shelve__%s' % server.id}
 1044         res = self.client.post(INDEX_URL, formData)
 1045 
 1046         self.assertRedirectsNoFollow(res, INDEX_URL)
 1047 
 1048         self.mock_flavor_list.assert_called_once_with(helpers.IsHttpRequest())
 1049         self._assert_mock_image_list_detailed_calls()
 1050 
 1051         search_opts = {'marker': None, 'paginate': True}
 1052         self.mock_server_list_paged.assert_called_once_with(
 1053             helpers.IsHttpRequest(),
 1054             sort_dir='desc',
 1055             search_opts=search_opts)
 1056         self.mock_servers_update_addresses.assert_called_once_with(
 1057             helpers.IsHttpRequest(), servers)
 1058         self.mock_server_shelve.assert_called_once_with(
 1059             helpers.IsHttpRequest(), server.id)
 1060 
 1061     @helpers.create_mocks({api.nova: ('server_shelve',
 1062                                       'server_list_paged',
 1063                                       'flavor_list',
 1064                                       'is_feature_available',),
 1065                            api.glance: ('image_list_detailed',),
 1066                            api.network: ('servers_update_addresses',),
 1067                            api.cinder: ('volume_list',)})
 1068     def test_shelve_instance_exception(self):
 1069         servers = self.servers.list()
 1070         server = servers[0]
 1071 
 1072         self.mock_flavor_list.return_value = self.flavors.list()
 1073         self.mock_image_list_detailed.return_value = (self.images.list(),
 1074                                                       False, False)
 1075         self.mock_server_list_paged.return_value = [servers, False, False]
 1076         self.mock_servers_update_addresses.return_value = None
 1077         self.mock_server_shelve.side_effect = self.exceptions.nova
 1078 
 1079         formData = {'action': 'instances__shelve__%s' % server.id}
 1080         res = self.client.post(INDEX_URL, formData)
 1081 
 1082         self.assertRedirectsNoFollow(res, INDEX_URL)
 1083 
 1084         self.mock_flavor_list.assert_called_once_with(helpers.IsHttpRequest())
 1085         self._assert_mock_image_list_detailed_calls()
 1086 
 1087         search_opts = {'marker': None, 'paginate': True}
 1088         self.mock_server_list_paged.assert_called_once_with(
 1089             helpers.IsHttpRequest(),
 1090             sort_dir='desc',
 1091             search_opts=search_opts)
 1092         self.mock_servers_update_addresses.assert_called_once_with(
 1093             helpers.IsHttpRequest(), servers)
 1094         self.mock_server_shelve.assert_called_once_with(
 1095             helpers.IsHttpRequest(), server.id)
 1096 
 1097     @helpers.create_mocks({api.nova: ('server_unshelve',
 1098                                       'server_list_paged',
 1099                                       'flavor_list',
 1100                                       'is_feature_available',),
 1101                            api.glance: ('image_list_detailed',),
 1102                            api.network: ('servers_update_addresses',),
 1103                            api.cinder: ('volume_list',)})
 1104     def test_unshelve_instance(self):
 1105         servers = self.servers.list()
 1106         server = servers[0]
 1107         server.status = "SHELVED_OFFLOADED"
 1108 
 1109         self.mock_flavor_list.return_value = self.flavors.list()
 1110         self.mock_image_list_detailed.return_value = (self.images.list(),
 1111                                                       False, False)
 1112         self.mock_server_list_paged.return_value = [servers, False, False]
 1113         self.mock_servers_update_addresses.return_value = None
 1114         self.mock_server_unshelve.return_value = None
 1115 
 1116         formData = {'action': 'instances__shelve__%s' % server.id}
 1117         res = self.client.post(INDEX_URL, formData)
 1118 
 1119         self.assertRedirectsNoFollow(res, INDEX_URL)
 1120 
 1121         self.mock_flavor_list.assert_called_once_with(helpers.IsHttpRequest())
 1122         self._assert_mock_image_list_detailed_calls()
 1123 
 1124         search_opts = {'marker': None, 'paginate': True}
 1125         self.mock_server_list_paged.assert_called_once_with(
 1126             helpers.IsHttpRequest(),
 1127             sort_dir='desc',
 1128             search_opts=search_opts)
 1129         self.mock_servers_update_addresses.assert_called_once_with(
 1130             helpers.IsHttpRequest(), servers)
 1131         self.mock_server_unshelve.assert_called_once_with(
 1132             helpers.IsHttpRequest(), server.id)
 1133 
 1134     @helpers.create_mocks({api.nova: ('server_unshelve',
 1135                                       'server_list_paged',
 1136                                       'flavor_list',
 1137                                       'is_feature_available',),
 1138                            api.glance: ('image_list_detailed',),
 1139                            api.network: ('servers_update_addresses',),
 1140                            api.cinder: ('volume_list',)})
 1141     def test_unshelve_instance_exception(self):
 1142         servers = self.servers.list()
 1143         server = servers[0]
 1144         server.status = "SHELVED_OFFLOADED"
 1145 
 1146         self.mock_flavor_list.return_value = self.flavors.list()
 1147         self.mock_image_list_detailed.return_value = (self.images.list(),
 1148                                                       False, False)
 1149         self.mock_server_list_paged.return_value = [servers, False, False]
 1150         self.mock_servers_update_addresses.return_value = None
 1151         self.mock_server_unshelve.side_effect = self.exceptions.nova
 1152 
 1153         formData = {'action': 'instances__shelve__%s' % server.id}
 1154         res = self.client.post(INDEX_URL, formData)
 1155 
 1156         self.assertRedirectsNoFollow(res, INDEX_URL)
 1157 
 1158         self.mock_flavor_list.assert_called_once_with(helpers.IsHttpRequest())
 1159         self._assert_mock_image_list_detailed_calls()
 1160 
 1161         search_opts = {'marker': None, 'paginate': True}
 1162         self.mock_server_list_paged.assert_called_once_with(
 1163             helpers.IsHttpRequest(),
 1164             sort_dir='desc',
 1165             search_opts=search_opts)
 1166         self.mock_servers_update_addresses.assert_called_once_with(
 1167             helpers.IsHttpRequest(), servers)
 1168         self.mock_server_unshelve.assert_called_once_with(
 1169             helpers.IsHttpRequest(), server.id)
 1170 
 1171     @helpers.create_mocks({api.nova: ('server_lock',
 1172                                       'server_list_paged',
 1173                                       'flavor_list',
 1174                                       'is_feature_available',),
 1175                            api.glance: ('image_list_detailed',),
 1176                            api.network: ('servers_update_addresses',),
 1177                            api.cinder: ('volume_list',)})
 1178     def test_lock_instance(self):
 1179         servers = self.servers.list()
 1180         server = servers[0]
 1181 
 1182         self.mock_is_feature_available.return_value = True
 1183         self.mock_flavor_list.return_value = self.flavors.list()
 1184         self.mock_image_list_detailed.return_value = (self.images.list(),
 1185                                                       False, False)
 1186         self.mock_server_list_paged.return_value = [servers, False, False]
 1187         self.mock_servers_update_addresses.return_value = None
 1188         self.mock_server_lock.return_value = None
 1189         formData = {'action': 'instances__lock__%s' % server.id}
 1190         res = self.client.post(INDEX_URL, formData)
 1191 
 1192         self.assertRedirectsNoFollow(res, INDEX_URL)
 1193 
 1194         self.mock_is_feature_available.assert_called_once_with(
 1195             helpers.IsHttpRequest(), 'locked_attribute')
 1196         self.mock_flavor_list.assert_called_once_with(helpers.IsHttpRequest())
 1197         self._assert_mock_image_list_detailed_calls()
 1198 
 1199         search_opts = {'marker': None, 'paginate': True}
 1200         self.mock_server_list_paged.assert_called_once_with(
 1201             helpers.IsHttpRequest(),
 1202             sort_dir='desc',
 1203             search_opts=search_opts)
 1204         self.mock_servers_update_addresses.assert_called_once_with(
 1205             helpers.IsHttpRequest(), servers)
 1206         self.mock_server_lock.assert_called_once_with(
 1207             helpers.IsHttpRequest(), server.id)
 1208 
 1209     @helpers.create_mocks({api.nova: ('server_lock',
 1210                                       'server_list_paged',
 1211                                       'flavor_list',
 1212                                       'is_feature_available',),
 1213                            api.glance: ('image_list_detailed',),
 1214                            api.network: ('servers_update_addresses',),
 1215                            api.cinder: ('volume_list',)})
 1216     def test_lock_instance_exception(self):
 1217         servers = self.servers.list()
 1218         server = servers[0]
 1219 
 1220         self.mock_is_feature_available.return_value = True
 1221         self.mock_flavor_list.return_value = self.flavors.list()
 1222         self.mock_image_list_detailed.return_value = (self.images.list(),
 1223                                                       False, False)
 1224         self.mock_server_list_paged.return_value = [servers, False, False]
 1225         self.mock_servers_update_addresses.return_value = None
 1226         self.mock_server_lock.side_effect = self.exceptions.nova
 1227 
 1228         formData = {'action': 'instances__lock__%s' % server.id}
 1229         res = self.client.post(INDEX_URL, formData)
 1230 
 1231         self.assertRedirectsNoFollow(res, INDEX_URL)
 1232 
 1233         self.mock_is_feature_available.assert_called_once_with(
 1234             helpers.IsHttpRequest(), 'locked_attribute')
 1235         self.mock_flavor_list.assert_called_once_with(
 1236             helpers.IsHttpRequest())
 1237         self._assert_mock_image_list_detailed_calls()
 1238 
 1239         search_opts = {'marker': None, 'paginate': True}
 1240         self.mock_server_list_paged.assert_called_once_with(
 1241             helpers.IsHttpRequest(),
 1242             sort_dir='desc',
 1243             search_opts=search_opts)
 1244         self.mock_servers_update_addresses.assert_called_once_with(
 1245             helpers.IsHttpRequest(), servers)
 1246         self.mock_server_lock.assert_called_once_with(
 1247             helpers.IsHttpRequest(), server.id)
 1248 
 1249     @helpers.create_mocks({api.nova: ('server_unlock',
 1250                                       'server_list_paged',
 1251                                       'flavor_list',
 1252                                       'is_feature_available'),
 1253                            api.glance: ('image_list_detailed',),
 1254                            api.network: ('servers_update_addresses',),
 1255                            api.cinder: ('volume_list',)})
 1256     def test_unlock_instance(self):
 1257         servers = self.servers.list()
 1258         server = servers[0]
 1259         self.mock_is_feature_available.return_value = True
 1260         self.mock_flavor_list.return_value = self.flavors.list()
 1261         self.mock_image_list_detailed.return_value = (self.images.list(),
 1262                                                       False, False)
 1263         self.mock_server_list_paged.return_value = [servers, False, False]
 1264         self.mock_servers_update_addresses.return_value = None
 1265         self.mock_server_unlock.return_value = None
 1266         formData = {'action': 'instances__unlock__%s' % server.id}
 1267         res = self.client.post(INDEX_URL, formData)
 1268 
 1269         self.assertRedirectsNoFollow(res, INDEX_URL)
 1270 
 1271         self.mock_is_feature_available.assert_called_once_with(
 1272             helpers.IsHttpRequest(), 'locked_attribute')
 1273         self.mock_flavor_list.assert_called_once_with(
 1274             helpers.IsHttpRequest())
 1275         self._assert_mock_image_list_detailed_calls()
 1276 
 1277         search_opts = {'marker': None, 'paginate': True}
 1278         self.mock_server_list_paged.assert_called_once_with(
 1279             helpers.IsHttpRequest(),
 1280             sort_dir='desc',
 1281             search_opts=search_opts)
 1282         self.mock_servers_update_addresses.assert_called_once_with(
 1283             helpers.IsHttpRequest(), servers)
 1284         self.mock_server_unlock.assert_called_once_with(
 1285             helpers.IsHttpRequest(), server.id)
 1286 
 1287     @helpers.create_mocks({api.nova: ('server_unlock',
 1288                                       'server_list_paged',
 1289                                       'flavor_list',
 1290                                       'is_feature_available'),
 1291                            api.glance: ('image_list_detailed',),
 1292                            api.network: ('servers_update_addresses',),
 1293                            api.cinder: ('volume_list',)})
 1294     def test_unlock_instance_exception(self):
 1295         servers = self.servers.list()
 1296         server = servers[0]
 1297         self.mock_is_feature_available.return_value = True
 1298         self.mock_flavor_list.return_value = self.flavors.list()
 1299         self.mock_image_list_detailed.return_value = (self.images.list(),
 1300                                                       False, False)
 1301         self.mock_server_list_paged.return_value = [servers, False, False]
 1302         self.mock_servers_update_addresses.return_value = None
 1303         self.mock_server_unlock.side_effect = self.exceptions.nova
 1304 
 1305         formData = {'action': 'instances__unlock__%s' % server.id}
 1306         res = self.client.post(INDEX_URL, formData)
 1307 
 1308         self.assertRedirectsNoFollow(res, INDEX_URL)
 1309 
 1310         self.mock_is_feature_available.assert_called_once_with(
 1311             helpers.IsHttpRequest(), 'locked_attribute')
 1312         self.mock_flavor_list.assert_called_once_with(helpers.IsHttpRequest())
 1313         self._assert_mock_image_list_detailed_calls()
 1314 
 1315         search_opts = {'marker': None, 'paginate': True}
 1316         self.mock_server_list_paged.assert_called_once_with(
 1317             helpers.IsHttpRequest(),
 1318             sort_dir='desc',
 1319             search_opts=search_opts)
 1320         self.mock_servers_update_addresses.assert_called_once_with(
 1321             helpers.IsHttpRequest(), servers)
 1322         self.mock_server_unlock.assert_called_once_with(
 1323             helpers.IsHttpRequest(), server.id)
 1324 
 1325 
 1326 class InstanceDetailTests(InstanceTestBase):
 1327 
 1328     @helpers.create_mocks({
 1329         api.nova: (
 1330             "server_get",
 1331             "instance_volumes_list",
 1332             "flavor_get",
 1333             'is_feature_available',
 1334         ),
 1335         api.neutron: (
 1336             "server_security_groups",
 1337             "floating_ip_simple_associate_supported",
 1338             "floating_ip_supported"
 1339         ),
 1340         api.network: ('servers_update_addresses',),
 1341     })
 1342     def _get_instance_details(self, server, qs=None,
 1343                               flavor_return=None, volumes_return=None,
 1344                               security_groups_return=None,
 1345                               flavor_exception=False):
 1346 
 1347         url = reverse('horizon:project:instances:detail', args=[server.id])
 1348         if qs:
 1349             url += qs
 1350 
 1351         if flavor_return is None:
 1352             flavor_return = self.flavors.first()
 1353 
 1354         if volumes_return is None:
 1355             volumes_return = []
 1356 
 1357         if security_groups_return is None:
 1358             security_groups_return = self.security_groups.list()
 1359 
 1360         self.mock_server_get.return_value = server
 1361         self.mock_servers_update_addresses.return_value = None
 1362         self.mock_instance_volumes_list.return_value = volumes_return
 1363         if flavor_exception:
 1364             self.mock_flavor_get.side_effect = self.exceptions.nova
 1365         else:
 1366             self.mock_flavor_get.return_value = flavor_return
 1367         self.mock_server_security_groups.return_value = security_groups_return
 1368         self.mock_floating_ip_simple_associate_supported.return_value = True
 1369         self.mock_floating_ip_supported.return_value = True
 1370         self.mock_is_feature_available.return_value = True
 1371 
 1372         res = self.client.get(url)
 1373 
 1374         self.mock_server_get.assert_called_once_with(
 1375             helpers.IsHttpRequest(), server.id)
 1376         self.mock_servers_update_addresses.assert_called_once_with(
 1377             helpers.IsHttpRequest(), mock.ANY)
 1378         self.mock_instance_volumes_list.assert_called_once_with(
 1379             helpers.IsHttpRequest(), server.id)
 1380         self.mock_flavor_get.assert_called_once_with(
 1381             helpers.IsHttpRequest(), server.flavor['id'])
 1382         self.mock_server_security_groups.assert_called_once_with(
 1383             helpers.IsHttpRequest(), server.id)
 1384         self.mock_floating_ip_simple_associate_supported \
 1385             .assert_called_once_with(helpers.IsHttpRequest())
 1386         self.assert_mock_multiple_calls_with_same_arguments(
 1387             self.mock_floating_ip_supported, 2,
 1388             mock.call(helpers.IsHttpRequest()))
 1389         self.assert_mock_multiple_calls_with_same_arguments(
 1390             self.mock_is_feature_available, 2,
 1391             mock.call(helpers.IsHttpRequest(), 'locked_attribute'))
 1392 
 1393         return res
 1394 
 1395     @helpers.create_mocks({api.neutron: ['is_extension_supported']})
 1396     def test_instance_details_volumes(self):
 1397         server = self.servers.first()
 1398         volumes = [self.nova_volumes.list()[1]]
 1399         security_groups = self.security_groups.list()
 1400 
 1401         self.mock_is_extension_supported.return_value = False
 1402 
 1403         res = self._get_instance_details(
 1404             server, volumes_return=volumes,
 1405             security_groups_return=security_groups)
 1406 
 1407         self.assertCountEqual(res.context['instance'].volumes, volumes)
 1408         self.mock_is_extension_supported.assert_called_once_with(
 1409             helpers.IsHttpRequest(), 'mac-learning')
 1410 
 1411     @helpers.create_mocks({api.neutron: ['is_extension_supported']})
 1412     def test_instance_details_volume_sorting(self):
 1413         server = self.servers.first()
 1414         volumes = self.nova_volumes.list()[1:3]
 1415         security_groups = self.security_groups.list()
 1416 
 1417         self.mock_is_extension_supported.return_value = False
 1418 
 1419         res = self._get_instance_details(
 1420             server, volumes_return=volumes,
 1421             security_groups_return=security_groups)
 1422 
 1423         self.assertCountEqual(res.context['instance'].volumes, volumes)
 1424         self.assertEqual(res.context['instance'].volumes[0].device,
 1425                          "/dev/hda")
 1426         self.assertEqual(res.context['instance'].volumes[1].device,
 1427                          "/dev/hdk")
 1428         self.mock_is_extension_supported.assert_called_once_with(
 1429             helpers.IsHttpRequest(), 'mac-learning')
 1430 
 1431     @helpers.create_mocks({api.neutron: ['is_extension_supported']})
 1432     def test_instance_details_metadata(self):
 1433         server = self.servers.first()
 1434 
 1435         self.mock_is_extension_supported.return_value = False
 1436 
 1437         tg = tabs.InstanceDetailTabs(self.request, instance=server)
 1438         qs = "?%s=%s" % (tg.param_name, tg.get_tab("overview").get_id())
 1439         res = self._get_instance_details(server, qs)
 1440 
 1441         self.assertContains(res, '<dd class="word-wrap">keyName</dd>', 1)
 1442         self.assertContains(res, "<dt>someMetaLabel</dt>", 1)
 1443         self.assertContains(res, "<dd>someMetaData</dd>", 1)
 1444         self.assertContains(res, "<dt>some&lt;b&gt;html&lt;/b&gt;label</dt>",
 1445                             1)
 1446         self.assertContains(res, "<dd>&lt;!--</dd>", 1)
 1447         self.assertContains(res, "<dt>empty</dt>", 1)
 1448         self.assertContains(res, "<dd><em>N/A</em></dd>", 1)
 1449 
 1450         self.assert_mock_multiple_calls_with_same_arguments(
 1451             self.mock_is_extension_supported, 2,
 1452             mock.call(helpers.IsHttpRequest(), 'mac-learning'))
 1453 
 1454     @helpers.create_mocks({api.neutron: ['is_extension_supported']})
 1455     def test_instance_details_fault(self):
 1456         server = self.servers.first()
 1457 
 1458         self.mock_is_extension_supported.return_value = False
 1459 
 1460         server.status = 'ERROR'
 1461         server.fault = {"message": "NoValidHost",
 1462                         "code": 500,
 1463                         "details": "No valid host was found. \n  "
 1464                                    "File \"/mnt/stack/nova/nova/"
 1465                                    "scheduler/filter_scheduler.py\", "
 1466                                    "line 105, in schedule_run_instance\n    "
 1467                                    "raise exception.NoValidHost"
 1468                                    "(reason=\"\")\n",
 1469                         "created": "2013-10-07T00:08:32Z"}
 1470 
 1471         res = self._get_instance_details(server)
 1472         self.assertCountEqual(res.context['instance'].fault, server.fault)
 1473         self.mock_is_extension_supported.assert_called_once_with(
 1474             helpers.IsHttpRequest(), 'mac-learning')
 1475 
 1476     @helpers.create_mocks({console: ['get_console'],
 1477                            api.neutron: ['is_extension_supported']})
 1478     def test_instance_details_console_tab(self):
 1479         server = self.servers.first()
 1480         CONSOLE_OUTPUT = '/vncserver'
 1481         CONSOLE_TITLE = '&title=%s(%s)' % (server.name, server.id)
 1482         CONSOLE_URL = CONSOLE_OUTPUT + CONSOLE_TITLE
 1483 
 1484         self.mock_get_console.return_value = ('VNC', CONSOLE_URL)
 1485         self.mock_is_extension_supported.return_value = False
 1486 
 1487         tg = tabs.InstanceDetailTabs(self.request, instance=server)
 1488         qs = "?%s=%s" % (tg.param_name, tg.get_tab("console").get_id())
 1489         res = self._get_instance_details(server, qs)
 1490         self.assertIn(tabs.ConsoleTab, res.context_data['tab_group'].tabs)
 1491         self.assertTemplateUsed(res,
 1492                                 'project/instances/_detail_console.html')
 1493         console_tab_rendered = False
 1494         for tab in res.context_data['tab_group'].get_loaded_tabs():
 1495             if isinstance(tab, tabs.ConsoleTab):
 1496                 console_tab_rendered = True
 1497                 break
 1498         self.assertTrue(console_tab_rendered)
 1499         self.mock_get_console.assert_called_once_with(
 1500             mock.ANY, 'AUTO', server)
 1501         self.assert_mock_multiple_calls_with_same_arguments(
 1502             self.mock_is_extension_supported, 2,
 1503             mock.call(helpers.IsHttpRequest(), 'mac-learning'))
 1504 
 1505     @django.test.utils.override_settings(CONSOLE_TYPE=None)
 1506     @helpers.create_mocks({api.neutron: ['is_extension_supported']})
 1507     def test_instance_details_console_tab_deactivated(self):
 1508         server = self.servers.first()
 1509 
 1510         self.mock_is_extension_supported.return_value = False
 1511 
 1512         tg = tabs.InstanceDetailTabs(self.request, instance=server)
 1513         self.assertIsNone(tg.get_tab("console"))
 1514         res = self._get_instance_details(server)
 1515         self.assertTemplateNotUsed(res,
 1516                                    'project/instances/_detail_console.html')
 1517         for tab in res.context_data['tab_group'].get_loaded_tabs():
 1518             self.assertNotIsInstance(tab, tabs.ConsoleTab)
 1519 
 1520         self.assert_mock_multiple_calls_with_same_arguments(
 1521             self.mock_is_extension_supported, 2,
 1522             mock.call(helpers.IsHttpRequest(), 'mac-learning'))
 1523 
 1524     @helpers.create_mocks({api.nova: ('server_get',)})
 1525     def test_instance_details_exception(self):
 1526         server = self.servers.first()
 1527 
 1528         self.mock_server_get.side_effect = self.exceptions.nova
 1529 
 1530         url = reverse('horizon:project:instances:detail',
 1531                       args=[server.id])
 1532         res = self.client.get(url)
 1533 
 1534         self.assertRedirectsNoFollow(res, INDEX_URL)
 1535         self.mock_server_get.assert_called_once_with(helpers.IsHttpRequest(),
 1536                                                      server.id)
 1537 
 1538     @helpers.create_mocks({api.nova: ("server_get",)})
 1539     def test_instance_details_unauthorized(self):
 1540         server = self.servers.first()
 1541 
 1542         url = reverse('horizon:admin:instances:detail',
 1543                       args=[server.id])
 1544 
 1545         # Avoid the log message in the test
 1546         # when unauthorized exception will be logged
 1547         logging.disable(logging.ERROR)
 1548         res = self.client.get(url)
 1549         logging.disable(logging.NOTSET)
 1550 
 1551         self.assertEqual(403, res.status_code)
 1552         self.assertEqual(0, self.mock_server_get.call_count)
 1553 
 1554     @helpers.create_mocks({api.neutron: ['is_extension_supported']})
 1555     def test_instance_details_flavor_not_found(self):
 1556         server = self.servers.first()
 1557         self.mock_is_extension_supported.return_value = False
 1558         res = self._get_instance_details(server, flavor_exception=True)
 1559         self.assertTemplateUsed(res,
 1560                                 'project/instances/_detail_overview.html')
 1561         self.assertContains(res, "Not available")
 1562         self.mock_is_extension_supported.assert_called_once_with(
 1563             helpers.IsHttpRequest(), 'mac-learning')
 1564 
 1565     @helpers.create_mocks({api.nova: ['server_console_output'],
 1566                            api.neutron: ['is_extension_supported']})
 1567     def test_instance_log(self):
 1568         server = self.servers.first()
 1569         CONSOLE_OUTPUT = 'output'
 1570 
 1571         self.mock_server_console_output.return_value = CONSOLE_OUTPUT
 1572         self.mock_is_extension_supported.return_value = False
 1573 
 1574         url = reverse('horizon:project:instances:console',
 1575                       args=[server.id])
 1576         tg = tabs.InstanceDetailTabs(self.request, instance=server)
 1577         qs = "?%s=%s" % (tg.param_name, tg.get_tab("log").get_id())
 1578         res = self.client.get(url + qs)
 1579 
 1580         self.assertNoMessages()
 1581         self.assertIsInstance(res, http.HttpResponse)
 1582         self.assertContains(res, CONSOLE_OUTPUT)
 1583         self.mock_server_console_output.assert_called_once_with(
 1584             helpers.IsHttpRequest(), server.id, tail_length=None)
 1585         self.mock_is_extension_supported.assert_called_once_with(
 1586             helpers.IsHttpRequest(), 'mac-learning')
 1587 
 1588     @helpers.create_mocks({api.nova: ['server_console_output'],
 1589                            api.neutron: ['is_extension_supported']})
 1590     def test_instance_log_exception(self):
 1591         server = self.servers.first()
 1592 
 1593         self.mock_server_console_output.side_effect = self.exceptions.nova
 1594         self.mock_is_extension_supported.return_value = False
 1595 
 1596         url = reverse('horizon:project:instances:console',
 1597                       args=[server.id])
 1598         tg = tabs.InstanceDetailTabs(self.request, instance=server)
 1599         qs = "?%s=%s" % (tg.param_name, tg.get_tab("log").get_id())
 1600         res = self.client.get(url + qs)
 1601 
 1602         self.assertContains(res, "Unable to get log for")
 1603         self.mock_server_console_output.assert_called_once_with(
 1604             helpers.IsHttpRequest(), server.id, tail_length=None)
 1605         self.mock_is_extension_supported.assert_called_once_with(
 1606             helpers.IsHttpRequest(), 'mac-learning')
 1607 
 1608     @helpers.create_mocks({api.neutron: ['is_extension_supported']})
 1609     def test_instance_log_invalid_input(self):
 1610         server = self.servers.first()
 1611         self.mock_is_extension_supported.return_value = False
 1612 
 1613         url = reverse('horizon:project:instances:console',
 1614                       args=[server.id])
 1615         tg = tabs.InstanceDetailTabs(self.request, instance=server)
 1616         for length in ["-5", "x"]:
 1617             qs = "?%s=%s&length=%s" % (tg.param_name,
 1618                                        tg.get_tab("log").get_id(),
 1619                                        length)
 1620             res = self.client.get(url + qs)
 1621 
 1622             self.assertContains(res, "Unable to get log for")
 1623 
 1624         self.mock_is_extension_supported.assert_called_once_with(
 1625             helpers.IsHttpRequest(), 'mac-learning')
 1626 
 1627     @helpers.create_mocks({api.nova: ['server_get'],
 1628                            console: ['get_console']})
 1629     def test_instance_auto_console(self):
 1630         server = self.servers.first()
 1631         CONSOLE_OUTPUT = '/vncserver'
 1632         CONSOLE_TITLE = '&title=%s(%s)' % (server.name, server.id)
 1633         CONSOLE_URL = CONSOLE_OUTPUT + CONSOLE_TITLE
 1634 
 1635         self.mock_server_get.return_value = server
 1636         self.mock_get_console.return_value = ('VNC', CONSOLE_URL)
 1637 
 1638         url = reverse('horizon:project:instances:auto_console',
 1639                       args=[server.id])
 1640         res = self.client.get(url)
 1641         redirect = CONSOLE_URL
 1642         self.assertRedirectsNoFollow(res, redirect)
 1643 
 1644         self.mock_server_get.assert_called_once_with(
 1645             helpers.IsHttpRequest(), server.id)
 1646         self.mock_get_console.assert_called_once_with(
 1647             mock.ANY, 'AUTO', server)
 1648 
 1649     @helpers.create_mocks({api.nova: ['server_get'],
 1650                            console: ['get_console']})
 1651     def test_instance_vnc_error(self):
 1652         server = self.servers.first()
 1653         self.mock_server_get.return_value = server
 1654         self.mock_get_console.side_effect = exceptions.NotAvailable('console')
 1655 
 1656         url = reverse('horizon:project:instances:vnc',
 1657                       args=[server.id])
 1658         res = self.client.get(url)
 1659 
 1660         self.assertRedirectsNoFollow(res, INDEX_URL)
 1661 
 1662         self.mock_server_get.assert_called_once_with(
 1663             helpers.IsHttpRequest(), server.id)
 1664         self.mock_get_console.assert_called_once_with(
 1665             mock.ANY, 'VNC', server)
 1666 
 1667     @helpers.create_mocks({api.nova: ['server_get'],
 1668                            console: ['get_console']})
 1669     def test_instance_spice(self):
 1670         server = self.servers.first()
 1671         CONSOLE_OUTPUT = '/spiceserver'
 1672         CONSOLE_TITLE = '&title=%s(%s)' % (server.name, server.id)
 1673         CONSOLE_URL = CONSOLE_OUTPUT + CONSOLE_TITLE
 1674 
 1675         self.mock_server_get.return_value = server
 1676         self.mock_get_console.return_value = ('SPICE', CONSOLE_URL)
 1677 
 1678         url = reverse('horizon:project:instances:spice',
 1679                       args=[server.id])
 1680         res = self.client.get(url)
 1681         redirect = CONSOLE_URL
 1682         self.assertRedirectsNoFollow(res, redirect)
 1683 
 1684         self.mock_server_get.assert_called_once_with(
 1685             helpers.IsHttpRequest(), server.id)
 1686         self.mock_get_console.assert_called_once_with(
 1687             mock.ANY, 'SPICE', server)
 1688 
 1689     @helpers.create_mocks({api.nova: ['server_get'],
 1690                            console: ['get_console']})
 1691     def test_instance_spice_exception(self):
 1692         server = self.servers.first()
 1693         self.mock_server_get.return_value = server
 1694         self.mock_get_console.side_effect = exceptions.NotAvailable('console')
 1695 
 1696         url = reverse('horizon:project:instances:spice',
 1697                       args=[server.id])
 1698         res = self.client.get(url)
 1699 
 1700         self.assertRedirectsNoFollow(res, INDEX_URL)
 1701 
 1702         self.mock_server_get.assert_called_once_with(
 1703             helpers.IsHttpRequest(), server.id)
 1704         self.mock_get_console.assert_called_once_with(
 1705             mock.ANY, 'SPICE', server)
 1706 
 1707     @helpers.create_mocks({api.nova: ['server_get'],
 1708                            console: ['get_console']})
 1709     def test_instance_rdp(self):
 1710         server = self.servers.first()
 1711         CONSOLE_OUTPUT = '/rdpserver'
 1712         CONSOLE_TITLE = '&title=%s(%s)' % (server.name, server.id)
 1713         CONSOLE_URL = CONSOLE_OUTPUT + CONSOLE_TITLE
 1714 
 1715         self.mock_server_get.return_value = server
 1716         self.mock_get_console.return_value = ('RDP', CONSOLE_URL)
 1717 
 1718         url = reverse('horizon:project:instances:rdp',
 1719                       args=[server.id])
 1720         res = self.client.get(url)
 1721         redirect = CONSOLE_URL
 1722         self.assertRedirectsNoFollow(res, redirect)
 1723 
 1724         self.mock_server_get.assert_called_once_with(
 1725             helpers.IsHttpRequest(), server.id)
 1726         self.mock_get_console.assert_called_once_with(
 1727             mock.ANY, 'RDP', server)
 1728 
 1729     @helpers.create_mocks({api.nova: ['server_get'],
 1730                            console: ['get_console']})
 1731     def test_instance_rdp_exception(self):
 1732         server = self.servers.first()
 1733 
 1734         self.mock_server_get.return_value = server
 1735         self.mock_get_console.side_effect = exceptions.NotAvailable('console')
 1736 
 1737         url = reverse('horizon:project:instances:rdp',
 1738                       args=[server.id])
 1739         res = self.client.get(url)
 1740 
 1741         self.assertRedirectsNoFollow(res, INDEX_URL)
 1742 
 1743         self.mock_server_get.assert_called_once_with(
 1744             helpers.IsHttpRequest(), server.id)
 1745         self.mock_get_console.assert_called_once_with(
 1746             mock.ANY, 'RDP', server)
 1747 
 1748 
 1749 class InstanceTests(InstanceTestBase):
 1750 
 1751     @helpers.create_mocks({api.nova: ('server_get',
 1752                                       'snapshot_create'),
 1753                            api.glance: ('image_list_detailed',)})
 1754     def test_create_instance_snapshot(self):
 1755         server = self.servers.first()
 1756 
 1757         self.mock_server_get.return_value = server
 1758         self.mock_snapshot_create.return_value = self.snapshots.first()
 1759         self.mock_image_list_detailed.return_value = \
 1760             (self.images.list(), False, False)
 1761 
 1762         formData = {'instance_id': server.id,
 1763                     'method': 'CreateSnapshot',
 1764                     'name': 'snapshot1'}
 1765         url = reverse('horizon:project:images:snapshots:create',
 1766                       args=[server.id])
 1767         redir_url = reverse('horizon:project:images:index')
 1768         res = self.client.post(url, formData)
 1769         self.assertRedirects(res, redir_url)
 1770 
 1771         self.mock_server_get.assert_called_once_with(
 1772             helpers.IsHttpRequest(), server.id)
 1773         self.mock_snapshot_create.assert_called_once_with(
 1774             helpers.IsHttpRequest(), server.id, "snapshot1")
 1775         self.mock_image_list_detailed.assert_called_once_with(
 1776             helpers.IsHttpRequest(), marker=None, paginate=True,
 1777             reversed_order=False, sort_dir='asc', sort_key='name')
 1778 
 1779     @django.test.utils.override_settings(
 1780         OPENSTACK_ENABLE_PASSWORD_RETRIEVE=False)
 1781     def test_instances_index_retrieve_password_action_disabled(self):
 1782         self. _test_instances_index_retrieve_password_action()
 1783 
 1784     @django.test.utils.override_settings(
 1785         OPENSTACK_ENABLE_PASSWORD_RETRIEVE=True)
 1786     def test_instances_index_retrieve_password_action_enabled(self):
 1787         self._test_instances_index_retrieve_password_action()
 1788 
 1789     @helpers.create_mocks({
 1790         api.nova: ('flavor_list',
 1791                    'server_list_paged',
 1792                    'tenant_absolute_limits',
 1793                    'is_feature_available',),
 1794         api.glance: ('image_list_detailed',),
 1795         api.neutron: ('floating_ip_simple_associate_supported',
 1796                       'floating_ip_supported',),
 1797         api.network: ('servers_update_addresses',),
 1798         api.cinder: ('volume_list',),
 1799     })
 1800     def _test_instances_index_retrieve_password_action(self):
 1801         servers = self.servers.list()
 1802 
 1803         self.mock_is_feature_available.return_value = True
 1804         self.mock_flavor_list.return_value = self.flavors.list()
 1805         self.mock_image_list_detailed.return_value = (self.images.list(),
 1806                                                       False, False)
 1807         self.mock_server_list_paged.return_value = [servers, False, False]
 1808         self.mock_servers_update_addresses.return_value = None
 1809         self.mock_tenant_absolute_limits.return_value = self.limits['absolute']
 1810         self.mock_floating_ip_supported.return_value = True
 1811         self.mock_floating_ip_simple_associate_supported.return_value = True
 1812 
 1813         url = reverse('horizon:project:instances:index')
 1814         res = self.client.get(url)
 1815         for server in servers:
 1816             _action_id = ''.join(["instances__row_",
 1817                                   server.id,
 1818                                   "__action_decryptpassword"])
 1819             if settings.OPENSTACK_ENABLE_PASSWORD_RETRIEVE and \
 1820                     server.status == "ACTIVE" and \
 1821                     server.key_name is not None:
 1822                 self.assertContains(res, _action_id)
 1823             else:
 1824                 self.assertNotContains(res, _action_id)
 1825 
 1826         self.assert_mock_multiple_calls_with_same_arguments(
 1827             self.mock_is_feature_available, 10,
 1828             mock.call(helpers.IsHttpRequest(), 'locked_attribute'))
 1829         self.mock_flavor_list.assert_called_once_with(helpers.IsHttpRequest())
 1830         self._assert_mock_image_list_detailed_calls()
 1831 
 1832         search_opts = {'marker': None, 'paginate': True}
 1833         self.mock_server_list_paged.assert_called_once_with(
 1834             helpers.IsHttpRequest(),
 1835             sort_dir='desc',
 1836             search_opts=search_opts)
 1837         self.mock_servers_update_addresses.assert_called_once_with(
 1838             helpers.IsHttpRequest(), servers)
 1839         self.assert_mock_multiple_calls_with_same_arguments(
 1840             self.mock_tenant_absolute_limits, 2,
 1841             mock.call(helpers.IsHttpRequest(), reserved=True))
 1842         self.assert_mock_multiple_calls_with_same_arguments(
 1843             self.mock_floating_ip_supported, 10,
 1844             mock.call(helpers.IsHttpRequest()))
 1845         self.assert_mock_multiple_calls_with_same_arguments(
 1846             self.mock_floating_ip_simple_associate_supported, 5,
 1847             mock.call(helpers.IsHttpRequest()))
 1848 
 1849     @helpers.create_mocks({api.nova: ('get_password',)})
 1850     def test_decrypt_instance_password(self):
 1851         server = self.servers.first()
 1852         enc_password = "azerty"
 1853         self.mock_get_password.return_value = enc_password
 1854         url = reverse('horizon:project:instances:decryptpassword',
 1855                       args=[server.id,
 1856                             server.key_name])
 1857         res = self.client.get(url)
 1858         self.assertTemplateUsed(res, 'project/instances/decryptpassword.html')
 1859         self.mock_get_password.assert_called_once_with(
 1860             helpers.IsHttpRequest(), server.id)
 1861 
 1862     @helpers.create_mocks({api.nova: ('get_password',)})
 1863     def test_decrypt_instance_get_exception(self):
 1864         server = self.servers.first()
 1865         keypair = self.keypairs.first()
 1866         self.mock_get_password.side_effect = self.exceptions.nova
 1867         url = reverse('horizon:project:instances:decryptpassword',
 1868                       args=[server.id,
 1869                             keypair])
 1870         res = self.client.get(url)
 1871         self.assertRedirectsNoFollow(res, INDEX_URL)
 1872         self.mock_get_password.assert_called_once_with(
 1873             helpers.IsHttpRequest(), server.id)
 1874 
 1875     instance_update_get_stubs = {
 1876         api.nova: ('server_get', 'is_feature_available'),
 1877         api.neutron: ('security_group_list',
 1878                       'server_security_groups',)}
 1879 
 1880     @helpers.create_mocks(instance_update_get_stubs)
 1881     def test_instance_update_get(self):
 1882         server = self.servers.first()
 1883 
 1884         self.mock_server_get.return_value = server
 1885         self.mock_security_group_list.return_value = []
 1886         self.mock_server_security_groups.return_value = []
 1887         self.mock_is_feature_available.return_value = False
 1888 
 1889         url = reverse('horizon:project:instances:update', args=[server.id])
 1890         res = self.client.get(url)
 1891 
 1892         self.assertTemplateUsed(res, views.WorkflowView.template_name)
 1893 
 1894         self.mock_server_get.assert_called_once_with(
 1895             helpers.IsHttpRequest(), server.id)
 1896         self.mock_security_group_list(helpers.IsHttpRequest(), tenant_id=None)
 1897         self.mock_server_security_groups(helpers.IsHttpRequest(), server.id)
 1898         self.mock_is_feature_available.assert_called_once_with(
 1899             helpers.IsHttpRequest(), "instance_description"
 1900         )
 1901 
 1902     @helpers.create_mocks(instance_update_get_stubs)
 1903     def test_instance_update_get_server_get_exception(self):
 1904         server = self.servers.first()
 1905 
 1906         self.mock_server_get.side_effect = self.exceptions.nova
 1907 
 1908         url = reverse('horizon:project:instances:update',
 1909                       args=[server.id])
 1910         res = self.client.get(url)
 1911 
 1912         self.assertRedirectsNoFollow(res, INDEX_URL)
 1913         self.mock_server_get.assert_called_once_with(
 1914             helpers.IsHttpRequest(), server.id)
 1915 
 1916     def _instance_update_post(self, server_id, server_name, secgroups):
 1917         default_role_field_name = 'default_' + \
 1918             workflows.update_instance.INSTANCE_SEC_GROUP_SLUG + '_role'
 1919         formData = {'name': server_name,
 1920                     default_role_field_name: 'member',
 1921                     SEC_GROUP_ROLE_PREFIX + 'member': secgroups}
 1922         url = reverse('horizon:project:instances:update',
 1923                       args=[server_id])
 1924         return self.client.post(url, formData)
 1925 
 1926     instance_update_post_stubs = {
 1927         api.nova: ('server_get', 'server_update', 'is_feature_available'),
 1928         api.neutron: ('security_group_list',
 1929                       'server_security_groups',
 1930                       'server_update_security_groups')}
 1931 
 1932     @helpers.create_mocks(instance_update_post_stubs)
 1933     def test_instance_update_post(self):
 1934         server = self.servers.first()
 1935         secgroups = self.security_groups.list()[:3]
 1936 
 1937         server_groups = [secgroups[0], secgroups[1]]
 1938         wanted_groups = [secgroups[1].id, secgroups[2].id]
 1939 
 1940         self.mock_server_get.return_value = server
 1941         self.mock_is_feature_available.return_value = False
 1942         self.mock_security_group_list.return_value = secgroups
 1943         self.mock_server_security_groups.return_value = server_groups
 1944         self.mock_server_update.return_value = server
 1945         self.mock_server_update_security_groups.return_value = None
 1946 
 1947         res = self._instance_update_post(server.id, server.name, wanted_groups)
 1948         self.assertNoFormErrors(res)
 1949         self.assertRedirectsNoFollow(res, INDEX_URL)
 1950 
 1951         self.mock_server_get.assert_called_once_with(
 1952             helpers.IsHttpRequest(), server.id)
 1953         self.mock_security_group_list.assert_called_once_with(
 1954             helpers.IsHttpRequest(), tenant_id=self.tenant.id)
 1955         self.mock_server_security_groups.assert_called_once_with(
 1956             helpers.IsHttpRequest(), server.id)
 1957         self.mock_server_update.assert_called_once_with(
 1958             helpers.IsHttpRequest(), server.id, server.name, description=None)
 1959         self.mock_server_update_security_groups.assert_called_once_with(
 1960             helpers.IsHttpRequest(), server.id, wanted_groups)
 1961         self.mock_is_feature_available.assert_called_once_with(
 1962             helpers.IsHttpRequest(), "instance_description"
 1963         )
 1964 
 1965     @helpers.create_mocks(instance_update_post_stubs)
 1966     def test_instance_update_post_with_desc(self):
 1967         server = self.servers.first()
 1968         secgroups = self.security_groups.list()[:3]
 1969 
 1970         server_groups = [secgroups[0], secgroups[1]]
 1971         test_description = 'test description'
 1972 
 1973         self.mock_server_get.return_value = server
 1974         self.mock_is_feature_available.return_value = True
 1975         self.mock_security_group_list.return_value = secgroups
 1976         self.mock_server_security_groups.return_value = server_groups
 1977         self.mock_server_update.return_value = server
 1978 
 1979         formData = {'name': server.name,
 1980                     'description': test_description}
 1981         url = reverse('horizon:project:instances:update',
 1982                       args=[server.id])
 1983         res = self.client.post(url, formData)
 1984         self.assertNoFormErrors(res)
 1985         self.assertRedirectsNoFollow(res, INDEX_URL)
 1986 
 1987         self.mock_server_get.assert_called_once_with(
 1988             helpers.IsHttpRequest(), server.id)
 1989         self.mock_security_group_list.assert_called_once_with(
 1990             helpers.IsHttpRequest(), tenant_id=self.tenant.id)
 1991         self.mock_server_security_groups.assert_called_once_with(
 1992             helpers.IsHttpRequest(), server.id)
 1993         self.mock_server_update.assert_called_once_with(
 1994             helpers.IsHttpRequest(), server.id, server.name,
 1995             description=test_description)
 1996         self.mock_is_feature_available.assert_called_once_with(
 1997             helpers.IsHttpRequest(), "instance_description"
 1998         )
 1999 
 2000     @helpers.create_mocks(instance_update_post_stubs)
 2001     def test_instance_update_post_api_exception(self):
 2002         server = self.servers.first()
 2003 
 2004         self.mock_server_get.return_value = server
 2005         self.mock_is_feature_available.return_value = False
 2006         self.mock_security_group_list.return_value = []
 2007         self.mock_server_security_groups.return_value = []
 2008         self.mock_server_update.side_effect = self.exceptions.nova
 2009         self.mock_server_update_security_groups.return_value = None
 2010 
 2011         res = self._instance_update_post(server.id, server.name, [])
 2012         self.assertRedirectsNoFollow(res, INDEX_URL)
 2013 
 2014         self.mock_server_get.assert_called_once_with(
 2015             helpers.IsHttpRequest(), server.id)
 2016         self.mock_security_group_list.assert_called_once_with(
 2017             helpers.IsHttpRequest(), tenant_id=self.tenant.id)
 2018         self.mock_server_security_groups.assert_called_once_with(
 2019             helpers.IsHttpRequest(), server.id)
 2020         self.mock_server_update.assert_called_once_with(
 2021             helpers.IsHttpRequest(), server.id, server.name, description=None)
 2022         self.mock_server_update_security_groups.assert_called_once_with(
 2023             helpers.IsHttpRequest(), server.id, [])
 2024         self.mock_is_feature_available.assert_called_once_with(
 2025             helpers.IsHttpRequest(), "instance_description"
 2026         )
 2027 
 2028     @helpers.create_mocks(instance_update_post_stubs)
 2029     def test_instance_update_post_secgroup_api_exception(self):
 2030         server = self.servers.first()
 2031 
 2032         self.mock_server_get.return_value = server
 2033         self.mock_is_feature_available.return_value = False
 2034         self.mock_security_group_list.return_value = []
 2035         self.mock_server_security_groups.return_value = []
 2036         self.mock_server_update.return_value = server
 2037         self.mock_server_update_security_groups.side_effect = \
 2038             self.exceptions.nova
 2039 
 2040         res = self._instance_update_post(server.id, server.name, [])
 2041         self.assertRedirectsNoFollow(res, INDEX_URL)
 2042 
 2043         self.mock_server_get.assert_called_once_with(
 2044             helpers.IsHttpRequest(), server.id)
 2045         self.mock_security_group_list.assert_called_once_with(
 2046             helpers.IsHttpRequest(), tenant_id=self.tenant.id)
 2047         self.mock_server_security_groups.assert_called_once_with(
 2048             helpers.IsHttpRequest(), server.id)
 2049         self.mock_server_update.assert_called_once_with(
 2050             helpers.IsHttpRequest(), server.id, server.name, description=None)
 2051         self.mock_server_update_security_groups.assert_called_once_with(
 2052             helpers.IsHttpRequest(), server.id, [])
 2053         self.mock_is_feature_available.assert_called_once_with(
 2054             helpers.IsHttpRequest(), "instance_description"
 2055         )
 2056 
 2057 
 2058 class InstanceLaunchInstanceTests(InstanceTestBase,
 2059                                   InstanceTableTestMixin):
 2060 
 2061     @helpers.create_mocks({api.nova: ('is_feature_available',
 2062                                       'flavor_list',
 2063                                       'keypair_list',
 2064                                       'server_group_list',
 2065                                       'availability_zone_list',),
 2066                            cinder: ('volume_snapshot_list',
 2067                                     'volume_list',),
 2068                            api.neutron: ('network_list',
 2069                                          'port_list_with_trunk_types',
 2070                                          'security_group_list',),
 2071                            api.glance: ('image_list_detailed',),
 2072                            quotas: ('tenant_quota_usages',)})
 2073     def test_launch_instance_get(self,
 2074                                  expect_password_fields=True,
 2075                                  custom_flavor_sort=None,
 2076                                  only_one_network=False,
 2077                                  config_drive_default=False):
 2078         image = self.versioned_images.first()
 2079 
 2080         self.mock_volume_list.return_value = []
 2081         self.mock_volume_snapshot_list.return_value = []
 2082         self._mock_glance_image_list_detailed(self.versioned_images.list())
 2083         self.mock_network_list.side_effect = [
 2084             self.networks.list()[:1],
 2085             [] if only_one_network else self.networks.list()[1:],
 2086             self.networks.list()[:1],
 2087             self.networks.list()[1:],
 2088         ]
 2089         self.mock_port_list_with_trunk_types.return_value = self.ports.list()
 2090         self.mock_server_group_list.return_value = self.server_groups.list()
 2091         self.mock_tenant_quota_usages.return_value = self.quota_usages.first()
 2092         self._mock_nova_lists()
 2093 
 2094         url = reverse('horizon:project:instances:launch')
 2095         params = urlencode({"source_type": "image_id",
 2096                             "source_id": image.id})
 2097         res = self.client.get("%s?%s" % (url, params))
 2098 
 2099         workflow = res.context['workflow']
 2100         self.assertTemplateUsed(res, views.WorkflowView.template_name)
 2101         self.assertEqual(res.context['workflow'].name,
 2102                          workflows.LaunchInstance.name)
 2103         step = workflow.get_step("setinstancedetailsaction")
 2104         self.assertEqual(step.action.initial['image_id'], image.id)
 2105         self.assertQuerysetEqual(
 2106             workflow.steps,
 2107             ['<SetInstanceDetails: setinstancedetailsaction>',
 2108              '<SetAccessControls: setaccesscontrolsaction>',
 2109              '<SetNetwork: setnetworkaction>',
 2110              '<SetNetworkPorts: setnetworkportsaction>',
 2111              '<PostCreationStep: customizeaction>',
 2112              '<SetAdvanced: setadvancedaction>'])
 2113 
 2114         if custom_flavor_sort == 'id':
 2115             # Reverse sorted by id
 2116             sorted_flavors = (
 2117                 ('eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee', 'm1.metadata'),
 2118                 ('dddddddd-dddd-dddd-dddd-dddddddddddd', 'm1.secret'),
 2119                 ('bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', 'm1.massive'),
 2120                 ('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 'm1.tiny'),
 2121             )
 2122         elif custom_flavor_sort == 'name':
 2123             sorted_flavors = (
 2124                 ('bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', 'm1.massive'),
 2125                 ('eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee', 'm1.metadata'),
 2126                 ('dddddddd-dddd-dddd-dddd-dddddddddddd', 'm1.secret'),
 2127                 ('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 'm1.tiny'),
 2128             )
 2129         elif custom_flavor_sort == helpers.my_custom_sort:
 2130             sorted_flavors = (
 2131                 ('dddddddd-dddd-dddd-dddd-dddddddddddd', 'm1.secret'),
 2132                 ('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 'm1.tiny'),
 2133                 ('bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', 'm1.massive'),
 2134                 ('eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee', 'm1.metadata'),
 2135             )
 2136         else:
 2137             # Default - sorted by RAM
 2138             sorted_flavors = (
 2139                 ('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 'm1.tiny'),
 2140                 ('bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', 'm1.massive'),
 2141                 ('dddddddd-dddd-dddd-dddd-dddddddddddd', 'm1.secret'),
 2142                 ('eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee', 'm1.metadata'),
 2143             )
 2144 
 2145         select_options = ''.join([
 2146             '<option value="%s">%s</option>' % (f[0], f[1])
 2147             for f in sorted_flavors
 2148         ])
 2149         self.assertContains(res, select_options)
 2150 
 2151         password_field_label = 'Admin Pass'
 2152         if expect_password_fields:
 2153             self.assertContains(res, password_field_label)
 2154         else:
 2155             self.assertNotContains(res, password_field_label)
 2156 
 2157         boot_from_image_field_label = 'Boot from image (creates a new volume)'
 2158         self.assertContains(res, boot_from_image_field_label)
 2159 
 2160         # NOTE(adriant): Django 1.11 changes the checked syntax to use html5
 2161         # "checked" rather than XHTML's "checked='checked'".
 2162         checked_box = (
 2163             '<input type="checkbox" name="network" '
 2164             'value="82288d84-e0a5-42ac-95be-e6af08727e42" '
 2165             'id="id_network_0" checked />'
 2166         )
 2167         if only_one_network:
 2168             self.assertContains(res, checked_box, html=True)
 2169         else:
 2170             self.assertNotContains(res, checked_box, html=True)
 2171 
 2172         self.assertContains(res, 'Disk Partition')
 2173         self.assertContains(res, 'Configuration Drive')
 2174 
 2175         step = workflow.get_step("setadvancedaction")
 2176         self.assertEqual(step.action.initial['config_drive'],
 2177                          config_drive_default)
 2178 
 2179         self.mock_volume_list.assert_has_calls([
 2180             mock.call(helpers.IsHttpRequest(),
 2181                       search_opts=VOLUME_SEARCH_OPTS),
 2182             mock.call(helpers.IsHttpRequest(),
 2183                       search_opts=VOLUME_BOOTABLE_SEARCH_OPTS),
 2184         ])
 2185         self.mock_volume_snapshot_list.assert_called_once_with(
 2186             helpers.IsHttpRequest(),
 2187             search_opts=SNAPSHOT_SEARCH_OPTS)
 2188 
 2189         self._check_glance_image_list_detailed(count=8)
 2190 
 2191         self.mock_network_list.assert_has_calls([
 2192             mock.call(helpers.IsHttpRequest(),
 2193                       tenant_id=self.tenant.id, shared=False),
 2194             mock.call(helpers.IsHttpRequest(), shared=True),
 2195             mock.call(helpers.IsHttpRequest(),
 2196                       tenant_id=self.tenant.id, shared=False),
 2197             mock.call(helpers.IsHttpRequest(), shared=True),
 2198         ])
 2199         self.assertEqual(4, self.mock_network_list.call_count)
 2200         self.mock_port_list_with_trunk_types.assert_has_calls(
 2201             [mock.call(helpers.IsHttpRequest(),
 2202                        network_id=net.id, tenant_id=self.tenant.id)
 2203              for net in self.networks.list()])
 2204         self.assertEqual(len(self.networks.list()),
 2205                          self.mock_port_list_with_trunk_types.call_count)
 2206         self.mock_server_group_list.assert_called_once_with(
 2207             helpers.IsHttpRequest())
 2208         self.mock_tenant_quota_usages.assert_called_once_with(
 2209             helpers.IsHttpRequest(),
 2210             targets=('instances', 'cores', 'ram', 'volumes', 'gigabytes'))
 2211         self._check_nova_lists(flavor_count=2)
 2212 
 2213     @helpers.update_settings(
 2214         OPENSTACK_HYPERVISOR_FEATURES={'can_set_password': False})
 2215     def test_launch_instance_get_without_password(self):
 2216         self.test_launch_instance_get(expect_password_fields=False)
 2217 
 2218     @helpers.update_settings(
 2219         OPENSTACK_HYPERVISOR_FEATURES={'requires_keypair': True})
 2220     def test_launch_instance_required_key(self):
 2221         flavor = self.flavors.first()
 2222         image = self.images.first()
 2223         image.min_ram = flavor.ram
 2224         image.min_disk = flavor.disk
 2225         res = self._launch_form_instance(image, flavor, keypair=None)
 2226         msg = "This field is required"
 2227         self.assertContains(res, msg)
 2228 
 2229     @django.test.utils.override_settings(
 2230         LAUNCH_INSTANCE_DEFAULTS={'config_drive': True})
 2231     def test_launch_instance_get_with_config_drive_default(self):
 2232         self.test_launch_instance_get(config_drive_default=True)
 2233 
 2234     @django.test.utils.override_settings(
 2235         CREATE_INSTANCE_FLAVOR_SORT={
 2236             'key': 'id',
 2237             'reverse': True,
 2238         })
 2239     def test_launch_instance_get_custom_flavor_sort_by_id(self):
 2240         self.test_launch_instance_get(custom_flavor_sort='id')
 2241 
 2242     @django.test.utils.override_settings(
 2243         CREATE_INSTANCE_FLAVOR_SORT={
 2244             'key': 'name',
 2245             'reverse': False,
 2246         })
 2247     def test_launch_instance_get_custom_flavor_sort_by_name(self):
 2248         self.test_launch_instance_get(custom_flavor_sort='name')
 2249 
 2250     @django.test.utils.override_settings(
 2251         CREATE_INSTANCE_FLAVOR_SORT={
 2252             'key': helpers.my_custom_sort,
 2253             'reverse': False,
 2254         })
 2255     def test_launch_instance_get_custom_flavor_sort_by_callable(self):
 2256         self.test_launch_instance_get(
 2257             custom_flavor_sort=helpers.my_custom_sort)
 2258 
 2259     @django.test.utils.override_settings(
 2260         CREATE_INSTANCE_FLAVOR_SORT={
 2261             'key': 'no_such_column',
 2262             'reverse': False,
 2263         })
 2264     def test_launch_instance_get_custom_flavor_sort_by_missing_column(self):
 2265         self.test_launch_instance_get(custom_flavor_sort='no_such_column')
 2266 
 2267     def test_launch_instance_get_with_only_one_network(self):
 2268         self.test_launch_instance_get(only_one_network=True)
 2269 
 2270     @helpers.create_mocks({api.nova: ('is_feature_available',
 2271                                       'flavor_list',
 2272                                       'keypair_list',
 2273                                       'server_group_list',
 2274                                       'availability_zone_list',),
 2275                            cinder: ('volume_snapshot_list',
 2276                                     'volume_list',),
 2277                            api.neutron: ('network_list',
 2278                                          'port_list_with_trunk_types',
 2279                                          'security_group_list',),
 2280                            api.glance: ('image_list_detailed',),
 2281                            quotas: ('tenant_quota_usages',)})
 2282     def test_launch_instance_get_images_snapshots(self,
 2283                                                   block_device_mapping_v2=True,
 2284                                                   only_one_network=False,
 2285                                                   disk_config=True,
 2286                                                   config_drive=True):
 2287         self.mock_volume_list.return_value = []
 2288         self.mock_volume_snapshot_list.return_value = []
 2289         self._mock_glance_image_list_detailed(self.versioned_images.list() +
 2290                                               self.versioned_snapshots.list())
 2291         self.mock_network_list.side_effect = [
 2292             self.networks.list()[:1],
 2293             [] if only_one_network else self.networks.list()[1:],
 2294             self.networks.list()[:1],
 2295             self.networks.list()[1:],
 2296         ]
 2297         self.mock_port_list_with_trunk_types.return_value = self.ports.list()
 2298         self.mock_server_group_list.return_value = self.server_groups.list()
 2299         self.mock_tenant_quota_usages.return_value = self.limits['absolute']
 2300         self._mock_nova_lists()
 2301 
 2302         url = reverse('horizon:project:instances:launch')
 2303         res = self.client.get(url)
 2304 
 2305         image_sources = (res.context_data['workflow'].steps[0].
 2306                          action.fields['image_id'].choices)
 2307 
 2308         snapshot_sources = (res.context_data['workflow'].steps[0].
 2309                             action.fields['instance_snapshot_id'].choices)
 2310 
 2311         images = [image.id for image in self.versioned_images.list()]
 2312         snapshots = [s.id for s in self.versioned_snapshots.list()]
 2313 
 2314         image_sources_ids = []
 2315         snapshot_sources_ids = []
 2316         for image in image_sources:
 2317             self.assertTrue(image[0] in images or image[0] == '')
 2318             if image[0] != '':
 2319                 image_sources_ids.append(image[0])
 2320 
 2321         for image in images:
 2322             self.assertIn(image, image_sources_ids)
 2323 
 2324         for snapshot in snapshot_sources:
 2325             self.assertTrue(snapshot[0] in snapshots or snapshot[0] == '')
 2326             if snapshot[0] != '':
 2327                 snapshot_sources_ids.append(snapshot[0])
 2328 
 2329         for snapshot in snapshots:
 2330             self.assertIn(snapshot, snapshot_sources_ids)
 2331 
 2332         self.mock_volume_list.assert_has_calls([
 2333             mock.call(helpers.IsHttpRequest(),
 2334                       search_opts=VOLUME_SEARCH_OPTS),
 2335             mock.call(helpers.IsHttpRequest(),
 2336                       search_opts=VOLUME_BOOTABLE_SEARCH_OPTS),
 2337         ])
 2338         self.mock_volume_snapshot_list.assert_called_once_with(
 2339             helpers.IsHttpRequest(),
 2340             search_opts=SNAPSHOT_SEARCH_OPTS)
 2341         self._check_glance_image_list_detailed(count=8)
 2342         self.mock_network_list.assert_has_calls([
 2343             mock.call(helpers.IsHttpRequest(),
 2344                       tenant_id=self.tenant.id, shared=False),
 2345             mock.call(helpers.IsHttpRequest(), shared=True),
 2346             mock.call(helpers.IsHttpRequest(),
 2347                       tenant_id=self.tenant.id, shared=False),
 2348             mock.call(helpers.IsHttpRequest(), shared=True),
 2349         ])
 2350         self.assertEqual(4, self.mock_network_list.call_count)
 2351         self.mock_port_list_with_trunk_types.assert_has_calls(
 2352             [mock.call(helpers.IsHttpRequest(),
 2353                        network_id=net.id, tenant_id=self.tenant.id)
 2354              for net in self.networks.list()])
 2355         self.mock_server_group_list.assert_called_once_with(
 2356             helpers.IsHttpRequest())
 2357         self.mock_tenant_quota_usages.assert_called_once_with(
 2358             helpers.IsHttpRequest(),
 2359             targets=('instances', 'cores', 'ram', 'volumes', 'gigabytes'))
 2360         self._check_nova_lists(flavor_count=2)
 2361 
 2362     @helpers.create_mocks({api.nova: ('is_feature_available',
 2363                                       'flavor_list',
 2364                                       'keypair_list',
 2365                                       'server_group_list',
 2366                                       'availability_zone_list',),
 2367                            cinder: ('volume_snapshot_list',
 2368                                     'volume_list',),
 2369                            api.neutron: ('network_list',
 2370                                          'port_list_with_trunk_types',
 2371                                          'security_group_list',),
 2372                            api.glance: ('image_list_detailed',),
 2373                            quotas: ('tenant_quota_usages',)})
 2374     def test_launch_instance_get_bootable_volumes(self,
 2375                                                   block_device_mapping_v2=True,
 2376                                                   only_one_network=False,
 2377                                                   disk_config=True,
 2378                                                   config_drive=True):
 2379         volumes = [v for v in self.cinder_volumes.list()
 2380                    if (v.status == AVAILABLE and v.bootable == 'true')]
 2381         self.mock_volume_list.return_value = volumes
 2382         self.mock_volume_snapshot_list.return_value = []
 2383         self._mock_glance_image_list_detailed(self.versioned_images.list())
 2384         self.mock_network_list.side_effect = [
 2385             self.networks.list()[:1],
 2386             [] if only_one_network else self.networks.list()[1:],
 2387             self.networks.list()[:1],
 2388             self.networks.list()[1:],
 2389         ]
 2390         self.mock_port_list_with_trunk_types.return_value = self.ports.list()
 2391         self.mock_server_group_list.return_value = self.server_groups.list()
 2392         self.mock_tenant_quota_usages.return_value = self.quota_usages.first()
 2393         self._mock_nova_lists()
 2394 
 2395         url = reverse('horizon:project:instances:launch')
 2396         res = self.client.get(url)
 2397 
 2398         bootable_volumes = [v.id for v in self.cinder_volumes.list()
 2399                             if (v.bootable == 'true' and
 2400                                 v.status == 'available')]
 2401 
 2402         volume_sources = (res.context_data['workflow'].steps[0].
 2403                           action.fields['volume_id'].choices)
 2404 
 2405         volume_sources_ids = []
 2406         for volume in volume_sources:
 2407             self.assertTrue(volume[0].split(":vol")[0] in bootable_volumes or
 2408                             volume[0] == '')
 2409             if volume[0] != '':
 2410                 volume_sources_ids.append(volume[0].split(":vol")[0])
 2411 
 2412         for volume in bootable_volumes:
 2413             self.assertIn(volume, volume_sources_ids)
 2414 
 2415         self.mock_volume_list.assert_has_calls([
 2416             mock.call(helpers.IsHttpRequest(),
 2417                       search_opts=VOLUME_SEARCH_OPTS),
 2418             mock.call(helpers.IsHttpRequest(),
 2419                       search_opts=VOLUME_BOOTABLE_SEARCH_OPTS),
 2420         ])
 2421         self.mock_volume_snapshot_list.assert_called_once_with(
 2422             helpers.IsHttpRequest(),
 2423             search_opts=SNAPSHOT_SEARCH_OPTS)
 2424         self._check_glance_image_list_detailed(count=8)
 2425         self.mock_network_list.assert_has_calls([
 2426             mock.call(helpers.IsHttpRequest(),
 2427                       tenant_id=self.tenant.id, shared=False),
 2428             mock.call(helpers.IsHttpRequest(), shared=True),
 2429             mock.call(helpers.IsHttpRequest(),
 2430                       tenant_id=self.tenant.id, shared=False),
 2431             mock.call(helpers.IsHttpRequest(), shared=True),
 2432         ])
 2433         self.assertEqual(4, self.mock_network_list.call_count)
 2434         self.mock_port_list_with_trunk_types.assert_has_calls(
 2435             [mock.call(helpers.IsHttpRequest(),
 2436                        network_id=net.id, tenant_id=self.tenant.id)
 2437              for net in self.networks.list()])
 2438         self.mock_server_group_list.assert_called_once_with(
 2439             helpers.IsHttpRequest())
 2440         self.mock_tenant_quota_usages.assert_called_once_with(
 2441             helpers.IsHttpRequest(),
 2442             targets=('instances', 'cores', 'ram', 'volumes', 'gigabytes'))
 2443         self._check_nova_lists(flavor_count=2)
 2444 
 2445     @helpers.create_mocks({api.glance: ('image_list_detailed',),
 2446                            api.neutron: ('network_list',
 2447                                          'port_create',
 2448                                          'port_list_with_trunk_types',
 2449                                          'security_group_list',),
 2450                            api.nova: ('is_feature_available',
 2451                                       'flavor_list',
 2452                                       'keypair_list',
 2453                                       'availability_zone_list',
 2454                                       'server_group_list',
 2455                                       'server_create',),
 2456                            cinder: ('volume_list',
 2457                                     'volume_snapshot_list',),
 2458                            quotas: ('tenant_quota_usages',)})
 2459     def test_launch_instance_post(self):
 2460         flavor = self.flavors.first()
 2461         image = self.versioned_images.first()
 2462         keypair = self.keypairs.first()
 2463         server = self.servers.first()
 2464         sec_group = self.security_groups.first()
 2465         avail_zone = self.availability_zones.first()
 2466         customization_script = 'user data'
 2467         nics = [{"net-id": self.networks.first().id, "v4-fixed-ip": ''}]
 2468         quota_usages = self.quota_usages.first()
 2469         scheduler_hints = {"group": self.server_groups.first().id}
 2470 
 2471         self._mock_nova_glance_neutron_lists()
 2472 
 2473         self.mock_server_group_list.return_value = self.server_groups.list()
 2474         self.mock_volume_list.return_value = []
 2475         self.mock_volume_snapshot_list.return_value = []
 2476         self.mock_server_create.return_value = None
 2477         self.mock_tenant_quota_usages.return_value = quota_usages
 2478         self.mock_flavor_list.return_value = self.flavors.list()
 2479 
 2480         form_data = {'flavor': flavor.id,
 2481                      'source_type': 'image_id',
 2482                      'image_id': image.id,
 2483                      'keypair': keypair.name,
 2484                      'name': server.name,
 2485                      'script_source': 'raw',
 2486                      'script_data': customization_script,
 2487                      'project_id': self.tenants.first().id,
 2488                      'user_id': self.user.id,
 2489                      'groups': str(sec_group.id),
 2490                      'availability_zone': avail_zone.zoneName,
 2491                      'volume_type': '',
 2492                      'network': self.networks.first().id,
 2493                      'count': 1,
 2494                      'server_group': self.server_groups.first().id,
 2495                      'disk_config': 'AUTO',
 2496                      'config_drive': True,
 2497                      }
 2498         url = reverse('horizon:project:instances:launch')
 2499         res = self.client.post(url, form_data)
 2500 
 2501         self.assertNoFormErrors(res)
 2502         self.assertRedirectsNoFollow(res, INDEX_URL)
 2503 
 2504         self._check_nova_glance_neutron_lists(flavor_count=2, image_count=8)
 2505         self.mock_server_group_list.assert_called_once_with(
 2506             helpers.IsHttpRequest())
 2507         self.mock_volume_list.assert_has_calls([
 2508             mock.call(helpers.IsHttpRequest(),
 2509                       search_opts=VOLUME_SEARCH_OPTS),
 2510             mock.call(helpers.IsHttpRequest(),
 2511                       search_opts=VOLUME_BOOTABLE_SEARCH_OPTS),
 2512         ])
 2513         self.mock_volume_snapshot_list.assert_called_once_with(
 2514             helpers.IsHttpRequest(),
 2515             search_opts=SNAPSHOT_SEARCH_OPTS)
 2516         self.mock_server_create.assert_called_once_with(
 2517             helpers.IsHttpRequest(),
 2518             server.name,
 2519             image.id,
 2520             flavor.id,
 2521             keypair.name,
 2522             customization_script,
 2523             [str(sec_group.id)],
 2524             block_device_mapping=None,
 2525             block_device_mapping_v2=None,
 2526             nics=nics,
 2527             availability_zone=avail_zone.zoneName,
 2528             instance_count=helpers.IsA(int),
 2529             admin_pass='',
 2530             disk_config='AUTO',
 2531             config_drive=True,
 2532             scheduler_hints=scheduler_hints)
 2533         self.mock_tenant_quota_usages.assert_called_once_with(
 2534             helpers.IsHttpRequest(),
 2535             targets=('instances', 'cores', 'ram', 'volumes', ))
 2536         self.assert_mock_multiple_calls_with_same_arguments(
 2537             self.mock_flavor_list, 2,
 2538             mock.call(helpers.IsHttpRequest()))
 2539 
 2540     @helpers.create_mocks({api.glance: ('image_list_detailed',),
 2541                            api.neutron: ('network_list',
 2542                                          'port_create',
 2543                                          'port_list_with_trunk_types',
 2544                                          'security_group_list',),
 2545                            api.nova: ('is_feature_available',
 2546                                       'flavor_list',
 2547                                       'keypair_list',
 2548                                       'availability_zone_list',
 2549                                       'server_group_list',
 2550                                       'server_create',),
 2551                            cinder: ('volume_list',
 2552                                     'volume_snapshot_list',),
 2553                            quotas: ('tenant_quota_usages',)})
 2554     def test_launch_instance_post_boot_from_volume(self):
 2555         flavor = self.flavors.first()
 2556         keypair = self.keypairs.first()
 2557         server = self.servers.first()
 2558         volume = self.cinder_volumes.first()
 2559         sec_group = self.security_groups.first()
 2560         avail_zone = self.availability_zones.first()
 2561         customization_script = 'user data'
 2562         device_name = 'vda'
 2563         volume_choice = "%s:vol" % volume.id
 2564 
 2565         volume_source_id = volume.id.split(':')[0]
 2566         block_device_mapping = None
 2567         block_device_mapping_2 = [
 2568             {'device_name': 'vda',
 2569              'source_type': 'volume',
 2570              'destination_type': 'volume',
 2571              'delete_on_termination': False,
 2572              'uuid': volume_source_id,
 2573              'boot_index': '0',
 2574              'volume_size': 1
 2575              }
 2576         ]
 2577 
 2578         nics = [{"net-id": self.networks.first().id, "v4-fixed-ip": ''}]
 2579         quota_usages = self.quota_usages.first()
 2580 
 2581         self._mock_nova_glance_neutron_lists()
 2582 
 2583         volumes = [v for v in self.cinder_volumes.list()
 2584                    if (v.status == AVAILABLE and v.bootable == 'true')]
 2585         self.mock_volume_list.return_value = volumes
 2586         self.mock_volume_snapshot_list.return_value = []
 2587         self.mock_server_create.return_value = None
 2588         self.mock_tenant_quota_usages.return_value = quota_usages
 2589 
 2590         form_data = {'flavor': flavor.id,
 2591                      'source_type': 'volume_id',
 2592                      'source_id': volume_choice,
 2593                      'keypair': keypair.name,
 2594                      'name': server.name,
 2595                      'script_source': 'raw',
 2596                      'script_data': customization_script,
 2597                      'project_id': self.tenants.first().id,
 2598                      'user_id': self.user.id,
 2599                      'groups': str(sec_group.id),
 2600                      'availability_zone': avail_zone.zoneName,
 2601                      'volume_size': '1',
 2602                      'volume_id': volume_choice,
 2603                      'device_name': device_name,
 2604                      'network': self.networks.first().id,
 2605                      'count': 1,
 2606                      'disk_config': 'AUTO',
 2607                      'config_drive': True}
 2608         url = reverse('horizon:project:instances:launch')
 2609         res = self.client.post(url, form_data)
 2610 
 2611         self.assertNoFormErrors(res)
 2612         self.assertRedirectsNoFollow(res, INDEX_URL)
 2613 
 2614         self._check_nova_glance_neutron_lists(flavor_count=2, image_count=6)
 2615         self.mock_volume_list.assert_has_calls([
 2616             mock.call(helpers.IsHttpRequest(),
 2617                       search_opts=VOLUME_SEARCH_OPTS),
 2618             mock.call(helpers.IsHttpRequest(),
 2619                       search_opts=VOLUME_BOOTABLE_SEARCH_OPTS),
 2620         ])
 2621         self.mock_volume_snapshot_list.assert_called_once_with(
 2622             helpers.IsHttpRequest(),
 2623             search_opts=SNAPSHOT_SEARCH_OPTS)
 2624         self.mock_server_group_list.assert_called_once_with(
 2625             helpers.IsHttpRequest())
 2626 
 2627         self.mock_server_create.assert_called_once_with(
 2628             helpers.IsHttpRequest(),
 2629             server.name,
 2630             '',
 2631             flavor.id,
 2632             keypair.name,
 2633             customization_script,
 2634             [str(sec_group.id)],
 2635             block_device_mapping=block_device_mapping,
 2636             block_device_mapping_v2=block_device_mapping_2,
 2637             nics=nics,
 2638             availability_zone=avail_zone.zoneName,
 2639             instance_count=helpers.IsA(int),
 2640             admin_pass='',
 2641             disk_config='AUTO',
 2642             config_drive=True,
 2643             scheduler_hints={})
 2644         self.mock_tenant_quota_usages.assert_called_once_with(
 2645             helpers.IsHttpRequest(),
 2646             targets=('instances', 'cores', 'ram', 'volumes', ))
 2647         self.assert_mock_multiple_calls_with_same_arguments(
 2648             self.mock_flavor_list, 2,
 2649             mock.call(helpers.IsHttpRequest()))
 2650 
 2651     @helpers.create_mocks({api.glance: ('image_list_detailed',),
 2652                            api.neutron: ('network_list',
 2653                                          'port_create',
 2654                                          'port_list_with_trunk_types',
 2655                                          'security_group_list',),
 2656                            api.nova: ('server_create',
 2657                                       'is_feature_available',
 2658                                       'flavor_list',
 2659                                       'keypair_list',
 2660                                       'availability_zone_list',
 2661                                       'server_group_list',),
 2662                            cinder: ('volume_list',
 2663                                     'volume_snapshot_list',),
 2664                            quotas: ('tenant_quota_usages',)})
 2665     def test_launch_instance_post_no_images_available_boot_from_volume(self):
 2666         flavor = self.flavors.first()
 2667         keypair = self.keypairs.first()
 2668         server = self.servers.first()
 2669         volume = self.cinder_volumes.first()
 2670         sec_group = self.security_groups.first()
 2671         avail_zone = self.availability_zones.first()
 2672         customization_script = 'user data'
 2673         device_name = 'vda'
 2674         volume_choice = "%s:vol" % volume.id
 2675         block_device_mapping = [
 2676             {'device_name': device_name,
 2677              'source_type': 'volume',
 2678              'destination_type': 'volume',
 2679              'delete_on_termination': False,
 2680              'uuid': volume.id,
 2681              'boot_index': '0',
 2682              'volume_size': None,
 2683              }
 2684         ]
 2685         nics = [{"net-id": self.networks.first().id, "v4-fixed-ip": ''}]
 2686         quota_usages = self.quota_usages.first()
 2687 
 2688         self._mock_nova_glance_neutron_lists()
 2689 
 2690         self.mock_flavor_list.return_value = self.flavors.list()
 2691         volumes = [v for v in self.cinder_volumes.list()
 2692                    if (v.status == AVAILABLE and v.bootable == 'true')]
 2693         self.mock_volume_list.return_value = volumes
 2694         self.mock_volume_snapshot_list.return_value = []
 2695         self.mock_tenant_quota_usages.return_value = quota_usages
 2696         self.mock_server_create.return_value = None
 2697 
 2698         form_data = {'flavor': flavor.id,
 2699                      'source_type': 'volume_id',
 2700                      # 'image_id': '',
 2701                      'keypair': keypair.name,
 2702                      'name': server.name,
 2703                      'script_source': 'raw',
 2704                      'script_data': customization_script,
 2705                      'project_id': self.tenants.first().id,
 2706                      'user_id': self.user.id,
 2707                      'groups': str(sec_group.id),
 2708                      'availability_zone': avail_zone.zoneName,
 2709                      'network': self.networks.first().id,
 2710                      'volume_type': 'volume_id',
 2711                      'volume_id': volume_choice,
 2712                      'device_name': device_name,
 2713                      'count': 1,
 2714                      'disk_config': 'MANUAL',
 2715                      'config_drive': True}
 2716         url = reverse('horizon:project:instances:launch')
 2717         res = self.client.post(url, form_data)
 2718 
 2719         self.assertNoFormErrors(res)
 2720         self.assertRedirectsNoFollow(res, INDEX_URL)
 2721 
 2722         self._check_nova_glance_neutron_lists(flavor_count=2,
 2723                                               image_count=6)
 2724         self.assert_mock_multiple_calls_with_same_arguments(
 2725             self.mock_flavor_list, 2,
 2726             mock.call(helpers.IsHttpRequest()))
 2727         self.mock_server_group_list.assert_called_once_with(
 2728             helpers.IsHttpRequest())
 2729         self.mock_volume_list.assert_has_calls([
 2730             mock.call(helpers.IsHttpRequest(),
 2731                       search_opts=VOLUME_SEARCH_OPTS),
 2732             mock.call(helpers.IsHttpRequest(),
 2733                       search_opts=VOLUME_BOOTABLE_SEARCH_OPTS),
 2734         ])
 2735         self.mock_volume_snapshot_list.assert_called_once_with(
 2736             helpers.IsHttpRequest(),
 2737             search_opts=SNAPSHOT_SEARCH_OPTS)
 2738         self.mock_tenant_quota_usages.assert_called_once_with(
 2739             helpers.IsHttpRequest(),
 2740             targets=('instances', 'cores', 'ram', 'volumes', ))
 2741 
 2742         self.mock_server_create.assert_called_once_with(
 2743             helpers.IsHttpRequest(),
 2744             server.name,
 2745             '',
 2746             flavor.id,
 2747             keypair.name,
 2748             customization_script,
 2749             [str(sec_group.id)],
 2750             block_device_mapping=None,
 2751             block_device_mapping_v2=block_device_mapping,
 2752             nics=nics,
 2753             availability_zone=avail_zone.zoneName,
 2754             instance_count=helpers.IsA(int),
 2755             admin_pass='',
 2756             disk_config='MANUAL',
 2757             config_drive=True,
 2758             scheduler_hints={})
 2759 
 2760     @helpers.create_mocks({api.glance: ('image_list_detailed',),
 2761                            api.neutron: ('network_list',
 2762                                          'port_list_with_trunk_types',
 2763                                          'security_group_list',),
 2764                            api.nova: ('is_feature_available',
 2765                                       'flavor_list',
 2766                                       'keypair_list',
 2767                                       'server_group_list',
 2768                                       'availability_zone_list'),
 2769                            cinder: ('volume_list',
 2770                                     'volume_snapshot_list',),
 2771                            quotas: ('tenant_quota_usages',)})
 2772     def test_launch_instance_post_no_images_available(self):
 2773         flavor = self.flavors.first()
 2774         keypair = self.keypairs.first()
 2775         server = self.servers.first()
 2776         sec_group = self.security_groups.first()
 2777         avail_zone = self.availability_zones.first()
 2778         customization_script = 'user data'
 2779         quota_usages = self.quota_usages.first()
 2780 
 2781         self.mock_tenant_quota_usages.return_value = self.quota_usages.first()
 2782         self._mock_glance_image_list_detailed([])
 2783         self._mock_neutron_network_and_port_list()
 2784         self._mock_nova_lists()
 2785         self.mock_volume_list.return_value = []
 2786         self.mock_volume_snapshot_list.return_value = []
 2787         self.mock_tenant_quota_usages.return_value = quota_usages
 2788 
 2789         form_data = {'flavor': flavor.id,
 2790                      'source_type': 'image_id',
 2791                      'image_id': '',
 2792                      'keypair': keypair.name,
 2793                      'name': server.name,
 2794                      'script_source': 'raw',
 2795                      'script_data': customization_script,
 2796                      'project_id': self.tenants.first().id,
 2797                      'user_id': self.user.id,
 2798                      'groups': str(sec_group.id),
 2799                      'availability_zone': avail_zone.zoneName,
 2800                      'volume_type': '',
 2801                      'count': 1}
 2802         url = reverse('horizon:project:instances:launch')
 2803         res = self.client.post(url, form_data)
 2804 
 2805         self.assertFormErrors(res, 1, "You must select an image.")
 2806         self.assertTemplateUsed(res, views.WorkflowView.template_name)
 2807 
 2808         self.mock_tenant_quota_usages.assert_has_calls([
 2809             mock.call(
 2810                 helpers.IsHttpRequest(),
 2811                 targets=('instances', 'cores', 'ram', 'volumes', )),
 2812             mock.call(
 2813                 helpers.IsHttpRequest(),
 2814                 targets=('instances', 'cores', 'ram', 'volumes', 'gigabytes')),
 2815         ])
 2816         self.assertEqual(2, self.mock_tenant_quota_usages.call_count)
 2817         self._check_glance_image_list_detailed(count=8)
 2818         self._check_neutron_network_and_port_list()
 2819         self._check_nova_lists(flavor_count=3)
 2820         self.mock_volume_list.assert_has_calls([
 2821             mock.call(helpers.IsHttpRequest(),
 2822                       search_opts=VOLUME_SEARCH_OPTS),
 2823             mock.call(helpers.IsHttpRequest(),
 2824                       search_opts=VOLUME_BOOTABLE_SEARCH_OPTS),
 2825         ])
 2826         self.mock_volume_snapshot_list.assert_called_once_with(
 2827             helpers.IsHttpRequest(),
 2828             search_opts=SNAPSHOT_SEARCH_OPTS)
 2829         self.mock_tenant_quota_usages.assert_has_calls([
 2830             mock.call(
 2831                 helpers.IsHttpRequest(),
 2832                 targets=('instances', 'cores', 'ram', 'volumes', )),
 2833             mock.call(
 2834                 helpers.IsHttpRequest(),
 2835                 targets=('instances', 'cores', 'ram', 'volumes', 'gigabytes')),
 2836         ])
 2837         self.assertEqual(2, self.mock_tenant_quota_usages.call_count)
 2838 
 2839     @helpers.create_mocks({
 2840         api.glance: ('image_list_detailed',),
 2841         api.neutron: ('network_list',
 2842                       'port_create',
 2843                       'port_list_with_trunk_types',
 2844                       'security_group_list',),
 2845         api.nova: ('is_feature_available',
 2846                    'flavor_list',
 2847                    'keypair_list',
 2848                    'availability_zone_list',
 2849                    'server_group_list',
 2850                    'server_create',),
 2851         cinder: ('volume_list',
 2852                  'volume_snapshot_list',),
 2853         quotas: ('tenant_quota_usages',)})
 2854     def test_launch_instance_post_boot_from_snapshot(self):
 2855         flavor = self.flavors.first()
 2856         keypair = self.keypairs.first()
 2857         server = self.servers.first()
 2858         snapshot = self.cinder_volume_snapshots.first()
 2859         sec_group = self.security_groups.first()
 2860         avail_zone = self.availability_zones.first()
 2861         customization_script = 'user data'
 2862         device_name = 'vda'
 2863         snapshot_choice = "%s:snap" % snapshot.id
 2864 
 2865         snapshot_source_id = snapshot.id.split(':')[0]
 2866         block_device_mapping = None
 2867         block_device_mapping_2 = [
 2868             {'device_name': 'vda',
 2869              'source_type': 'snapshot',
 2870              'destination_type': 'volume',
 2871              'delete_on_termination': 0,
 2872              'uuid': snapshot_source_id,
 2873              'boot_index': '0',
 2874              'volume_size': 1
 2875              }
 2876         ]
 2877 
 2878         nics = [{"net-id": self.networks.first().id, "v4-fixed-ip": ''}]
 2879         quota_usages = self.quota_usages.first()
 2880 
 2881         self._mock_nova_glance_neutron_lists()
 2882 
 2883         volumes = [v for v in self.cinder_volumes.list()
 2884                    if (getattr(v, 'bootable', 'false') == 'true')]
 2885         snapshots = [v for v in self.cinder_volume_snapshots.list()
 2886                      if (v.status == AVAILABLE)]
 2887         self.mock_volume_list.return_value = volumes
 2888         self.mock_volume_snapshot_list.return_value = snapshots
 2889         self.mock_server_create.return_value = None
 2890         self.mock_tenant_quota_usages.return_value = quota_usages
 2891 
 2892         form_data = {'flavor': flavor.id,
 2893                      'source_type': 'volume_snapshot_id',
 2894                      'source_id': snapshot_choice,
 2895                      'keypair': keypair.name,
 2896                      'name': server.name,
 2897                      'script_source': 'raw',
 2898                      'script_data': customization_script,
 2899                      'project_id': self.tenants.first().id,
 2900                      'user_id': self.user.id,
 2901                      'groups': str(sec_group.id),
 2902                      'availability_zone': avail_zone.zoneName,
 2903                      'volume_size': '1',
 2904                      'volume_snapshot_id': snapshot_choice,
 2905                      'device_name': device_name,
 2906                      'network': self.networks.first().id,
 2907                      'count': 1,
 2908                      'disk_config': 'AUTO',
 2909                      'config_drive': True}
 2910         url = reverse('horizon:project:instances:launch')
 2911         res = self.client.post(url, form_data)
 2912 
 2913         self.assertNoFormErrors(res)
 2914         self.assertRedirectsNoFollow(res, INDEX_URL)
 2915 
 2916         self.assert_mock_multiple_calls_with_same_arguments(
 2917             self.mock_flavor_list, 2,
 2918             mock.call(helpers.IsHttpRequest()))
 2919         self.mock_volume_list.assert_has_calls([
 2920             mock.call(helpers.IsHttpRequest(),
 2921                       search_opts=VOLUME_SEARCH_OPTS),
 2922             mock.call(helpers.IsHttpRequest(),
 2923                       search_opts=VOLUME_BOOTABLE_SEARCH_OPTS),
 2924         ])
 2925         self.mock_volume_snapshot_list.assert_called_once_with(
 2926             helpers.IsHttpRequest(),
 2927             search_opts=SNAPSHOT_SEARCH_OPTS)
 2928 
 2929         self.mock_server_create.assert_called_once_with(
 2930             helpers.IsHttpRequest(),
 2931             server.name,
 2932             '',
 2933             flavor.id,
 2934             keypair.name,
 2935             customization_script,
 2936             [str(sec_group.id)],
 2937             block_device_mapping=block_device_mapping,
 2938             block_device_mapping_v2=block_device_mapping_2,
 2939             nics=nics,
 2940             availability_zone=avail_zone.zoneName,
 2941             instance_count=helpers.IsA(int),
 2942             admin_pass='',
 2943             disk_config='AUTO',
 2944             config_drive=True,
 2945             scheduler_hints={})
 2946         self.mock_tenant_quota_usages.assert_called_once_with(
 2947             helpers.IsHttpRequest(),
 2948             targets=('instances', 'cores', 'ram', 'volumes', ))
 2949 
 2950     @helpers.create_mocks({
 2951         api.glance: ('image_list_detailed',),
 2952         api.neutron: ('network_list',
 2953                       'port_create',
 2954                       'port_list_with_trunk_types',
 2955                       'security_group_list',),
 2956         api.nova: ('is_feature_available',
 2957                    'flavor_list',
 2958                    'keypair_list',
 2959                    'availability_zone_list',
 2960                    'server_group_list',
 2961                    'server_create'),
 2962         cinder: ('volume_list',
 2963                  'volume_snapshot_list'),
 2964         quotas: ('tenant_quota_usages',)})
 2965     def test_launch_instance_post_boot_from_snapshot_error(self):
 2966         flavor = self.flavors.first()
 2967         keypair = self.keypairs.first()
 2968         server = self.servers.first()
 2969         avail_zone = self.availability_zones.first()
 2970         quota_usages = self.quota_usages.first()
 2971 
 2972         self.mock_image_list_detailed.return_value = [[], False, False]
 2973         self.mock_tenant_quota_usages.return_value = quota_usages
 2974         self._mock_neutron_network_and_port_list()
 2975 
 2976         bad_snapshot_id = 'a-bogus-id'
 2977 
 2978         form_data = {'flavor': flavor.id,
 2979                      'source_type': 'instance_snapshot_id',
 2980                      'instance_snapshot_id': bad_snapshot_id,
 2981                      'keypair': keypair.name,
 2982                      'name': server.name,
 2983                      'script_source': 'raw',
 2984                      'availability_zone': avail_zone.zoneName,
 2985                      'network': self.networks.first().id,
 2986                      'volume_id': '',
 2987                      'volume_snapshot_id': '',
 2988                      'image_id': '',
 2989                      'device_name': 'vda',
 2990                      'count': 1,
 2991                      'customization_script': ''}
 2992 
 2993         url = reverse('horizon:project:instances:launch')
 2994         res = self.client.post(url, form_data)
 2995 
 2996         self.assertFormErrors(res, 3, "You must select a snapshot.")
 2997 
 2998         self.assertEqual(4, self.mock_image_list_detailed.call_count)
 2999         self.mock_image_list_detailed.assert_has_calls([
 3000             mock.call(helpers.IsHttpRequest(),
 3001                       filters={'is_public': True,
 3002                                'status': 'active'}),
 3003             mock.call(helpers.IsHttpRequest(),
 3004                       filters={'property-owner_id': self.tenant.id,
 3005                                'status': 'active'}),
 3006             mock.call(helpers.IsHttpRequest(),
 3007                       filters={'status': 'active', 'visibility': 'community'}),
 3008             mock.call(helpers.IsHttpRequest(),
 3009                       filters={'status': 'active', 'visibility': 'shared'}),
 3010         ])
 3011 
 3012         self.mock_tenant_quota_usages.assert_has_calls([
 3013             mock.call(
 3014                 helpers.IsHttpRequest(),
 3015                 targets=('instances', 'cores', 'ram', 'volumes', )),
 3016             mock.call(
 3017                 helpers.IsHttpRequest(),
 3018                 targets=('instances', 'cores', 'ram', 'volumes', 'gigabytes')),
 3019         ])
 3020         self.assertEqual(2, self.mock_tenant_quota_usages.call_count)
 3021 
 3022         self._check_neutron_network_and_port_list()
 3023 
 3024     @helpers.create_mocks({api.glance: ('image_list_detailed',),
 3025                            api.neutron: ('network_list',
 3026                                          'port_list_with_trunk_types',
 3027                                          'security_group_list',),
 3028                            cinder: ('volume_list',
 3029                                     'volume_snapshot_list',),
 3030                            api.nova: ('is_feature_available',
 3031                                       'flavor_list',
 3032                                       'keypair_list',
 3033                                       'availability_zone_list',
 3034                                       'server_group_list',),
 3035                            quotas: ('tenant_quota_usages',)})
 3036     def test_launch_flavorlist_error(self):
 3037         self.mock_volume_list.return_value = []
 3038         self.mock_volume_snapshot_list.return_value = []
 3039         self._mock_glance_image_list_detailed(self.versioned_images.list())
 3040         self._mock_neutron_network_and_port_list()
 3041         self.mock_tenant_quota_usages.return_value = self.quota_usages.first()
 3042         self.mock_flavor_list.side_effect = self.exceptions.nova
 3043         self.mock_keypair_list.return_value = self.keypairs.list()
 3044         self.mock_security_group_list.return_value = \
 3045             self.security_groups.list()
 3046         self.mock_availability_zone_list.return_value = \
 3047             self.availability_zones.list()
 3048         self.mock_server_group_list.return_value = self.server_groups.list()
 3049 
 3050         url = reverse('horizon:project:instances:launch')
 3051         res = self.client.get(url)
 3052 
 3053         self.assertTemplateUsed(res, views.WorkflowView.template_name)
 3054 
 3055         self.mock_volume_list.assert_has_calls([
 3056             mock.call(helpers.IsHttpRequest(),
 3057                       search_opts=VOLUME_SEARCH_OPTS),
 3058             mock.call(helpers.IsHttpRequest(),
 3059                       search_opts=VOLUME_BOOTABLE_SEARCH_OPTS),
 3060         ])
 3061         self.mock_volume_snapshot_list.assert_called_once_with(
 3062             helpers.IsHttpRequest(),
 3063             search_opts=SNAPSHOT_SEARCH_OPTS)
 3064 
 3065         self._check_glance_image_list_detailed(count=8)
 3066         self._check_neutron_network_and_port_list()
 3067 
 3068         self.mock_tenant_quota_usages.assert_called_once_with(
 3069             helpers.IsHttpRequest(),
 3070             targets=('instances', 'cores', 'ram', 'volumes', 'gigabytes'))
 3071         self.assert_mock_multiple_calls_with_same_arguments(
 3072             self.mock_flavor_list, 2,
 3073             mock.call(helpers.IsHttpRequest()))
 3074         self.mock_keypair_list.assert_called_once_with(helpers.IsHttpRequest())
 3075         self.mock_security_group_list.assert_called_once_with(
 3076             helpers.IsHttpRequest())
 3077         self.mock_availability_zone_list.assert_called_once_with(
 3078             helpers.IsHttpRequest())
 3079         self.mock_server_group_list.assert_called_once_with(
 3080             helpers.IsHttpRequest())
 3081 
 3082     @helpers.create_mocks({api.glance: ('image_list_detailed',),
 3083                            api.neutron: ('network_list',
 3084                                          'port_create',
 3085                                          'port_delete',
 3086                                          'port_list_with_trunk_types',
 3087                                          'security_group_list',),
 3088                            api.nova: ('is_feature_available',
 3089                                       'flavor_list',
 3090                                       'keypair_list',
 3091                                       'availability_zone_list',
 3092                                       'server_group_list',
 3093                                       'server_create',),
 3094                            cinder: ('volume_list',
 3095                                     'volume_snapshot_list',),
 3096                            quotas: ('tenant_quota_usages',)})
 3097     def test_launch_form_keystone_exception(self):
 3098         flavor = self.flavors.first()
 3099         image = self.versioned_images.first()
 3100         keypair = self.keypairs.first()
 3101         server = self.servers.first()
 3102         sec_group = self.security_groups.first()
 3103         avail_zone = self.availability_zones.first()
 3104         customization_script = 'user data'
 3105         nics = [{"net-id": self.networks.first().id, "v4-fixed-ip": ''}]
 3106         quota_usages = self.quota_usages.first()
 3107 
 3108         volumes = [v for v in self.cinder_volumes.list()
 3109                    if (v.status == AVAILABLE and v.bootable == 'true')]
 3110         self.mock_volume_list.return_value = volumes
 3111         volumes = [v for v in self.cinder_volumes.list()
 3112                    if (v.status == AVAILABLE)]
 3113         self.mock_volume_snapshot_list.return_value = volumes
 3114         self.mock_flavor_list.return_value = self.flavors.list()
 3115         self.mock_keypair_list.return_value = self.keypairs.list()
 3116         self.mock_security_group_list.return_value = \
 3117             self.security_groups.list()
 3118         self.mock_availability_zone_list.return_value = \
 3119             self.availability_zones.list()
 3120         self._mock_glance_image_list_detailed(self.versioned_images.list())
 3121         self._mock_neutron_network_and_port_list()
 3122         self.mock_server_create.side_effect = self.exceptions.keystone
 3123         self.mock_tenant_quota_usages.return_value = quota_usages
 3124         self.mock_flavor_list.return_value = self.flavors.list()
 3125 
 3126         form_data = {'flavor': flavor.id,
 3127                      'source_type': 'image_id',
 3128                      'source_id': image.id,
 3129                      'volume_size': '1',
 3130                      'image_id': image.id,
 3131                      'availability_zone': avail_zone.zoneName,
 3132                      'keypair': keypair.name,
 3133                      'name': server.name,
 3134                      'script_source': 'raw',
 3135                      'script_data': customization_script,
 3136                      'project_id': self.tenants.first().id,
 3137                      'user_id': self.user.id,
 3138                      'groups': str(sec_group.id),
 3139                      'volume_type': '',
 3140                      'network': self.networks.first().id,
 3141                      'count': 1,
 3142                      'admin_pass': 'password',
 3143                      'confirm_admin_pass': 'password',
 3144                      'disk_config': 'AUTO',
 3145                      'config_drive': False}
 3146         url = reverse('horizon:project:instances:launch')
 3147         res = self.client.post(url, form_data)
 3148 
 3149         self.assertRedirectsNoFollow(res, INDEX_URL)
 3150 
 3151         self.mock_volume_list.assert_has_calls([
 3152             mock.call(helpers.IsHttpRequest(),
 3153                       search_opts=VOLUME_SEARCH_OPTS),
 3154             mock.call(helpers.IsHttpRequest(),
 3155                       search_opts=VOLUME_BOOTABLE_SEARCH_OPTS),
 3156         ])
 3157         self.mock_volume_snapshot_list.assert_called_once_with(
 3158             helpers.IsHttpRequest(),
 3159             search_opts=SNAPSHOT_SEARCH_OPTS)
 3160         self.assert_mock_multiple_calls_with_same_arguments(
 3161             self.mock_flavor_list, 2,
 3162             mock.call(helpers.IsHttpRequest()))
 3163         self.mock_keypair_list.assert_called_once_with(helpers.IsHttpRequest())
 3164         self.mock_security_group_list.assert_called_once_with(
 3165             helpers.IsHttpRequest())
 3166         self.mock_availability_zone_list.assert_called_once_with(
 3167             helpers.IsHttpRequest())
 3168 
 3169         self._check_glance_image_list_detailed(count=8)
 3170         self._check_neutron_network_and_port_list()
 3171 
 3172         self.mock_server_create.assert_called_once_with(
 3173             helpers.IsHttpRequest(),
 3174             server.name,
 3175             image.id,
 3176             flavor.id,
 3177             keypair.name,
 3178             customization_script,
 3179             [str(sec_group.id)],
 3180             block_device_mapping=None,
 3181             block_device_mapping_v2=None,
 3182             nics=nics,
 3183             availability_zone=avail_zone.zoneName,
 3184             instance_count=helpers.IsA(int),
 3185             admin_pass='password',
 3186             disk_config='AUTO',
 3187             config_drive=False,
 3188             scheduler_hints={})
 3189         self.mock_tenant_quota_usages.assert_called_once_with(
 3190             helpers.IsHttpRequest(),
 3191             targets=('instances', 'cores', 'ram', 'volumes', ))
 3192 
 3193     @helpers.create_mocks({api.glance: ('image_list_detailed',),
 3194                            api.neutron: ('network_list',
 3195                                          'port_list_with_trunk_types',
 3196                                          'security_group_list',),
 3197                            api.nova: ('is_feature_available',
 3198                                       'flavor_list',
 3199                                       'keypair_list',
 3200                                       'availability_zone_list',
 3201                                       'server_group_list'),
 3202                            cinder: ('volume_list',
 3203                                     'volume_snapshot_list',),
 3204                            quotas: ('tenant_quota_usages',)})
 3205     def test_launch_form_instance_count_error(self):
 3206         flavor = self.flavors.first()
 3207         image = self.versioned_images.first()
 3208         keypair = self.keypairs.first()
 3209         server = self.servers.first()
 3210         volume = self.cinder_volumes.first()
 3211         sec_group = self.security_groups.first()
 3212         avail_zone = self.availability_zones.first()
 3213         customization_script = 'user data'
 3214         device_name = 'vda'
 3215         volume_choice = "%s:vol" % volume.id
 3216         quota_usages = self.quota_usages.first()
 3217 
 3218         self._mock_nova_glance_neutron_lists()
 3219 
 3220         volumes = [v for v in self.cinder_volumes.list()
 3221                    if (v.status == AVAILABLE and v.bootable == 'true')]
 3222         self.mock_volume_list.return_value = volumes
 3223         self.mock_volume_snapshot_list.return_value = []
 3224         self.mock_flavor_list.return_value = self.flavors.list()
 3225         self.mock_tenant_quota_usages.return_value = quota_usages
 3226 
 3227         form_data = {'flavor': flavor.id,
 3228                      'source_type': 'image_id',
 3229                      'image_id': image.id,
 3230                      'availability_zone': avail_zone.zoneName,
 3231                      'keypair': keypair.name,
 3232                      'name': server.name,
 3233                      'script_source': 'raw',
 3234                      'script_data': customization_script,
 3235                      'project_id': self.tenants.first().id,
 3236                      'user_id': self.user.id,
 3237                      'groups': str(sec_group.id),
 3238                      'volume_type': 'volume_id',
 3239                      'volume_id': volume_choice,
 3240                      'device_name': device_name,
 3241                      'count': 0}
 3242         url = reverse('horizon:project:instances:launch')
 3243         res = self.client.post(url, form_data)
 3244 
 3245         self.assertContains(res, "greater than or equal to 1")
 3246 
 3247         self._check_nova_glance_neutron_lists(flavor_count=3,
 3248                                               image_count=10)
 3249         self.mock_volume_list.assert_has_calls([
 3250             mock.call(helpers.IsHttpRequest(),
 3251                       search_opts=VOLUME_SEARCH_OPTS),
 3252             mock.call(helpers.IsHttpRequest(),
 3253                       search_opts=VOLUME_BOOTABLE_SEARCH_OPTS),
 3254         ])
 3255         self.mock_volume_snapshot_list.assert_called_once_with(
 3256             helpers.IsHttpRequest(),
 3257             search_opts=SNAPSHOT_SEARCH_OPTS)
 3258 
 3259         self.assert_mock_multiple_calls_with_same_arguments(
 3260             self.mock_flavor_list, 3,
 3261             mock.call(helpers.IsHttpRequest()))
 3262         self.mock_tenant_quota_usages.assert_has_calls([
 3263             mock.call(
 3264                 helpers.IsHttpRequest(),
 3265                 targets=('instances', 'cores', 'ram', 'volumes', )),
 3266             mock.call(
 3267                 helpers.IsHttpRequest(),
 3268                 targets=('instances', 'cores', 'ram', 'volumes', 'gigabytes')),
 3269         ])
 3270         self.assertEqual(2, self.mock_tenant_quota_usages.call_count)
 3271 
 3272     @helpers.create_mocks({api.glance: ('image_list_detailed',),
 3273                            api.neutron: ('network_list',
 3274                                          'port_list_with_trunk_types',
 3275                                          'security_group_list',),
 3276                            api.nova: ('is_feature_available',
 3277                                       'flavor_list',
 3278                                       'keypair_list',
 3279                                       'server_group_list',
 3280                                       'availability_zone_list',),
 3281                            cinder: ('volume_list',
 3282                                     'volume_snapshot_list',),
 3283                            quotas: ('tenant_quota_usages',)})
 3284     def _test_launch_form_count_error(self, resource, avail):
 3285         flavor = self.flavors.first()
 3286         image = self.versioned_images.first()
 3287         keypair = self.keypairs.first()
 3288         server = self.servers.first()
 3289         volume = self.cinder_volumes.first()
 3290         sec_group = self.security_groups.first()
 3291         avail_zone = self.availability_zones.first()
 3292         customization_script = 'user data'
 3293         device_name = 'vda'
 3294         volume_choice = "%s:vol" % volume.id
 3295         quota_usages = self.quota_usages.first()
 3296         if resource == 'both':
 3297             quota_usages['cores']['available'] = avail
 3298             quota_usages['ram']['available'] = 512
 3299         else:
 3300             quota_usages[resource]['available'] = avail
 3301 
 3302         self._mock_nova_glance_neutron_lists()
 3303         volumes = [v for v in self.cinder_volumes.list()
 3304                    if (v.status == AVAILABLE and v.bootable == 'true')]
 3305         self.mock_volume_list.return_value = volumes
 3306         self.mock_volume_snapshot_list.return_value = []
 3307         self.mock_flavor_list.return_value = self.flavors.list()
 3308         self.mock_tenant_quota_usages.return_value = quota_usages
 3309 
 3310         form_data = {'flavor': flavor.id,
 3311                      'source_type': 'image_id',
 3312                      'image_id': image.id,
 3313                      'availability_zone': avail_zone.zoneName,
 3314                      'keypair': keypair.name,
 3315                      'name': server.name,
 3316                      'script_source': 'raw',
 3317                      'script_data': customization_script,
 3318                      'project_id': self.tenants.first().id,
 3319                      'user_id': self.user.id,
 3320                      'groups': str(sec_group.id),
 3321                      'volume_type': 'volume_id',
 3322                      'volume_id': volume_choice,
 3323                      'device_name': device_name,
 3324                      'count': 2}
 3325         url = reverse('horizon:project:instances:launch')
 3326         res = self.client.post(url, form_data)
 3327 
 3328         if resource == 'ram':
 3329             msg = ("The following requested resource(s) exceed quota(s): "
 3330                    "RAM(Available: %s" % avail)
 3331         if resource == 'cores':
 3332             msg = ("The following requested resource(s) exceed quota(s): "
 3333                    "Cores(Available: %s" % avail)
 3334         if resource == 'both':
 3335             msg = ("The following requested resource(s) exceed quota(s): "
 3336                    "Cores(Available: %(avail)s, Requested: 2), RAM(Available: "
 3337                    "512, Requested: 1024)" % {'avail': avail})
 3338         self.assertContains(res, msg)
 3339 
 3340         self._check_nova_glance_neutron_lists(flavor_count=3,
 3341                                               image_count=10)
 3342         self.mock_volume_list.assert_has_calls([
 3343             mock.call(helpers.IsHttpRequest(),
 3344                       search_opts=VOLUME_SEARCH_OPTS),
 3345             mock.call(helpers.IsHttpRequest(),
 3346                       search_opts=VOLUME_BOOTABLE_SEARCH_OPTS),
 3347         ])
 3348         self.mock_volume_snapshot_list.assert_called_once_with(
 3349             helpers.IsHttpRequest(),
 3350             search_opts=SNAPSHOT_SEARCH_OPTS)
 3351 
 3352         self.assert_mock_multiple_calls_with_same_arguments(
 3353             self.mock_flavor_list, 3,
 3354             mock.call(helpers.IsHttpRequest()))
 3355         self.mock_tenant_quota_usages.assert_has_calls([
 3356             mock.call(
 3357                 helpers.IsHttpRequest(),
 3358                 targets=('instances', 'cores', 'ram', 'volumes', )),
 3359             mock.call(
 3360                 helpers.IsHttpRequest(),
 3361                 targets=('instances', 'cores', 'ram', 'volumes', 'gigabytes')),
 3362         ])
 3363         self.assertEqual(2, self.mock_tenant_quota_usages.call_count)
 3364 
 3365     def test_launch_form_cores_count_error_glance_v2(self):
 3366         self._test_launch_form_count_error('cores', 1)
 3367 
 3368     def test_launch_form_ram_count_error(self):
 3369         self._test_launch_form_count_error('ram', 512)
 3370 
 3371     def test_launch_form_ram_cores_count_error(self):
 3372         self._test_launch_form_count_error('both', 1)
 3373 
 3374     @helpers.create_mocks({api.glance: ('image_list_detailed',),
 3375                            api.neutron: ('network_list',
 3376                                          'port_list_with_trunk_types',
 3377                                          'security_group_list',),
 3378                            api.nova: ('is_feature_available',
 3379                                       'flavor_list',
 3380                                       'keypair_list',
 3381                                       'server_group_list',
 3382                                       'availability_zone_list',),
 3383                            cinder: ('volume_list',
 3384                                     'volume_snapshot_list',),
 3385                            quotas: ('tenant_quota_usages',)})
 3386     def _launch_form_instance(self, image, flavor, keypair=None):
 3387         server = self.servers.first()
 3388         volume = self.cinder_volumes.first()
 3389         sec_group = self.security_groups.first()
 3390         avail_zone = self.availability_zones.first()
 3391         customization_script = 'user data'
 3392         device_name = 'vda'
 3393         volume_choice = "%s:vol" % volume.id
 3394         quota_usages = self.quota_usages.first()
 3395 
 3396         self._mock_nova_glance_neutron_lists()
 3397         volumes = [v for v in self.cinder_volumes.list()
 3398                    if (v.status == AVAILABLE and v.bootable == 'true')]
 3399         self.mock_volume_list.return_value = volumes
 3400         self.mock_volume_snapshot_list.return_value = []
 3401         self.mock_flavor_list.return_value = self.flavors.list()
 3402         self.mock_tenant_quota_usages.return_value = quota_usages
 3403 
 3404         form_data = {'flavor': flavor.id,
 3405                      'source_type': 'image_id',
 3406                      'image_id': image.id,
 3407                      'availability_zone': avail_zone.zoneName,
 3408                      'name': server.name,
 3409                      'script_source': 'raw',
 3410                      'script_data': customization_script,
 3411                      'project_id': self.tenants.first().id,
 3412                      'user_id': self.user.id,
 3413                      'groups': str(sec_group.id),
 3414                      'volume_type': 'volume_id',
 3415                      'volume_id': volume_choice,
 3416                      'device_name': device_name,
 3417                      'count': 1}
 3418         if keypair:
 3419             form_data['keypair'] = keypair.name
 3420 
 3421         url = reverse('horizon:project:instances:launch')
 3422         res = self.client.post(url, form_data)
 3423 
 3424         self._check_nova_glance_neutron_lists(flavor_count=3,
 3425                                               image_count=10)
 3426         self.mock_volume_list.assert_has_calls([
 3427             mock.call(helpers.IsHttpRequest(),
 3428                       search_opts=VOLUME_SEARCH_OPTS),
 3429             mock.call(helpers.IsHttpRequest(),
 3430                       search_opts=VOLUME_BOOTABLE_SEARCH_OPTS),
 3431         ])
 3432         self.mock_volume_snapshot_list.assert_called_once_with(
 3433             helpers.IsHttpRequest(),
 3434             search_opts=SNAPSHOT_SEARCH_OPTS)
 3435         self.assert_mock_multiple_calls_with_same_arguments(
 3436             self.mock_flavor_list, 3,
 3437             mock.call(helpers.IsHttpRequest()))
 3438         self.mock_tenant_quota_usages.assert_has_calls([
 3439             mock.call(
 3440                 helpers.IsHttpRequest(),
 3441                 targets=('instances', 'cores', 'ram', 'volumes', )),
 3442             mock.call(
 3443                 helpers.IsHttpRequest(),
 3444                 targets=('instances', 'cores', 'ram', 'volumes', 'gigabytes')),
 3445         ])
 3446         self.assertEqual(2, self.mock_tenant_quota_usages.call_count)
 3447 
 3448         return res
 3449 
 3450     def test_launch_form_instance_requirement_error_disk(self):
 3451         flavor = self.flavors.get(id="bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb")
 3452         image = self.versioned_images.first()
 3453         image.min_ram = flavor.ram
 3454         image.min_disk = flavor.disk + 1
 3455         keypair = self.keypairs.first()
 3456         res = self._launch_form_instance(image, flavor, keypair)
 3457         msg = (f"The flavor &#39;{flavor.name}&#39; is too small for requested "
 3458                f"image. Minimum requirements: {image.min_ram} MB of RAM and "
 3459                f"{image.min_disk} GB of Root Disk.")
 3460         self.assertContains(res, msg, html=True)
 3461 
 3462     def test_launch_form_instance_requirement_error_ram(self):
 3463         flavor = self.flavors.first()
 3464         image = self.versioned_images.first()
 3465         image.min_ram = flavor.ram + 1
 3466         image.min_disk = flavor.disk
 3467         keypair = self.keypairs.first()
 3468         res = self._launch_form_instance(image, flavor, keypair)
 3469         msg = (f"The flavor &#39;{flavor.name}&#39; is too small for requested "
 3470                f"image. Minimum requirements: {image.min_ram} MB of RAM and "
 3471                f"{image.min_disk} GB of Root Disk.")
 3472         self.assertContains(res, msg, html=True)
 3473 
 3474     def test_launch_form_instance_zero_value_flavor_with_min_req(self):
 3475         flavor = self.flavors.first()
 3476         image = self.versioned_images.first()
 3477         image.min_ram = flavor.ram
 3478         image.min_disk = flavor.disk + 1
 3479         keypair = self.keypairs.first()
 3480         res = self._launch_form_instance(image, flavor, keypair)
 3481         msg = (f"The flavor &39;{flavor.name}&39; is too small for requested "
 3482                f"image. Minimum requirements: {image.min_ram} MB of RAM and "
 3483                f"{image.min_disk} GB of Root Disk.")
 3484         self.assertNotContains(res, msg, html=True)
 3485 
 3486     @helpers.create_mocks({api.glance: ('image_list_detailed',),
 3487                            api.neutron: ('network_list',
 3488                                          'port_list_with_trunk_types',
 3489                                          'security_group_list',),
 3490                            api.nova: ('is_feature_available',
 3491                                       'flavor_list',
 3492                                       'keypair_list',
 3493                                       'server_group_list',
 3494                                       'availability_zone_list',),
 3495                            cinder: ('volume_list',
 3496                                     'volume_snapshot_list',),
 3497                            quotas: ('tenant_quota_usages',)})
 3498     def _test_launch_form_instance_show_device_name(self, device_name,
 3499                                                     widget_class,
 3500                                                     widget_attrs):
 3501         flavor = self.flavors.first()
 3502         image = self.versioned_images.first()
 3503         keypair = self.keypairs.first()
 3504         server = self.servers.first()
 3505         volume = self.cinder_volumes.first()
 3506         sec_group = self.security_groups.first()
 3507         avail_zone = self.availability_zones.first()
 3508         customization_script = 'user data'
 3509         volume_choice = "%s:vol" % volume.id
 3510         quota_usages = self.quota_usages.first()
 3511 
 3512         self.mock_flavor_list.return_value = self.flavors.list()
 3513         self.mock_keypair_list.return_value = self.keypairs.list()
 3514         self.mock_security_group_list.return_value = \
 3515             self.security_groups.list()
 3516         self.mock_availability_zone_list.return_value = \
 3517             self.availability_zones.list()
 3518         self.mock_server_group_list.return_value = self.server_groups.list()
 3519         self.mock_image_list_detailed.side_effect = [
 3520             [self.versioned_images.list(), False, False],
 3521             [[], False, False],
 3522         ]
 3523         self.mock_network_list.side_effect = [
 3524             self.networks.list()[:1],
 3525             self.networks.list()[1:],
 3526             self.networks.list()[:1],
 3527             self.networks.list()[1:],
 3528         ]
 3529         self.mock_port_list_with_trunk_types.return_value = self.ports.list()
 3530         volumes = [v for v in self.cinder_volumes.list()
 3531                    if (v.status == AVAILABLE and v.bootable == 'true')]
 3532         self.mock_volume_list.return_value = volumes
 3533         self.mock_volume_snapshot_list.return_value = []
 3534         self.mock_flavor_list.return_value = self.flavors.list()
 3535         self.mock_tenant_quota_usages.return_value = quota_usages
 3536 
 3537         form_data = {'flavor': flavor.id,
 3538                      'source_type': 'volume_image_id',
 3539                      'image_id': image.id,
 3540                      'availability_zone': avail_zone.zoneName,
 3541                      'keypair': keypair.name,
 3542                      'name': server.name,
 3543                      'customization_script': customization_script,
 3544                      'project_id': self.tenants.first().id,
 3545                      'user_id': self.user.id,
 3546                      'groups': str(sec_group.id),
 3547                      'volume_type': 'volume_id',
 3548                      'volume_id': volume_choice,
 3549                      'volume_size': max(
 3550                          image.min_disk, image.size // 1024 ** 3),
 3551                      'device_name': device_name,
 3552                      'count': 1}
 3553 
 3554         url = reverse('horizon:project:instances:launch')
 3555         res = self.client.post(url, form_data)
 3556         self.assertNoFormErrors(res)
 3557         widget_content = widget_class().render(**widget_attrs)
 3558         # In django 1.4, the widget's html attributes are not always rendered
 3559         # in the same order and checking the fully rendered widget fails.
 3560         for widget_part in widget_content.split():
 3561             self.assertContains(res, widget_part)
 3562 
 3563         self.assert_mock_multiple_calls_with_same_arguments(
 3564             self.mock_flavor_list, 3,
 3565             mock.call(helpers.IsHttpRequest()))
 3566         self.mock_keypair_list.assert_called_once_with(helpers.IsHttpRequest())
 3567         self.mock_security_group_list.assert_called_once_with(
 3568             helpers.IsHttpRequest())
 3569         self.mock_availability_zone_list.assert_called_once_with(
 3570             helpers.IsHttpRequest())
 3571         self.mock_server_group_list.assert_called_once_with(
 3572             helpers.IsHttpRequest())
 3573         self.assertEqual(10, self.mock_image_list_detailed.call_count)
 3574         self.mock_image_list_detailed.assert_has_calls(
 3575             [
 3576                 mock.call(helpers.IsHttpRequest(),
 3577                           filters={'is_public': True,
 3578                                    'status': 'active'}),
 3579                 mock.call(helpers.IsHttpRequest(),
 3580                           filters={'property-owner_id': self.tenant.id,
 3581                                    'status': 'active'})
 3582             ] +
 3583             [
 3584                 mock.call(helpers.IsHttpRequest(),
 3585                           filters={'status': 'active',
 3586                                    'visibility': 'community'}),
 3587                 mock.call(helpers.IsHttpRequest(),
 3588                           filters={'status': 'active',
 3589                                    'visibility': 'shared'})
 3590             ] * 3
 3591         )
 3592         self.assertEqual(4, self.mock_network_list.call_count)
 3593         self.mock_network_list.assert_has_calls([
 3594             mock.call(
 3595                 helpers.IsHttpRequest(),
 3596                 tenant_id=self.tenant.id,
 3597                 shared=False),
 3598             mock.call(
 3599                 helpers.IsHttpRequest(),
 3600                 shared=True),
 3601             mock.call(
 3602                 helpers.IsHttpRequest(),
 3603                 tenant_id=self.tenant.id,
 3604                 shared=False),
 3605             mock.call(
 3606                 helpers.IsHttpRequest(),
 3607                 shared=True),
 3608         ])
 3609         self.assertEqual(len(self.networks.list()),
 3610                          self.mock_port_list_with_trunk_types.call_count)
 3611         self.mock_port_list_with_trunk_types.assert_has_calls(
 3612             [mock.call(helpers.IsHttpRequest(),
 3613                        network_id=net.id,
 3614                        tenant_id=self.tenant.id)
 3615              for net in self.networks.list()])
 3616         self.mock_volume_list.assert_has_calls([
 3617             mock.call(helpers.IsHttpRequest(),
 3618                       search_opts=VOLUME_SEARCH_OPTS),
 3619             mock.call(helpers.IsHttpRequest(),
 3620                       search_opts=VOLUME_BOOTABLE_SEARCH_OPTS),
 3621         ])
 3622         self.mock_volume_snapshot_list.assert_called_once_with(
 3623             helpers.IsHttpRequest(),
 3624             search_opts=SNAPSHOT_SEARCH_OPTS)
 3625         self.assert_mock_multiple_calls_with_same_arguments(
 3626             self.mock_flavor_list, 3,
 3627             mock.call(helpers.IsHttpRequest()))
 3628         self.mock_tenant_quota_usages.assert_has_calls([
 3629             mock.call(
 3630                 helpers.IsHttpRequest(),
 3631                 targets=('instances', 'cores', 'ram', 'volumes', )),
 3632             mock.call(
 3633                 helpers.IsHttpRequest(),
 3634                 targets=('instances', 'cores', 'ram', 'volumes', 'gigabytes')),
 3635         ])
 3636         self.assertEqual(2, self.mock_tenant_quota_usages.call_count)
 3637 
 3638     @helpers.update_settings(
 3639         OPENSTACK_HYPERVISOR_FEATURES={'can_set_mount_point': True},)
 3640     def test_launch_form_instance_device_name_showed(self):
 3641         self._test_launch_form_instance_show_device_name(
 3642             'vda', widgets.TextInput, {
 3643                 'name': 'device_name', 'value': 'vda',
 3644                 'attrs': {'id': 'id_device_name'}}
 3645         )
 3646 
 3647     @helpers.update_settings(
 3648         OPENSTACK_HYPERVISOR_FEATURES={'can_set_mount_point': False})
 3649     def test_launch_form_instance_device_name_hidden(self):
 3650         self._test_launch_form_instance_show_device_name(
 3651             '', widgets.HiddenInput, {
 3652                 'name': 'device_name', 'value': '',
 3653                 'attrs': {'id': 'id_device_name'}}
 3654         )
 3655 
 3656     @helpers.create_mocks({api.glance: ('image_list_detailed',),
 3657                            api.neutron: ('network_list',
 3658                                          'port_list_with_trunk_types',
 3659                                          'security_group_list',),
 3660                            api.nova: ('is_feature_available',
 3661                                       'flavor_list',
 3662                                       'keypair_list',
 3663                                       'server_group_list',
 3664                                       'availability_zone_list',),
 3665                            cinder: ('volume_list',
 3666                                     'volume_snapshot_list',),
 3667                            quotas: ('tenant_quota_usages',)})
 3668     def _test_launch_form_instance_volume_size(self, image, volume_size, msg,
 3669                                                avail_volumes=None):
 3670         flavor = self.flavors.get(name='m1.massive')
 3671         keypair = self.keypairs.first()
 3672         server = self.servers.first()
 3673         sec_group = self.security_groups.first()
 3674         avail_zone = self.availability_zones.first()
 3675         customization_script = 'user data'
 3676         device_name = 'vda'
 3677         quota_usages = self.quota_usages.first()
 3678         quota_usages['cores']['available'] = 2000
 3679         if avail_volumes is not None:
 3680             quota_usages['volumes']['available'] = avail_volumes
 3681 
 3682         self.mock_flavor_list.return_value = self.flavors.list()
 3683         self.mock_keypair_list.return_value = self.keypairs.list()
 3684         self.mock_security_group_list.return_value = \
 3685             self.security_groups.list()
 3686         self.mock_availability_zone_list.return_value = \
 3687             self.availability_zones.list()
 3688         self._mock_glance_image_list_detailed(self.versioned_images.list())
 3689         self._mock_neutron_network_and_port_list()
 3690         self.mock_server_group_list.return_value = self.server_groups.list()
 3691         volumes = [v for v in self.cinder_volumes.list()
 3692                    if (v.status == AVAILABLE and v.bootable == 'true')]
 3693         self.mock_volume_list.return_value = volumes
 3694         self.mock_volume_snapshot_list.return_value = []
 3695         self.mock_tenant_quota_usages.return_value = quota_usages
 3696 
 3697         form_data = {
 3698             'flavor': flavor.id,
 3699             'source_type': 'volume_image_id',
 3700             'image_id': image.id,
 3701             'availability_zone': avail_zone.zoneName,
 3702             'keypair': keypair.name,
 3703             'name': server.name,
 3704             'script_source': 'raw',
 3705             'script_data': customization_script,
 3706             'project_id': self.tenants.first().id,
 3707             'user_id': self.user.id,
 3708             'groups': str(sec_group.id),
 3709             'volume_size': volume_size,
 3710             'device_name': device_name,
 3711             'count': 1
 3712         }
 3713         url = reverse('horizon:project:instances:launch')
 3714 
 3715         res = self.client.post(url, form_data)
 3716         self.assertContains(res, msg, html=True)
 3717 
 3718         self.mock_keypair_list.assert_called_once_with(helpers.IsHttpRequest())
 3719         self.mock_security_group_list.assert_called_once_with(
 3720             helpers.IsHttpRequest())
 3721         self.mock_availability_zone_list.assert_called_once_with(
 3722             helpers.IsHttpRequest())
 3723         if avail_volumes is None:
 3724             image_list_count = 10
 3725         else:
 3726             image_list_count = 8
 3727         self._check_glance_image_list_detailed(count=image_list_count)
 3728         self._check_neutron_network_and_port_list()
 3729         self.mock_server_group_list.assert_called_once_with(
 3730             helpers.IsHttpRequest())
 3731         self.mock_volume_list.assert_has_calls([
 3732             mock.call(helpers.IsHttpRequest(),
 3733                       search_opts=VOLUME_SEARCH_OPTS),
 3734             mock.call(helpers.IsHttpRequest(),
 3735                       search_opts=VOLUME_BOOTABLE_SEARCH_OPTS),
 3736         ])
 3737         self.mock_volume_snapshot_list.assert_called_once_with(
 3738             helpers.IsHttpRequest(),
 3739             search_opts=SNAPSHOT_SEARCH_OPTS)
 3740         if avail_volumes is None:
 3741             flavor_list_count = 3
 3742         else:
 3743             flavor_list_count = 2
 3744         self.assert_mock_multiple_calls_with_same_arguments(
 3745             self.mock_flavor_list, flavor_list_count,
 3746             mock.call(helpers.IsHttpRequest()))
 3747         self.mock_tenant_quota_usages.assert_has_calls([
 3748             mock.call(
 3749                 helpers.IsHttpRequest(),
 3750                 targets=('instances', 'cores', 'ram', 'volumes', )),
 3751             mock.call(
 3752                 helpers.IsHttpRequest(),
 3753                 targets=('instances', 'cores', 'ram', 'volumes', 'gigabytes')),
 3754         ])
 3755         self.assertEqual(2, self.mock_tenant_quota_usages.call_count)
 3756 
 3757     def test_launch_form_instance_volume_size_error(self):
 3758         image = self.versioned_images.get(name='protected_images')
 3759         volume_size = image.min_disk // 2
 3760         msg = ("The Volume size is too small for the &#39;%s&#39; image "
 3761                "and has to be greater than or equal to &#39;%s&#39; GB." %
 3762                (image.name, image.min_disk))
 3763         self._test_launch_form_instance_volume_size(image, volume_size, msg)
 3764 
 3765     def test_launch_form_instance_non_int_volume_size(self):
 3766         image = self.versioned_images.get(name='protected_images')
 3767         msg = "Enter a whole number."
 3768         self._test_launch_form_instance_volume_size(image, 1.5, msg)
 3769 
 3770     def test_launch_form_instance_volume_exceed_quota(self):
 3771         image = self.versioned_images.get(name='protected_images')
 3772         msg = ("The requested instance cannot be launched. "
 3773                "Requested volume exceeds quota: Available: 0, Requested: 1.")
 3774         self._test_launch_form_instance_volume_size(image, image.min_disk,
 3775                                                     msg, 0)
 3776 
 3777     @helpers.create_mocks({
 3778         api.nova: ('flavor_list',
 3779                    'server_list_paged',
 3780                    'tenant_absolute_limits',
 3781                    'is_feature_available',),
 3782         api.glance: ('image_list_detailed',),
 3783         api.neutron: ('floating_ip_simple_associate_supported',
 3784                       'floating_ip_supported',),
 3785         api.network: ('servers_update_addresses',),
 3786         api.cinder: ('volume_list',),
 3787     })
 3788     def test_launch_button_attributes(self):
 3789         servers = self.servers.list()
 3790         limits = self.limits['absolute']
 3791 
 3792         self.mock_is_feature_available.return_value = True
 3793         self.mock_flavor_list.return_value = self.flavors.list()
 3794         self.mock_image_list_detailed.return_value = (self.images.list(),
 3795                                                       False, False)
 3796         self.mock_server_list_paged.return_value = [servers, False, False]
 3797         self.mock_servers_update_addresses.return_value = None
 3798         self.mock_tenant_absolute_limits.return_value = limits
 3799         self.mock_floating_ip_supported.return_value = True
 3800         self.mock_floating_ip_simple_associate_supported.return_value = True
 3801 
 3802         tables.LaunchLink()
 3803         res = self.client.get(INDEX_URL)
 3804 
 3805         launch_action = self.getAndAssertTableAction(res, 'instances',
 3806                                                      'launch-ng')
 3807 
 3808         self.assertEqual(set(['btn-launch']),
 3809                          set(launch_action.classes))
 3810         self.assertEqual('Launch Instance', launch_action.verbose_name)
 3811         self.assertEqual((('compute', 'os_compute_api:servers:create'),),
 3812                          launch_action.policy_rules)
 3813 
 3814         self.assert_mock_multiple_calls_with_same_arguments(
 3815             self.mock_is_feature_available, 10,
 3816             mock.call(helpers.IsHttpRequest(), 'locked_attribute'))
 3817         self.mock_flavor_list.assert_called_once_with(helpers.IsHttpRequest())
 3818         self._assert_mock_image_list_detailed_calls()
 3819 
 3820         search_opts = {'marker': None, 'paginate': True}
 3821         self.mock_server_list_paged.assert_called_once_with(
 3822             helpers.IsHttpRequest(),
 3823             sort_dir='desc',
 3824             search_opts=search_opts)
 3825         self.mock_servers_update_addresses.assert_called_once_with(
 3826             helpers.IsHttpRequest(), servers)
 3827         self.assert_mock_multiple_calls_with_same_arguments(
 3828             self.mock_tenant_absolute_limits, 3,
 3829             mock.call(helpers.IsHttpRequest(), reserved=True))
 3830         self.assert_mock_multiple_calls_with_same_arguments(
 3831             self.mock_floating_ip_supported, 10,
 3832             mock.call(helpers.IsHttpRequest()))
 3833         self.assert_mock_multiple_calls_with_same_arguments(
 3834             self.mock_floating_ip_simple_associate_supported, 5,
 3835             mock.call(helpers.IsHttpRequest()))
 3836 
 3837     @helpers.create_mocks({
 3838         api.nova: ('flavor_list',
 3839                    'server_list_paged',
 3840                    'tenant_absolute_limits',
 3841                    'is_feature_available',),
 3842         api.glance: ('image_list_detailed',),
 3843         api.neutron: ('floating_ip_simple_associate_supported',
 3844                       'floating_ip_supported',),
 3845         api.network: ('servers_update_addresses',),
 3846         api.cinder: ('volume_list',),
 3847     })
 3848     def test_launch_button_disabled_when_quota_exceeded(self):
 3849         servers = self.servers.list()
 3850         limits = self.limits['absolute']
 3851         limits['totalInstancesUsed'] = limits['maxTotalInstances']
 3852 
 3853         self.mock_is_feature_available.return_value = True
 3854         self.mock_flavor_list.return_value = self.flavors.list()
 3855         self.mock_image_list_detailed.return_value = (self.images.list(),
 3856                                                       False, False)
 3857         self.mock_server_list_paged.return_value = [servers, False, False]
 3858         self.mock_servers_update_addresses.return_value = None
 3859         self.mock_tenant_absolute_limits.return_value = limits
 3860         self.mock_floating_ip_supported.return_value = True
 3861         self.mock_floating_ip_simple_associate_supported.return_value = True
 3862 
 3863         tables.LaunchLink()
 3864         res = self.client.get(INDEX_URL)
 3865 
 3866         launch_action = self.getAndAssertTableAction(
 3867             res, 'instances', 'launch-ng')
 3868 
 3869         self.assertIn('disabled', launch_action.classes,
 3870                       'The launch button should be disabled')
 3871         self.assertEqual('Launch Instance (Quota exceeded)',
 3872                          launch_action.verbose_name)
 3873 
 3874         self.assert_mock_multiple_calls_with_same_arguments(
 3875             self.mock_is_feature_available, 10,
 3876             mock.call(helpers.IsHttpRequest(), 'locked_attribute'))
 3877         self.mock_flavor_list.assert_called_once_with(helpers.IsHttpRequest())
 3878         self._assert_mock_image_list_detailed_calls()
 3879 
 3880         search_opts = {'marker': None, 'paginate': True}
 3881         self.mock_server_list_paged.assert_called_once_with(
 3882             helpers.IsHttpRequest(),
 3883             sort_dir='desc',
 3884             search_opts=search_opts)
 3885         self.mock_servers_update_addresses.assert_called_once_with(
 3886             helpers.IsHttpRequest(), servers)
 3887         self.assert_mock_multiple_calls_with_same_arguments(
 3888             self.mock_tenant_absolute_limits, 3,
 3889             mock.call(helpers.IsHttpRequest(), reserved=True))
 3890         self.assert_mock_multiple_calls_with_same_arguments(
 3891             self.mock_floating_ip_supported, 10,
 3892             mock.call(helpers.IsHttpRequest()))
 3893         self.assert_mock_multiple_calls_with_same_arguments(
 3894             self.mock_floating_ip_simple_associate_supported, 5,
 3895             mock.call(helpers.IsHttpRequest()))
 3896 
 3897     @helpers.create_mocks({api.glance: ('image_list_detailed',),
 3898                            api.neutron: ('network_list',
 3899                                          'port_list_with_trunk_types',
 3900                                          'security_group_list',),
 3901                            api.nova: ('is_feature_available',
 3902                                       'flavor_list',
 3903                                       'keypair_list',
 3904                                       'availability_zone_list',
 3905                                       'server_group_list',
 3906                                       'tenant_absolute_limits',
 3907                                       'server_create',),
 3908                            cinder: ('volume_list',
 3909                                     'volume_snapshot_list',),
 3910                            quotas: ('tenant_quota_usages',)})
 3911     def test_launch_with_empty_device_name_allowed(self):
 3912         flavor = self.flavors.get(name='m1.massive')
 3913         image = self.versioned_images.first()
 3914         keypair = self.keypairs.first()
 3915         server = self.servers.first()
 3916         sec_group = self.security_groups.first()
 3917         avail_zone = self.availability_zones.first()
 3918         customization_script = 'user data'
 3919         nics = [{'net-id': self.networks.first().id, 'v4-fixed-ip': ''}]
 3920         device_name = ''
 3921         quota_usages = self.quota_usages.first()
 3922         quota_usages['cores']['available'] = 2000
 3923         device_mapping_v2 = [{'device_name': None,  # device_name must be None
 3924                               'source_type': 'image',
 3925                               'destination_type': 'volume',
 3926                               'delete_on_termination': False,
 3927                               'uuid': image.id,
 3928                               'boot_index': '0',
 3929                               'volume_size': image.size}]
 3930 
 3931         self._mock_nova_glance_neutron_lists()
 3932         volumes = [v for v in self.cinder_volumes.list()
 3933                    if (v.status == AVAILABLE and v.bootable == 'true')]
 3934         self.mock_volume_list.return_value = volumes
 3935         self.mock_volume_snapshot_list.return_value = []
 3936         self.mock_flavor_list.return_value = self.flavors.list()
 3937         self.mock_tenant_quota_usages.return_value = quota_usages
 3938         self.mock_server_create.return_value = None
 3939 
 3940         form_data = {
 3941             'flavor': flavor.id,
 3942             'source_type': 'volume_image_id',
 3943             'image_id': image.id,
 3944             'availability_zone': avail_zone.zoneName,
 3945             'keypair': keypair.name,
 3946             'name': server.name,
 3947             'script_source': 'raw',
 3948             'script_data': customization_script,
 3949             'project_id': self.tenants.first().id,
 3950             'user_id': self.user.id,
 3951             'groups': str(sec_group.id),
 3952             'volume_size': image.size,
 3953             'device_name': device_name,
 3954             'network': self.networks.first().id,
 3955             'count': 1
 3956         }
 3957         url = reverse('horizon:project:instances:launch')
 3958 
 3959         res = self.client.post(url, form_data)
 3960         self.assertNoFormErrors(res)
 3961 
 3962         self._check_nova_glance_neutron_lists(flavor_count=2,
 3963                                               image_count=8)
 3964 
 3965         self.mock_volume_list.assert_has_calls([
 3966             mock.call(helpers.IsHttpRequest(),
 3967                       search_opts=VOLUME_SEARCH_OPTS),
 3968             mock.call(helpers.IsHttpRequest(),
 3969                       search_opts=VOLUME_BOOTABLE_SEARCH_OPTS),
 3970         ])
 3971         self.mock_volume_snapshot_list.assert_called_once_with(
 3972             helpers.IsHttpRequest(),
 3973             search_opts=SNAPSHOT_SEARCH_OPTS)
 3974 
 3975         self.assert_mock_multiple_calls_with_same_arguments(
 3976             self.mock_flavor_list, 2,
 3977             mock.call(helpers.IsHttpRequest()))
 3978         self.mock_tenant_quota_usages.assert_called_once_with(
 3979             helpers.IsHttpRequest(),
 3980             targets=('instances', 'cores', 'ram', 'volumes', ))
 3981         self.mock_server_create.assert_called_once_with(
 3982             helpers.IsHttpRequest(),
 3983             server.name,
 3984             '',
 3985             flavor.id,
 3986             keypair.name,
 3987             customization_script,
 3988             [str(sec_group.id)],
 3989             block_device_mapping=None,
 3990             block_device_mapping_v2=device_mapping_v2,
 3991             nics=nics,
 3992             availability_zone=avail_zone.zoneName,
 3993             instance_count=helpers.IsA(int),
 3994             admin_pass='',
 3995             config_drive=False,
 3996             disk_config='',
 3997             scheduler_hints={})
 3998 
 3999 
 4000 class InstanceTests2(InstanceTestBase, InstanceTableTestMixin):
 4001 
 4002     @helpers.create_mocks({
 4003         api.nova: ('flavor_list',
 4004                    'server_list_paged',
 4005                    'tenant_absolute_limits',
 4006                    'is_feature_available',),
 4007         api.glance: ('image_list_detailed',),
 4008         api.neutron: ('floating_ip_simple_associate_supported',
 4009                       'floating_ip_supported',),
 4010         api.network: ('servers_update_addresses',),
 4011         api.cinder: ('volume_list',),
 4012     })
 4013     def test_index_options_after_migrate(self):
 4014         servers = self.servers.list()
 4015         server = self.servers.first()
 4016         server.status = "VERIFY_RESIZE"
 4017 
 4018         self.mock_is_feature_available.return_value = True
 4019         self.mock_flavor_list.return_value = self.flavors.list()
 4020         self.mock_image_list_detailed.return_value = (self.images.list(),
 4021                                                       False, False)
 4022         self.mock_server_list_paged.return_value = [servers, False, False]
 4023         self.mock_servers_update_addresses.return_value = None
 4024         self.mock_tenant_absolute_limits.return_value = self.limits['absolute']
 4025         self.mock_floating_ip_supported.return_value = True
 4026         self.mock_floating_ip_simple_associate_supported.return_value = True
 4027 
 4028         res = self.client.get(INDEX_URL)
 4029         self.assertContains(res, "instances__confirm")
 4030         self.assertContains(res, "instances__revert")
 4031 
 4032         self.assert_mock_multiple_calls_with_same_arguments(
 4033             self.mock_is_feature_available, 10,
 4034             mock.call(helpers.IsHttpRequest(), 'locked_attribute'))
 4035         self.mock_flavor_list.assert_called_once_with(helpers.IsHttpRequest())
 4036         self._assert_mock_image_list_detailed_calls()
 4037 
 4038         search_opts = {'marker': None, 'paginate': True}
 4039         self.mock_server_list_paged.assert_called_once_with(
 4040             helpers.IsHttpRequest(),
 4041             sort_dir='desc',
 4042             search_opts=search_opts)
 4043         self.mock_servers_update_addresses.assert_called_once_with(
 4044             helpers.IsHttpRequest(), servers)
 4045         self.assert_mock_multiple_calls_with_same_arguments(
 4046             self.mock_tenant_absolute_limits, 2,
 4047             mock.call(helpers.IsHttpRequest(), reserved=True))
 4048         self.assert_mock_multiple_calls_with_same_arguments(
 4049             self.mock_floating_ip_supported, 10,
 4050             mock.call(helpers.IsHttpRequest()))
 4051         self.assert_mock_multiple_calls_with_same_arguments(
 4052             self.mock_floating_ip_simple_associate_supported, 5,
 4053             mock.call(helpers.IsHttpRequest()))
 4054 
 4055     @helpers.create_mocks({api.nova: ('is_feature_available',
 4056                                       'flavor_list',
 4057                                       'keypair_list',
 4058                                       'server_group_list',
 4059                                       'availability_zone_list'),
 4060                            cinder: ('volume_snapshot_list',
 4061                                     'volume_list',),
 4062                            api.neutron: ('network_list',
 4063                                          'port_list_with_trunk_types',
 4064                                          'security_group_list',),
 4065                            api.glance: ('image_list_detailed',),
 4066                            quotas: ('tenant_quota_usages',)})
 4067     def test_select_default_keypair_if_only_one(self):
 4068         keypair = self.keypairs.first()
 4069 
 4070         self.mock_volume_list.return_value = []
 4071         self.mock_volume_snapshot_list.return_value = []
 4072         self._mock_glance_image_list_detailed(self.versioned_images.list())
 4073         self._mock_neutron_network_and_port_list()
 4074         self.mock_tenant_quota_usages.return_value = self.quota_usages.first()
 4075         self._mock_nova_lists()
 4076 
 4077         url = reverse('horizon:project:instances:launch')
 4078         res = self.client.get(url)
 4079         self.assertContains(
 4080             res, "<option selected='selected' value='%(key)s'>"
 4081                  "%(key)s</option>" % {'key': keypair.name},
 4082             html=True,
 4083             msg_prefix="The default key pair was not selected.")
 4084 
 4085         self.mock_volume_list.assert_has_calls([
 4086             mock.call(helpers.IsHttpRequest(),
 4087                       search_opts=VOLUME_SEARCH_OPTS),
 4088             mock.call(helpers.IsHttpRequest(),
 4089                       search_opts=VOLUME_BOOTABLE_SEARCH_OPTS),
 4090         ])
 4091         self.mock_volume_snapshot_list.assert_called_once_with(
 4092             helpers.IsHttpRequest(), search_opts=SNAPSHOT_SEARCH_OPTS)
 4093         self._check_glance_image_list_detailed(count=8)
 4094         self._check_neutron_network_and_port_list()
 4095         self.mock_tenant_quota_usages.assert_called_once_with(
 4096             helpers.IsHttpRequest(),
 4097             targets=('instances', 'cores', 'ram', 'volumes', 'gigabytes'))
 4098         self._check_nova_lists(flavor_count=2)
 4099 
 4100     @helpers.create_mocks({
 4101         api.neutron: ('floating_ip_target_list_by_instance',
 4102                       'tenant_floating_ip_list',
 4103                       'floating_ip_disassociate',
 4104                       'tenant_floating_ip_release'),
 4105     })
 4106     def _test_disassociate_floating_ip(self, is_release):
 4107         servers = self.servers.list()
 4108         server = servers[0]
 4109         port = [p for p in self.ports.list() if p.device_id == server.id][0]
 4110         fip_target = api.neutron.FloatingIpTarget(
 4111             port, port['fixed_ips'][0]['ip_address'], server.name)
 4112         fip = self.floating_ips.first()
 4113         fip.port_id = port.id
 4114 
 4115         self.mock_floating_ip_target_list_by_instance.return_value = \
 4116             [fip_target]
 4117         self.mock_tenant_floating_ip_list.return_value = [fip]
 4118         self.mock_floating_ip_disassociate.return_value = None
 4119         self.mock_tenant_floating_ip_release.return_value = None
 4120 
 4121         url = reverse('horizon:project:instances:disassociate',
 4122                       args=[server.id])
 4123         form_data = {'fip': fip.id,
 4124                      'is_release': is_release}
 4125         res = self.client.post(url, form_data)
 4126 
 4127         self.assertRedirectsNoFollow(res, INDEX_URL)
 4128 
 4129         self.mock_floating_ip_target_list_by_instance.assert_called_once_with(
 4130             helpers.IsHttpRequest(), server.id)
 4131         self.mock_tenant_floating_ip_list.assert_called_once_with(
 4132             helpers.IsHttpRequest())
 4133         if is_release:
 4134             self.mock_floating_ip_disassociate.assert_not_called()
 4135             self.mock_tenant_floating_ip_release.assert_called_once_with(
 4136                 helpers.IsHttpRequest(), fip.id)
 4137         else:
 4138             self.mock_floating_ip_disassociate.assert_called_once_with(
 4139                 helpers.IsHttpRequest(), fip.id)
 4140             self.mock_tenant_floating_ip_release.assert_not_called()
 4141 
 4142     @helpers.create_mocks({api.neutron: ('floating_ip_disassociate',)})
 4143     def test_disassociate_floating_ip(self):
 4144         self._test_disassociate_floating_ip(is_release=False)
 4145 
 4146     @helpers.create_mocks({api.neutron: ('tenant_floating_ip_release',)})
 4147     def test_disassociate_floating_ip_with_release(self):
 4148         self._test_disassociate_floating_ip(is_release=True)
 4149 
 4150     def _populate_server_flavor_nova_api_ge_2_47(self, server):
 4151         flavor_id = server.flavor['id']
 4152         flavor = self.flavors.get(id=flavor_id)
 4153         server.flavor = {
 4154             'original_name': flavor.name,
 4155             'vcpus': flavor.vcpus,
 4156             'ram': flavor.ram,
 4157             'swap': flavor.swap,
 4158             'disk': flavor.disk,
 4159             'ephemeral': flavor.ephemeral,
 4160             'extra_specs': flavor.extra_specs,
 4161         }
 4162         return server
 4163 
 4164     @helpers.create_mocks({api.nova: ('server_get',
 4165                                       'flavor_list',
 4166                                       'server_group_list',
 4167                                       'tenant_absolute_limits',
 4168                                       'is_feature_available')})
 4169     def _test_instance_resize_get(self, server, nova_api_lt_2_47=False):
 4170         self.mock_server_get.return_value = server
 4171         self.mock_flavor_list.return_value = self.flavors.list()
 4172         self.mock_server_group_list.return_value = self.server_groups.list()
 4173         self.mock_tenant_absolute_limits.return_value = self.limits['absolute']
 4174 
 4175         url = reverse('horizon:project:instances:resize', args=[server.id])
 4176         res = self.client.get(url)
 4177 
 4178         workflow = res.context['workflow']
 4179         self.assertTemplateUsed(res, views.WorkflowView.template_name)
 4180         self.assertEqual(res.context['workflow'].name,
 4181                          workflows.ResizeInstance.name)
 4182         self.assertContains(res, 'Disk Partition')
 4183 
 4184         config_drive_field_label = 'Configuration Drive'
 4185         self.assertNotContains(res, config_drive_field_label)
 4186 
 4187         step = workflow.get_step("flavor_choice")
 4188         self.assertEqual(step.action.initial['old_flavor_name'],
 4189                          self.flavors.first().name)
 4190 
 4191         step = workflow.get_step("setadvancedaction")
 4192         self.assertEqual(step.action.fields['disk_config'].label,
 4193                          'Disk Partition')
 4194         self.assertQuerysetEqual(workflow.steps,
 4195                                  ['<SetFlavorChoice: flavor_choice>',
 4196                                   '<SetAdvanced: setadvancedaction>'])
 4197         option = '<option value="%s">%s</option>'
 4198 
 4199         def is_original_flavor(server, flavor, nova_api_lt_2_47):
 4200             if nova_api_lt_2_47:
 4201                 return flavor.id == server.flavor['id']
 4202             else:
 4203                 return flavor.name == server.flavor['original_name']
 4204 
 4205         for flavor in self.flavors.list():
 4206             if is_original_flavor(server, flavor, nova_api_lt_2_47):
 4207                 self.assertNotContains(res, option % (flavor.id, flavor.name))
 4208             else:
 4209                 self.assertContains(res, option % (flavor.id, flavor.name))
 4210 
 4211         self.mock_server_get.assert_called_once_with(helpers.IsHttpRequest(),
 4212                                                      server.id)
 4213         self.assert_mock_multiple_calls_with_same_arguments(
 4214             self.mock_flavor_list, 2,
 4215             mock.call(helpers.IsHttpRequest()))
 4216         self.mock_server_group_list.assert_called_once_with(
 4217             helpers.IsHttpRequest())
 4218         self.mock_tenant_absolute_limits.assert_called_once_with(
 4219             helpers.IsHttpRequest(), reserved=True)
 4220 
 4221     def test_instance_resize_get_nova_api_lt_2_47(self):
 4222         server = self.servers.first()
 4223         self._test_instance_resize_get(server, nova_api_lt_2_47=True)
 4224 
 4225     def test_instance_resize_get_nova_api_ge_2_47(self):
 4226         server = self.servers.first()
 4227         self._populate_server_flavor_nova_api_ge_2_47(server)
 4228         self._test_instance_resize_get(server)
 4229 
 4230     @helpers.create_mocks({api.nova: ('server_get',)})
 4231     def test_instance_resize_get_server_get_exception(self):
 4232         server = self.servers.first()
 4233 
 4234         self.mock_server_get.side_effect = self.exceptions.nova
 4235 
 4236         url = reverse('horizon:project:instances:resize',
 4237                       args=[server.id])
 4238         res = self.client.get(url)
 4239 
 4240         self.assertRedirectsNoFollow(res, INDEX_URL)
 4241         self.mock_server_get.assert_called_once_with(
 4242             helpers.IsHttpRequest(), server.id)
 4243 
 4244     @helpers.create_mocks({api.nova: ('server_get',
 4245                                       'flavor_list',)})
 4246     def test_instance_resize_get_flavor_list_exception(self):
 4247         server = self.servers.first()
 4248         self.mock_server_get.return_value = server
 4249         self.mock_flavor_list.side_effect = self.exceptions.nova
 4250 
 4251         url = reverse('horizon:project:instances:resize',
 4252                       args=[server.id])
 4253         res = self.client.get(url)
 4254 
 4255         self.assertRedirectsNoFollow(res, INDEX_URL)
 4256 
 4257         self.mock_server_get.assert_called_once_with(helpers.IsHttpRequest(),
 4258                                                      server.id)
 4259         self.mock_flavor_list.assert_called_once_with(helpers.IsHttpRequest())
 4260 
 4261     # TODO(amotoki): This is requred only when nova API <=2.46 is used.
 4262     # Once server_get() uses nova API >=2.47 only, this test can be droppped.
 4263     @helpers.create_mocks({api.nova: ('server_get',
 4264                                       'flavor_list',
 4265                                       'flavor_get',
 4266                                       'server_group_list',
 4267                                       'tenant_absolute_limits',
 4268                                       'is_feature_available')})
 4269     def test_instance_resize_get_current_flavor_not_found(self):
 4270         server = self.servers.first()
 4271         self.mock_server_get.return_value = server
 4272         self.mock_flavor_list.return_value = []
 4273         self.mock_flavor_get.side_effect = self.exceptions.nova
 4274         self.mock_server_group_list.return_value = self.server_groups.list()
 4275         self.mock_tenant_absolute_limits.return_value = self.limits['absolute']
 4276 
 4277         url = reverse('horizon:project:instances:resize', args=[server.id])
 4278         res = self.client.get(url)
 4279 
 4280         self.assertTemplateUsed(res, views.WorkflowView.template_name)
 4281 
 4282         self.mock_server_get.assert_called_once_with(helpers.IsHttpRequest(),
 4283                                                      server.id)
 4284         self.assert_mock_multiple_calls_with_same_arguments(
 4285             self.mock_flavor_list, 2,
 4286             mock.call(helpers.IsHttpRequest()))
 4287         self.mock_flavor_get.assert_called_once_with(
 4288             helpers.IsHttpRequest(), server.flavor['id'])
 4289         self.mock_server_group_list.assert_called_once_with(
 4290             helpers.IsHttpRequest())
 4291         self.mock_tenant_absolute_limits.assert_called_once_with(
 4292             helpers.IsHttpRequest(), reserved=True)
 4293 
 4294     def _instance_resize_post(self, server_id, flavor_id, disk_config):
 4295         formData = {'flavor': flavor_id,
 4296                     'default_role': 'member',
 4297                     'disk_config': disk_config}
 4298         url = reverse('horizon:project:instances:resize',
 4299                       args=[server_id])
 4300         return self.client.post(url, formData)
 4301 
 4302     instance_resize_post_stubs = {
 4303         api.nova: ('server_get', 'server_resize',
 4304                    'flavor_list', 'flavor_get', 'server_group_list',
 4305                    'is_feature_available')}
 4306 
 4307     @helpers.create_mocks(instance_resize_post_stubs)
 4308     def test_instance_resize_post(self):
 4309         server = self.servers.first()
 4310         flavors = [flavor for flavor in self.flavors.list()
 4311                    if flavor.id != server.flavor['id']]
 4312         flavor = flavors[0]
 4313 
 4314         self.mock_server_get.return_value = server
 4315         self.mock_flavor_list.return_value = self.flavors.list()
 4316         self.mock_server_group_list.return_value = self.server_groups.list()
 4317         self.mock_server_resize.return_value = []
 4318 
 4319         res = self._instance_resize_post(server.id, flavor.id, 'AUTO')
 4320         self.assertNoFormErrors(res)
 4321         self.assertRedirectsNoFollow(res, INDEX_URL)
 4322 
 4323         self.mock_server_get.assert_called_once_with(helpers.IsHttpRequest(),
 4324                                                      server.id)
 4325         self.mock_flavor_list.assert_called_once_with(helpers.IsHttpRequest())
 4326         self.mock_server_group_list.assert_called_once_with(
 4327             helpers.IsHttpRequest())
 4328         self.mock_server_resize.assert_called_once_with(
 4329             helpers.IsHttpRequest(), server.id, flavor.id, 'AUTO')
 4330 
 4331     @helpers.create_mocks(instance_resize_post_stubs)
 4332     def test_instance_resize_post_api_exception(self):
 4333         server = self.servers.first()
 4334         flavors = [flavor for flavor in self.flavors.list()
 4335                    if flavor.id != server.flavor['id']]
 4336         flavor = flavors[0]
 4337 
 4338         self.mock_server_get.return_value = server
 4339         self.mock_flavor_list.return_value = self.flavors.list()
 4340         self.mock_server_group_list.return_value = self.server_groups.list()
 4341         self.mock_server_resize.side_effect = self.exceptions.nova
 4342 
 4343         res = self._instance_resize_post(server.id, flavor.id, 'AUTO')
 4344         self.assertRedirectsNoFollow(res, INDEX_URL)
 4345 
 4346         self.mock_server_get.assert_called_once_with(helpers.IsHttpRequest(),
 4347                                                      server.id)
 4348         self.mock_flavor_list.assert_called_once_with(helpers.IsHttpRequest())
 4349         self.mock_server_group_list.assert_called_once_with(
 4350             helpers.IsHttpRequest())
 4351         self.mock_server_resize.assert_called_once_with(
 4352             helpers.IsHttpRequest(), server.id, flavor.id, 'AUTO')
 4353 
 4354     @helpers.create_mocks({api.glance: ('image_list_detailed',),
 4355                            api.nova: ('server_get',
 4356                                       'is_feature_available',)})
 4357     def test_rebuild_instance_get(self, expect_password_fields=True):
 4358         server = self.servers.first()
 4359         self._mock_glance_image_list_detailed(self.images.list())
 4360         self.mock_is_feature_available.return_value = False
 4361         self.mock_server_get.return_value = server
 4362 
 4363         url = reverse('horizon:project:instances:rebuild', args=[server.id])
 4364         res = self.client.get(url)
 4365 
 4366         self.assertTemplateUsed(res, 'project/instances/rebuild.html')
 4367 
 4368         password_field_label = 'Rebuild Password'
 4369         if expect_password_fields:
 4370             self.assertContains(res, password_field_label)
 4371         else:
 4372             self.assertNotContains(res, password_field_label)
 4373 
 4374         self.mock_server_get.assert_called_once_with(
 4375             helpers.IsHttpRequest(), server.id)
 4376         self._check_glance_image_list_detailed(count=4)
 4377         self.mock_is_feature_available.assert_called_once_with(
 4378             helpers.IsHttpRequest(), "instance_description"
 4379         )
 4380 
 4381     @django.test.utils.override_settings(
 4382         OPENSTACK_HYPERVISOR_FEATURES={'can_set_password': False})
 4383     def test_rebuild_instance_get_without_set_password(self):
 4384         self.test_rebuild_instance_get(expect_password_fields=False)
 4385 
 4386     def _instance_rebuild_post(self, server_id, image_id,
 4387                                password=None, confirm_password=None,
 4388                                disk_config=None):
 4389         form_data = {'instance_id': server_id,
 4390                      'image': image_id,
 4391                      'disk_config': disk_config}
 4392         if password is not None:
 4393             form_data.update(password=password)
 4394         if confirm_password is not None:
 4395             form_data.update(confirm_password=confirm_password)
 4396         url = reverse('horizon:project:instances:rebuild',
 4397                       args=[server_id])
 4398         return self.client.post(url, form_data)
 4399 
 4400     instance_rebuild_post_stubs = {
 4401         api.nova: ('server_get',
 4402                    'server_rebuild',
 4403                    'is_feature_available',),
 4404         api.glance: ('image_list_detailed',)}
 4405 
 4406     @helpers.create_mocks(instance_rebuild_post_stubs)
 4407     def test_rebuild_instance_post_with_password(self):
 4408         server = self.servers.first()
 4409         image = self.images.first()
 4410         password = 'testpass'
 4411 
 4412         self.mock_server_get.return_value = server
 4413         self._mock_glance_image_list_detailed(self.images.list())
 4414         self.mock_server_rebuild.return_value = []
 4415         self.mock_is_feature_available.return_value = False
 4416 
 4417         res = self._instance_rebuild_post(server.id, image.id,
 4418                                           password=password,
 4419                                           confirm_password=password,
 4420                                           disk_config='AUTO')
 4421         self.assertNoFormErrors(res)
 4422         self.assertRedirectsNoFollow(res, INDEX_URL)
 4423 
 4424         self.mock_server_get.assert_called_once_with(
 4425             helpers.IsHttpRequest(), server.id)
 4426         self._check_glance_image_list_detailed(count=4)
 4427         self.mock_server_rebuild.assert_called_once_with(
 4428             helpers.IsHttpRequest(), server.id, image.id, password, 'AUTO',
 4429             description=None)
 4430         self.mock_is_feature_available.assert_called_once_with(
 4431             helpers.IsHttpRequest(), "instance_description"
 4432         )
 4433 
 4434     @helpers.create_mocks(instance_rebuild_post_stubs)
 4435     def test_rebuild_instance_post_with_password_equals_none(self):
 4436         server = self.servers.first()
 4437         image = self.images.first()
 4438 
 4439         self.mock_server_get.return_value = server
 4440         self._mock_glance_image_list_detailed(self.images.list())
 4441         self.mock_server_rebuild.side_effect = self.exceptions.nova
 4442         self.mock_is_feature_available.return_value = False
 4443 
 4444         res = self._instance_rebuild_post(server.id, image.id,
 4445                                           password=None,
 4446                                           confirm_password=None,
 4447                                           disk_config='AUTO')
 4448         self.assertRedirectsNoFollow(res, INDEX_URL)
 4449 
 4450         self.mock_server_get.assert_called_once_with(
 4451             helpers.IsHttpRequest(), server.id)
 4452         self._check_glance_image_list_detailed(count=4)
 4453         self.mock_server_rebuild.assert_called_once_with(
 4454             helpers.IsHttpRequest(), server.id, image.id, None, 'AUTO',
 4455             description=None)
 4456         self.mock_is_feature_available.assert_called_once_with(
 4457             helpers.IsHttpRequest(), "instance_description"
 4458         )
 4459 
 4460     @helpers.create_mocks(instance_rebuild_post_stubs)
 4461     def test_rebuild_instance_post_password_do_not_match(self):
 4462         server = self.servers.first()
 4463         image = self.images.first()
 4464         pass1 = 'somepass'
 4465         pass2 = 'notsomepass'
 4466 
 4467         self.mock_server_get.return_value = server
 4468         self._mock_glance_image_list_detailed(self.images.list())
 4469         self.mock_is_feature_available.return_value = False
 4470 
 4471         res = self._instance_rebuild_post(server.id, image.id,
 4472                                           password=pass1,
 4473                                           confirm_password=pass2,
 4474                                           disk_config='MANUAL')
 4475 
 4476         self.