1# Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#    http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15"""
16test_flavor
17----------------------------------
18
19Functional tests for `shade` flavor resource.
20"""
21
22from openstack.cloud.exc import OpenStackCloudException
23from openstack.tests.functional import base
24
25
26class TestFlavor(base.BaseFunctionalTest):
27
28    def setUp(self):
29        super(TestFlavor, self).setUp()
30
31        # Generate a random name for flavors in this test
32        self.new_item_name = self.getUniqueString('flavor')
33
34        self.addCleanup(self._cleanup_flavors)
35
36    def _cleanup_flavors(self):
37        exception_list = list()
38        for f in self.operator_cloud.list_flavors(get_extra=False):
39            if f['name'].startswith(self.new_item_name):
40                try:
41                    self.operator_cloud.delete_flavor(f['id'])
42                except Exception as e:
43                    # We were unable to delete a flavor, let's try with next
44                    exception_list.append(str(e))
45                    continue
46        if exception_list:
47            # Raise an error: we must make users aware that something went
48            # wrong
49            raise OpenStackCloudException('\n'.join(exception_list))
50
51    def test_create_flavor(self):
52        flavor_name = self.new_item_name + '_create'
53        flavor_kwargs = dict(
54            name=flavor_name, ram=1024, vcpus=2, disk=10, ephemeral=5,
55            swap=100, rxtx_factor=1.5, is_public=True
56        )
57
58        flavor = self.operator_cloud.create_flavor(**flavor_kwargs)
59
60        self.assertIsNotNone(flavor['id'])
61
62        # When properly normalized, we should always get an extra_specs
63        # and expect empty dict on create.
64        self.assertIn('extra_specs', flavor)
65        self.assertEqual({}, flavor['extra_specs'])
66
67        # We should also always have ephemeral and public attributes
68        self.assertIn('ephemeral', flavor)
69        self.assertEqual(5, flavor['ephemeral'])
70        self.assertIn('is_public', flavor)
71        self.assertTrue(flavor['is_public'])
72
73        for key in flavor_kwargs.keys():
74            self.assertIn(key, flavor)
75        for key, value in flavor_kwargs.items():
76            self.assertEqual(value, flavor[key])
77
78    def test_list_flavors(self):
79        pub_flavor_name = self.new_item_name + '_public'
80        priv_flavor_name = self.new_item_name + '_private'
81        public_kwargs = dict(
82            name=pub_flavor_name, ram=1024, vcpus=2, disk=10, is_public=True
83        )
84        private_kwargs = dict(
85            name=priv_flavor_name, ram=1024, vcpus=2, disk=10, is_public=False
86        )
87
88        # Create a public and private flavor. We expect both to be listed
89        # for an operator.
90        self.operator_cloud.create_flavor(**public_kwargs)
91        self.operator_cloud.create_flavor(**private_kwargs)
92
93        flavors = self.operator_cloud.list_flavors(get_extra=False)
94
95        # Flavor list will include the standard devstack flavors. We just want
96        # to make sure both of the flavors we just created are present.
97        found = []
98        for f in flavors:
99            # extra_specs should be added within list_flavors()
100            self.assertIn('extra_specs', f)
101            if f['name'] in (pub_flavor_name, priv_flavor_name):
102                found.append(f)
103        self.assertEqual(2, len(found))
104
105    def test_flavor_access(self):
106        priv_flavor_name = self.new_item_name + '_private'
107        private_kwargs = dict(
108            name=priv_flavor_name, ram=1024, vcpus=2, disk=10, is_public=False
109        )
110        new_flavor = self.operator_cloud.create_flavor(**private_kwargs)
111
112        # Validate the 'demo' user cannot see the new flavor
113        flavors = self.user_cloud.search_flavors(priv_flavor_name)
114        self.assertEqual(0, len(flavors))
115
116        # We need the tenant ID for the 'demo' user
117        project = self.operator_cloud.get_project('demo')
118        self.assertIsNotNone(project)
119
120        # Now give 'demo' access
121        self.operator_cloud.add_flavor_access(new_flavor['id'], project['id'])
122
123        # Now see if the 'demo' user has access to it
124        flavors = self.user_cloud.search_flavors(priv_flavor_name)
125        self.assertEqual(1, len(flavors))
126        self.assertEqual(priv_flavor_name, flavors[0]['name'])
127
128        # Now see if the 'demo' user has access to it without needing
129        #  the demo_cloud access.
130        acls = self.operator_cloud.list_flavor_access(new_flavor['id'])
131        self.assertEqual(1, len(acls))
132        self.assertEqual(project['id'], acls[0]['project_id'])
133
134        # Now revoke the access and make sure we can't find it
135        self.operator_cloud.remove_flavor_access(new_flavor['id'],
136                                                 project['id'])
137        flavors = self.user_cloud.search_flavors(priv_flavor_name)
138        self.assertEqual(0, len(flavors))
139
140    def test_set_unset_flavor_specs(self):
141        """
142        Test setting and unsetting flavor extra specs
143        """
144        flavor_name = self.new_item_name + '_spec_test'
145        kwargs = dict(
146            name=flavor_name, ram=1024, vcpus=2, disk=10
147        )
148        new_flavor = self.operator_cloud.create_flavor(**kwargs)
149
150        # Expect no extra_specs
151        self.assertEqual({}, new_flavor['extra_specs'])
152
153        # Now set them
154        extra_specs = {'foo': 'aaa', 'bar': 'bbb'}
155        self.operator_cloud.set_flavor_specs(new_flavor['id'], extra_specs)
156        mod_flavor = self.operator_cloud.get_flavor(
157            new_flavor['id'], get_extra=True)
158
159        # Verify extra_specs were set
160        self.assertIn('extra_specs', mod_flavor)
161        self.assertEqual(extra_specs, mod_flavor['extra_specs'])
162
163        # Unset the 'foo' value
164        self.operator_cloud.unset_flavor_specs(mod_flavor['id'], ['foo'])
165        mod_flavor = self.operator_cloud.get_flavor_by_id(
166            new_flavor['id'], get_extra=True)
167
168        # Verify 'foo' is unset and 'bar' is still set
169        self.assertEqual({'bar': 'bbb'}, mod_flavor['extra_specs'])
170