Revision f5f2dc53

b/docs/installation.rst
105 105
Install objpool (was: snf-common)
106 106
"""""""""""""""""""""""""""""""""
107 107

  
108
Since 0.6.2, kamaki is based on python-objpool. The objpool package is easy to install from source (even on windows platforms):
108
Kamaki is based on python-objpool. The objpool package is easy to install from source, even on windows platforms:
109 109

  
110 110
.. code-block:: console
111 111

  
......
121 121

  
122 122
.. code-block:: console
123 123

  
124
    $ tar xvfz kamaki-0.6.2.tar.gz
124
    $ tar xvfz kamaki-0.7.tar.gz
125 125

  
126 126
or it can be downloaded directly from the git repository:
127 127

  
......
156 156
Windows
157 157
-------
158 158

  
159
Since version 0.6.2 kamaki can run on Windows, either on standard Windows console, or inside an improved command line shell. The present guide presents a tested method for using kamaki in windows
159
Kamaki can run on Windows, either on standard Windows console, or inside an improved command line shell. The present guide presents a tested method for setting up kamaki in windows
160 160

  
161 161
Requirements
162 162
^^^^^^^^^^^^
......
242 242
        $ python setup.py install
243 243
        running install
244 244
        ...
245
        Finished processing dependencies for kamaki==0.6.2
246

  
247
.. warning:: kamaki version should be 0.6.2 or better, otherwise it will not function. Users can test that by running::
245
        Finished processing dependencies for kamaki==0.7
248 246

  
249 247
    $ kamaki --version
b/docs/setup.rst
29 29

  
30 30
* progress 
31 31
    * Attach progress bars to various kamaki commands (e.g. kamaki store upload)
32
    * Since version 0.6.1 kamaki "requires" progress version 1.0.2 or better
32
    * If desired, progress version should be 1.0.2 or better
33 33

  
34 34
Any of the above features can be installed at any time before or after kamaki installation.
35 35

  
......
157 157
Hidden features
158 158
^^^^^^^^^^^^^^^
159 159

  
160
Since version 0.6.1 kamaki contains a test suite for the kamaki.clients API. The test suite can be activated with the following option on the configuration file::
160
The livetest suite
161
""""""""""""""""""
161 162

  
162
    [test]
163
    cli=test_cli
163
Kamaki contains a live test suite for the kamaki.clients API, where "live" means that the tests are performed against active services that up and running. The live test package is named "livetest", it is accessible as kamaki.clients.livetest and it is designed to check the actual relation between kamaki and synnefo services.
164 164

  
165
After that, users can run "kamaki test" commands to unit-test the prepackaged client APIs. Unit-tests are still experimental and there is a high probability of false alarms due to some of the expected values being hard-coded in the testing code.
165
The livetest suite can be activated with the following option on the configuration file::
166 166

  
167
Since version 0.6.3, a quotaholder client is introduced as an advanced feature. Quotaholder client is mostly used as a client library for accessing a synnefo quota service, but it can also be allowed as a kamaki command set, but setting the quotaholder.cli and quotaholder.url methods:
167
    [livetest]
168
    cli=livetest_cli
169

  
170
In most tests, livetest will run as long as an Astakos identity manager service is accessible and kamaki is set up to authenticate a valid token on this server.
171

  
172
In specific, a setup file needs at least the following mandatory settings in the configuration file:
173

  
174
* If authentication information is used for default kamaki clients::
175

  
176
    [astakos]
177
    url=<Astakos Identity Manager URL>
178
    token=<A valid user token>
179

  
180
* else if this authentication information is only for testing add this under [livetest]::
181

  
182
    astakos_url=<Astakos Identity Manager URL>
183
    astakos_token=<A valid user token>
184

  
185
Each service tested in livetest might need some more options under the [livetest] label, as shown bellow:
186

  
187
* kamaki livetest astakos::
188

  
189
    astakos_email = <The valid email of testing user>
190
    astakos_name = <The exact "real" name of testing user>
191
    astakos_username = <The username of the testing user>
192
    astakos_uuid = <The valid unique user id of the testing user>
193

  
194
* kamaki livetest pithos::
195

  
196
    astakos_uuid = <The valid unique user id of the testing user>
197

  
198
* kamaki livetest cyclades / image::
199

  
200
    image_id = <A valid image id used for testing>
201
    image_local_path = <The local path of the testing image>
202
    image_details = <A text file containing testing image details in a python dict>
203

  
204
    - example image.details content:
205
    {
206
        u'id': u'b3e68235-3abd-4d60-adfe-1379a4f8d3fe',
207
        u'metadata': {
208
            u'values': {
209
                u'description': u'Debian 6.0.6 (Squeeze) Base System',
210
                u'gui': u'No GUI',
211
                u'kernel': u'2.6.32',
212
                u'os': u'debian',
213
                u'osfamily': u'linux',
214
                u'root_partition': u'1',
215
                u'sortorder': u'1',
216
                u'users': u'root'
217
            }
218
        },
219
        u'name': u'Debian Base',
220
        u'progress': u'100',
221
        u'status': u'ACTIVE',
222
        u'created': u'2012-11-19T14:54:57+00:00',
223
        u'updated': u'2012-11-19T15:29:51+00:00'
224
    }
225

  
226
    flavor_details = <A text file containing the testing images' flavor details in a python dict>
227

  
228
    - example flavor.details content:
229
    {
230
        u'name': u'C1R1drbd',
231
        u'ram': 1024,
232
        u'id': 1,
233
        u'SNF:disk_template': u'drbd',
234
        u'disk': 20,
235
        u'cpu': 1
236
    }
237

  
238
After setup, kamaki can run all tests::
239

  
240
    $ kamaki livetest all
241

  
242
a specific test (e.g. astakos)::
243

  
244
    $ kamaki livetest astakos
245

  
246
or a specific method from a service (e.g. astakos authenticate)::
247

  
248
    $ kamaki livetest astakos authenticate
249

  
250
The quotaholder client
251
""""""""""""""""""""""
252

  
253
A quotaholder client is introduced as an advanced feature. Quotaholder client is mostly used as a client library for accessing a synnefo quota service, but it can also be allowed as a kamaki command set, but setting the quotaholder.cli and quotaholder.url methods::
168 254

  
169 255
    [quotaholder]
170 256
    cli=quotaholder_cli
171 257
    url=<URL of quotaholder service>
258

  
259
Quotaholder is not tested in livetest
b/kamaki/cli/commands/livetest_cli.py
1
# Copyright 2012-2013 GRNET S.A. All rights reserved.
2
#
3
# Redistribution and use in source and binary forms, with or
4
# without modification, are permitted provided that the following
5
# conditions are met:
6
#
7
#   1. Redistributions of source code must retain the above
8
#      copyright notice, this list of conditions and the following
9
#      disclaimer.
10
#
11
#   2. Redistributions in binary form must reproduce the above
12
#      copyright notice, this list of conditions and the following
13
#      disclaimer in the documentation and/or other materials
14
#      provided with the distribution.
15
#
16
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
# POSSIBILITY OF SUCH DAMAGE.
28
#
29
# The views and conclusions contained in the software and
30
# documentation are those of the authors and should not be
31
# interpreted as representing official policies, either expressed
32
# or implied, of GRNET S.A.command
33

  
34
from kamaki.cli.commands import errors
35
from kamaki.cli import command
36
from kamaki.cli.commands import _command_init
37
from kamaki.cli.command_tree import CommandTree
38
from kamaki.clients import livetest
39
from kamaki.cli.errors import raiseCLIError
40

  
41
livetest_cmds = CommandTree('livetest', 'Test clients on live servers')
42
_commands = [livetest_cmds]
43

  
44

  
45
class _livetest_init(_command_init):
46

  
47
    def _run(self, client, method=None):
48
        if method:
49
            livetest._main([client, method], config=self.config)
50
        else:
51
            livetest._main([client], config=self.config)
52

  
53
    def main(self, client, method=None):
54
        return self._run(client, method)
55

  
56

  
57
@command(livetest_cmds)
58
class livetest_error(_livetest_init):
59
    """Create an error message with optional message"""
60

  
61
    @errors.generic.all
62
    def _run(self, errmsg='', importance=0, index=0):
63
        l = [1, 2]
64
        try:
65
            l[int(index)]
66
        except Exception as err:
67
            raiseCLIError(err, errmsg, importance)
68
        raiseCLIError(None, errmsg, importance)
69

  
70
    def main(self, errmsg='', importance=0, index=0):
71
        self._run(errmsg, importance, index)
72

  
73

  
74
@command(livetest_cmds)
75
class livetest_args(_livetest_init):
76
    """Test how arguments are treated by kamaki"""
77

  
78
    @errors.generic.all
79
    def _run(self, *args):
80
        print(args)
81

  
82
    def main(self, *args):
83
        self._run(args)
84

  
85

  
86
@command(livetest_cmds)
87
class livetest_all(_livetest_init):
88
    """test all clients"""
89

  
90
    @errors.generic.all
91
    def _run(self):
92
        for client in ('pithos', 'cyclades', 'image', 'astakos'):
93
            super(self.__class__, self)._run(client)
94

  
95
    def main(self):
96
        self._run()
97

  
98

  
99
@command(livetest_cmds)
100
class livetest_pithos(_livetest_init):
101
    """ test Pithos client"""
102

  
103
    @errors.generic.all
104
    def _run(self, method=None):
105
        super(self.__class__, self)._run('pithos', method)
106

  
107
    def main(self, method=None):
108
        self._run(method)
109

  
110

  
111
@command(livetest_cmds)
112
class livetest_cyclades(_livetest_init):
113
    """ test Cyclades client"""
114

  
115
    @errors.generic.all
116
    def _run(self, method=None):
117
        super(self.__class__, self)._run('cyclades', method)
118

  
119
    def main(self, method=None):
120
        self._run(method)
121

  
122

  
123
@command(livetest_cmds)
124
class livetest_image(_livetest_init):
125
    """ test Image client"""
126

  
127
    @errors.generic.all
128
    def _run(self, method=None):
129
        super(self.__class__, self)._run('image', method)
130

  
131
    def main(self, method=None):
132
        self._run(method)
133

  
134

  
135
@command(livetest_cmds)
136
class livetest_astakos(_livetest_init):
137
    """ test Astakos client"""
138

  
139
    @errors.generic.all
140
    def _run(self, method=None):
141
        super(self.__class__, self)._run('astakos', method)
142

  
143
    def main(self, method=None):
144
        self._run(method)
145

  
146

  
147
@command(livetest_cmds)
148
class livetest_prints(_livetest_init):
149
    """ user-test print methods for lists and dicts"""
150

  
151
    d1 = {'key0a': 'val0a', 'key0b': 'val0b', 'key0c': 'val0c'}
152

  
153
    l1 = [1, 'string', '3', 'many (2 or 3) numbers and strings combined', 5]
154

  
155
    d2 = {'id': 'val0a', 'key0b': d1, 'title': l1}
156

  
157
    l2 = [d2, l1, d1]
158

  
159
    spr_msg = 'long key of size 75 characters is used to check the effects on'
160
    spr_msg += ' total result for long messages that drive pep8 completely mad'
161
    d3 = {'dict 1': d1, 'dict 2': d2, 'list2': l2, spr_msg: l1}
162

  
163
    @errors.generic.all
164
    def _run(self):
165
        from kamaki.cli.utils import print_dict, print_list, print_items
166
        print('Test simple dict:\n- - -')
167
        print_dict(self.d1)
168
        print('- - -\n')
169
        print('\nTest simple list:\n- - -')
170
        print_list(self.l1)
171
        print('- - -\n')
172
        print('\nTest 2-level dict:\n- - -')
173
        print_dict(self.d2)
174
        print('- - -\n')
175
        print('\nTest non-trivial list:\n- - -')
176
        print_list(self.l2)
177
        print('- - -')
178
        print('\nTest extreme dict:\n- - -')
179
        print_dict(self.d3)
180
        print('- - -\n')
181
        print('Test simple enumerated dict:\n- - -')
182
        print_dict(self.d1, with_enumeration=True)
183
        print('- - -\n')
184
        print('\nTest simple enumerated list:\n- - -')
185
        print_list(self.l1, with_enumeration=True)
186
        print('- - -\n')
187
        print('Test non-trivial deep-enumerated dict:\n- - -')
188
        print_dict(self.d2, with_enumeration=True, recursive_enumeration=True)
189
        print('- - -\n')
190
        print('\nTest non-trivial enumerated list:\n- - -')
191
        print_list(self.l2, with_enumeration=True)
192
        print('- - -\n')
193
        print('\nTest print_items with id:\n- - -')
194
        print_items([
195
            {'id': '42', 'title': 'lalakis 1', 'content': self.d1},
196
            {'id': '142', 'title': 'lalakis 2', 'content': self.d2}])
197
        print('- - -')
198
        print('\nTest print_items with id and enumeration:\n- - -')
199
        print_items(
200
            [
201
                {'id': '42', 'title': 'lalakis 1', 'content': self.d1},
202
                {'id': '142', 'title': 'lalakis 2', 'content': self.d2}],
203
            with_enumeration=True)
204
        print('- - -')
205
        print('\nTest print_items with id, title and redundancy:\n- - -')
206
        print_items(
207
            [
208
                {'id': '42', 'title': 'lalakis 1', 'content': self.d1},
209
                {'id': '142', 'title': 'lalakis 2', 'content': self.d2}],
210
            title=('id', 'title'),
211
            with_redundancy=True)
212
        print('- - -')
213
        print('\nTest print_items with lists- - -')
214
        print_items([['i00', 'i01', 'i02'], [self.l2, 'i11', self.d1], 3])
215
        print('- - -')
216

  
217
    def main(self):
218
        self._run()
/dev/null
1
# Copyright 2012-2013 GRNET S.A. All rights reserved.
2
#
3
# Redistribution and use in source and binary forms, with or
4
# without modification, are permitted provided that the following
5
# conditions are met:
6
#
7
#   1. Redistributions of source code must retain the above
8
#      copyright notice, this list of conditions and the following
9
#      disclaimer.
10
#
11
#   2. Redistributions in binary form must reproduce the above
12
#      copyright notice, this list of conditions and the following
13
#      disclaimer in the documentation and/or other materials
14
#      provided with the distribution.
15
#
16
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
# POSSIBILITY OF SUCH DAMAGE.
28
#
29
# The views and conclusions contained in the software and
30
# documentation are those of the authors and should not be
31
# interpreted as representing official policies, either expressed
32
# or implied, of GRNET S.A.command
33

  
34
from kamaki.cli.commands import errors
35
from kamaki.cli import command
36
from kamaki.cli.commands import _command_init
37
from kamaki.cli.command_tree import CommandTree
38
from kamaki.clients import tests
39
from kamaki.cli.errors import raiseCLIError
40

  
41
test_cmds = CommandTree('test', 'Unitest clients')
42
_commands = [test_cmds]
43

  
44

  
45
class _test_init(_command_init):
46

  
47
    def _run(self, client, method=None):
48
        if method:
49
            tests._main([client, method], config=self.config)
50
        else:
51
            tests._main([client], config=self.config)
52

  
53
    def main(self, client, method=None):
54
        return self._run(client, method)
55

  
56

  
57
@command(test_cmds)
58
class test_error(_test_init):
59
    """Create an error message with optional message"""
60

  
61
    @errors.generic.all
62
    def _run(self, errmsg='', importance=0, index=0):
63
        l = [1, 2]
64
        try:
65
            l[int(index)]
66
        except Exception as err:
67
            raiseCLIError(err, errmsg, importance)
68
        raiseCLIError(None, errmsg, importance)
69

  
70
    def main(self, errmsg='', importance=0, index=0):
71
        self._run(errmsg, importance, index)
72

  
73

  
74
@command(test_cmds)
75
class test_args(_test_init):
76
    """Test how arguments are treated by kamaki"""
77

  
78
    @errors.generic.all
79
    def _run(self, *args):
80
        print(args)
81

  
82
    def main(self, *args):
83
        self._run(args)
84

  
85

  
86
@command(test_cmds)
87
class test_all(_test_init):
88
    """test all clients"""
89

  
90
    @errors.generic.all
91
    def _run(self):
92
        for client in ('pithos', 'cyclades', 'image', 'astakos'):
93
            super(self.__class__, self)._run(client)
94

  
95
    def main(self):
96
        self._run()
97

  
98

  
99
@command(test_cmds)
100
class test_pithos(_test_init):
101
    """ test Pithos client"""
102

  
103
    @errors.generic.all
104
    def _run(self, method=None):
105
        super(self.__class__, self)._run('pithos', method)
106

  
107
    def main(self, method=None):
108
        self._run(method)
109

  
110

  
111
@command(test_cmds)
112
class test_cyclades(_test_init):
113
    """ test Cyclades client"""
114

  
115
    @errors.generic.all
116
    def _run(self, method=None):
117
        super(self.__class__, self)._run('cyclades', method)
118

  
119
    def main(self, method=None):
120
        self._run(method)
121

  
122

  
123
@command(test_cmds)
124
class test_image(_test_init):
125
    """ test Image client"""
126

  
127
    @errors.generic.all
128
    def _run(self, method=None):
129
        super(self.__class__, self)._run('image', method)
130

  
131
    def main(self, method=None):
132
        self._run(method)
133

  
134

  
135
@command(test_cmds)
136
class test_astakos(_test_init):
137
    """ test Astakos client"""
138

  
139
    @errors.generic.all
140
    def _run(self, method=None):
141
        super(self.__class__, self)._run('astakos', method)
142

  
143
    def main(self, method=None):
144
        self._run(method)
145

  
146

  
147
@command(test_cmds)
148
class test_prints(_test_init):
149
    """ user-test print methods for lists and dicts"""
150

  
151
    d1 = {'key0a': 'val0a', 'key0b': 'val0b', 'key0c': 'val0c'}
152

  
153
    l1 = [1, 'string', '3', 'many (2 or 3) numbers and strings combined', 5]
154

  
155
    d2 = {'id': 'val0a', 'key0b': d1, 'title': l1}
156

  
157
    l2 = [d2, l1, d1]
158

  
159
    spr_msg = 'long key of size 75 characters is used to check the effects on'
160
    spr_msg += ' total result for long messages that drive pep8 completely mad'
161
    d3 = {'dict 1': d1, 'dict 2': d2, 'list2': l2, spr_msg: l1}
162

  
163
    @errors.generic.all
164
    def _run(self):
165
        from kamaki.cli.utils import print_dict, print_list, print_items
166
        print('Test simple dict:\n- - -')
167
        print_dict(self.d1)
168
        print('- - -\n')
169
        print('\nTest simple list:\n- - -')
170
        print_list(self.l1)
171
        print('- - -\n')
172
        print('\nTest 2-level dict:\n- - -')
173
        print_dict(self.d2)
174
        print('- - -\n')
175
        print('\nTest non-trivial list:\n- - -')
176
        print_list(self.l2)
177
        print('- - -')
178
        print('\nTest extreme dict:\n- - -')
179
        print_dict(self.d3)
180
        print('- - -\n')
181
        print('Test simple enumerated dict:\n- - -')
182
        print_dict(self.d1, with_enumeration=True)
183
        print('- - -\n')
184
        print('\nTest simple enumerated list:\n- - -')
185
        print_list(self.l1, with_enumeration=True)
186
        print('- - -\n')
187
        print('Test non-trivial deep-enumerated dict:\n- - -')
188
        print_dict(self.d2, with_enumeration=True, recursive_enumeration=True)
189
        print('- - -\n')
190
        print('\nTest non-trivial enumerated list:\n- - -')
191
        print_list(self.l2, with_enumeration=True)
192
        print('- - -\n')
193
        print('\nTest print_items with id:\n- - -')
194
        print_items([
195
            {'id': '42', 'title': 'lalakis 1', 'content': self.d1},
196
            {'id': '142', 'title': 'lalakis 2', 'content': self.d2}])
197
        print('- - -')
198
        print('\nTest print_items with id and enumeration:\n- - -')
199
        print_items(
200
            [
201
                {'id': '42', 'title': 'lalakis 1', 'content': self.d1},
202
                {'id': '142', 'title': 'lalakis 2', 'content': self.d2}],
203
            with_enumeration=True)
204
        print('- - -')
205
        print('\nTest print_items with id, title and redundancy:\n- - -')
206
        print_items(
207
            [
208
                {'id': '42', 'title': 'lalakis 1', 'content': self.d1},
209
                {'id': '142', 'title': 'lalakis 2', 'content': self.d2}],
210
            title=('id', 'title'),
211
            with_redundancy=True)
212
        print('- - -')
213
        print('\nTest print_items with lists- - -')
214
        print_items([['i00', 'i01', 'i02'], [self.l2, 'i11', self.d1], 3])
215
        print('- - -')
216

  
217
    def main(self):
218
        self._run()
b/kamaki/clients/livetest/__init__.py
1
# Copyright 2012-2013 GRNET S.A. All rights reserved.
2
#
3
# Redistribution and use in source and binary forms, with or
4
# without modification, are permitted provided that the following
5
# conditions are met:
6
#
7
#   1. Redistributions of source code must retain the above
8
#      copyright notice, this list of conditions and the following
9
#      disclaimer.
10
#
11
#   2. Redistributions in binary form must reproduce the above
12
#      copyright notice, this list of conditions and the following
13
#      disclaimer in the documentation and/or other materials
14
#      provided with the distribution.
15
#
16
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
# POSSIBILITY OF SUCH DAMAGE.
28
#
29
# The views and conclusions contained in the software and
30
# documentation are those of the authors and should not be
31
# interpreted as representing official policies, either expressed
32
# or implied, of GRNET S.A.
33

  
34
import inspect
35
from unittest import TestCase, TestSuite, TextTestRunner
36
from argparse import ArgumentParser
37
from sys import stdout
38

  
39
from kamaki.cli.config import Config
40
from kamaki.cli.utils import spiner
41

  
42

  
43
def _add_value(foo, value):
44
    def wrap(self):
45
        return foo(self, value)
46
    return wrap
47

  
48

  
49
class Generic(TestCase):
50

  
51
    _waits = []
52
    _cnf = None
53
    _grp = None
54
    _fetched = {}
55

  
56
    def __init__(self, specific=None, config=None, group=None):
57
        super(Generic, self).__init__(specific)
58
        self._cnf = config or Config()
59
        self._grp = group
60
        self._waits.append(0.71828)
61
        for i in range(10):
62
            self._waits.append(self._waits[-1] * 2.71828)
63

  
64
    def __getitem__(self, key):
65
        key = self._key(key)
66
        try:
67
            r = self._fetched[key]
68
            return r
69
            return self._fetched[key]
70
        except KeyError:
71
            r = self._get_from_cnf(key)
72
            return r
73
            return self._get_from_cnf(key)
74

  
75
    def _key(self, key):
76
        return ('', key) if isinstance(key, str)\
77
            else ('', key[0]) if len(key) == 1\
78
            else key
79

  
80
    def _get_from_cnf(self, key):
81
        val = 0
82
        if key[0]:
83
            keystr = '%s_%s' % key
84
            val = self._cnf.get('livetest', keystr) or self._cnf.get(*key)
85
        if not val:
86
            val = self._cnf.get('livetest', key[1]) or self._cnf.get(
87
                'global',
88
                key[1])
89
        self._fetched[key] = val
90
        return val
91

  
92
    def _safe_progress_bar(self, msg):
93
        """Try to get a progress bar, but do not raise errors"""
94
        try:
95
            from progress.bar import ShadyBar
96
            wait_bar = ShadyBar(msg)
97

  
98
            def wait_gen(n):
99
                for i in wait_bar.iter(range(int(n))):
100
                    yield
101
                yield
102
            wait_cb = wait_gen
103
        except Exception:
104
            stdout.write('%s:' % msg)
105
            (wait_bar, wait_cb) = (None, spiner)
106
        return (wait_bar, wait_cb)
107

  
108
    def _safe_progress_bar_finish(self, progress_bar):
109
        try:
110
            progress_bar.finish()
111
        except Exception:
112
            print('\b DONE')
113

  
114
    def do_with_progress_bar(self, action, msg, items):
115
        if not items:
116
            print('%s: DONE' % msg)
117
            return
118
        (action_bar, action_cb) = self._safe_progress_bar(msg)
119
        action_gen = action_cb(len(items))
120
        try:
121
            action_gen.next()
122
        except Exception:
123
            pass
124
        for item in items:
125
            action(item)
126
            action_gen.next()
127
        self._safe_progress_bar_finish(action_bar)
128

  
129
    def assert_dicts_are_deeply_equal(self, d1, d2):
130
        (st1, st2) = (set(d1.keys()), set(d2.keys()))
131
        diff1 = st1.difference(st2)
132
        diff2 = st2.difference(st1)
133
        self.assertTrue(
134
            not (diff1 or diff2),
135
            'Key differences:\n\td1-d2=%s\n\td2-d1=%s' % (diff1, diff2))
136
        for k, v in d1.items():
137
            if isinstance(v, dict):
138
                self.assert_dicts_are_deeply_equal(v, d2[k])
139
            else:
140
                self.assertEqual(unicode(v), unicode(d2[k]))
141

  
142
    def test_000(self):
143
        print('')
144
        methods = [method for method in inspect.getmembers(
145
            self,
146
            predicate=inspect.ismethod) if method[0].startswith('_test_')]
147
        failures = 0
148
        for method in methods:
149
            stdout.write('Test %s ' % method[0][6:])
150
            stdout.flush()
151
            try:
152
                method[1]()
153
                print(' ...ok')
154
            except AssertionError:
155
                print('  FAIL: %s (%s)' % (method[0], method[1]))
156
                failures += 1
157
        if failures:
158
            raise AssertionError('%s failures' % failures)
159

  
160

  
161
def init_parser():
162
    parser = ArgumentParser(add_help=False)
163
    parser.add_argument(
164
        '-h', '--help',
165
        dest='help',
166
        action='store_true',
167
        default=False,
168
        help="Show this help message and exit")
169
    return parser
170

  
171

  
172
def main(argv):
173
    _main(argv, config=None)
174

  
175

  
176
def _main(argv, config=None):
177
    suiteFew = TestSuite()
178
    if len(argv) == 0 or argv[0] == 'pithos':
179
        from kamaki.clients.livetest.pithos import Pithos
180
        test_method = 'test_%s' % (argv[1] if len(argv) > 1 else '000')
181
        suiteFew.addTest(Pithos(test_method, config))
182
    if len(argv) == 0 or argv[0] == 'cyclades':
183
        from kamaki.clients.livetest.cyclades import Cyclades
184
        test_method = 'test_%s' % (argv[1] if len(argv) > 1 else '000')
185
        suiteFew.addTest(Cyclades(test_method, config))
186
    if len(argv) == 0 or argv[0] == 'image':
187
        from kamaki.clients.livetest.image import Image
188
        test_method = 'test_%s' % (argv[1] if len(argv) > 1 else '000')
189
        suiteFew.addTest(Image(test_method, config))
190
    if len(argv) == 0 or argv[0] == 'astakos':
191
        from kamaki.clients.livetest.astakos import Astakos
192
        test_method = 'test_%s' % (argv[1] if len(argv) > 1 else '000')
193
        suiteFew.addTest(Astakos(test_method, config))
194

  
195
    TextTestRunner(verbosity=2).run(suiteFew)
196

  
197
if __name__ == '__main__':
198
    parser = init_parser()
199
    args, argv = parser.parse_known_args()
200
    if len(argv) > 2 or getattr(args, 'help') or len(argv) < 1:
201
        raise Exception('\tusage: livetest <group> [command]')
202
    main(argv)
b/kamaki/clients/livetest/astakos.py
1
# Copyright 2012-2013 GRNET S.A. All rights reserved.
2
#
3
# Redistribution and use in source and binary forms, with or
4
# without modification, are permitted provided that the following
5
# conditions are met:
6
#
7
#   1. Redistributions of source code must retain the above
8
#      copyright notice, this list of conditions and the following
9
#      disclaimer.
10
#
11
#   2. Redistributions in binary form must reproduce the above
12
#      copyright notice, this list of conditions and the following
13
#      disclaimer in the documentation and/or other materials
14
#      provided with the distribution.
15
#
16
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
# POSSIBILITY OF SUCH DAMAGE.
28
#
29
# The views and conclusions contained in the software and
30
# documentation are those of the authors and should not be
31
# interpreted as representing official policies, either expressed
32
# or implied, of GRNET S.A.
33

  
34
from kamaki.clients import livetest
35
from kamaki.clients.astakos import AstakosClient
36

  
37

  
38
class Astakos(livetest.Generic):
39
    def setUp(self):
40
        self.client = AstakosClient(
41
            self['astakos', 'url'],
42
            self['astakos', 'token'])
43

  
44
    def test_authenticate(self):
45
        self._test_0010_authenticate()
46

  
47
    def _test_0010_authenticate(self):
48
        r = self.client.authenticate()
49
        for term in (
50
                'name',
51
                'username',
52
                'auth_token_expires',
53
                'auth_token_created',
54
                'uuid',
55
                'id',
56
                'email'):
57
            self.assertTrue(term in r)
58

  
59
    def test_info(self):
60
        self._test_0020_info()
61

  
62
    def _test_0020_info(self):
63
        self.assertTrue(set([
64
            'name',
65
            'username',
66
            'uuid']).issubset(self.client.info().keys()))
67

  
68
    def test_get(self):
69
        self._test_0020_get()
70

  
71
    def _test_0020_get(self):
72
        for term in ('uuid', 'name', 'username'):
73
            self.assertEqual(
74
                self.client.term(term, self['astakos', 'token']),
75
                self['astakos', term])
76
        self.assertTrue(self['astakos', 'email'] in self.client.term('email'))
77

  
78
    def test_list(self):
79
        self.client.authenticate()
80
        self._test_0020_list()
81

  
82
    def _test_0020_list(self):
83
        terms = set(['name', 'username', 'uuid', 'email', 'auth_token'])
84
        uuid = 0
85
        for r in self.client.list():
86
            self.assertTrue(terms.issubset(r.keys()))
87
            self.assertTrue(uuid != r['uuid'] if uuid else True)
88
            uuid = r['uuid']
b/kamaki/clients/livetest/cyclades.py
1
# Copyright 2012-2013 GRNET S.A. All rights reserved.
2
#
3
# Redistribution and use in source and binary forms, with or
4
# without modification, are permitted provided that the following
5
# conditions are met:
6
#
7
#   1. Redistributions of source code must retain the above
8
#      copyright notice, this list of conditions and the following
9
#      disclaimer.
10
#
11
#   2. Redistributions in binary form must reproduce the above
12
#      copyright notice, this list of conditions and the following
13
#      disclaimer in the documentation and/or other materials
14
#      provided with the distribution.
15
#
16
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
# POSSIBILITY OF SUCH DAMAGE.
28
#
29
# The views and conclusions contained in the software and
30
# documentation are those of the authors and should not be
31
# interpreted as representing official policies, either expressed
32
# or implied, of GRNET S.A.
33

  
34
import time
35

  
36
from kamaki.clients import livetest, ClientError
37
from kamaki.clients.cyclades import CycladesClient
38

  
39

  
40
class Cyclades(livetest.Generic):
41
    """Set up a Cyclades thorough test"""
42
    def setUp(self):
43
        print
44
        with open(self['image', 'details']) as f:
45
            self.img_details = eval(f.read())
46
        self.img = self.img_details['id']
47
        with open(self['flavor', 'details']) as f:
48
            self._flavor_details = eval(f.read())
49
        self.PROFILES = ('ENABLED', 'DISABLED', 'PROTECTED')
50

  
51
        self.servers = {}
52
        self.now = time.mktime(time.gmtime())
53
        self.servname1 = 'serv' + unicode(self.now)
54
        self.servname2 = self.servname1 + '_v2'
55
        self.servname1 += '_v1'
56
        self.flavorid = 1
57
        #servers have to be created at the begining...
58
        self.networks = {}
59
        self.netname1 = 'net' + unicode(self.now)
60
        self.netname2 = 'net' + unicode(self.now) + '_v2'
61

  
62
        self.client = CycladesClient(self['compute', 'url'], self['token'])
63

  
64
    def tearDown(self):
65
        """Destoy servers used in testing"""
66
        for net in self.networks.keys():
67
            self._delete_network(net)
68
        for server in self.servers.values():
69
            self._delete_server(server['id'])
70
            print('DEL VM %s (%s)' % (server['id'], server['name']))
71

  
72
    def test_000(self):
73
        "Prepare a full Cyclades test scenario"
74
        self.server1 = self._create_server(
75
            self.servname1,
76
            self.flavorid,
77
            self.img)
78
        self.server2 = self._create_server(
79
            self.servname2,
80
            self.flavorid + 2,
81
            self.img)
82
        super(self.__class__, self).test_000()
83

  
84
    def _create_server(self, servername, flavorid, imageid, personality=None):
85
        server = self.client.create_server(
86
            servername,
87
            flavorid,
88
            imageid,
89
            personality)
90
        print('CREATE VM %s (%s)' % (server['id'], server['name']))
91
        self.servers[servername] = server
92
        return server
93

  
94
    def _delete_server(self, servid):
95
        try:
96
            current_state = self.client.get_server_details(servid)
97
            current_state = current_state['status']
98
            if current_state == 'DELETED':
99
                return
100
            self.client.delete_server(servid)
101
            self._wait_for_status(servid, current_state)
102
            self.client.delete_server(servid)
103
        except:
104
            return
105

  
106
    def _create_network(self, netname, **kwargs):
107
        net = self.client.create_network(netname, **kwargs)
108
        self.networks[net['id']] = net
109
        return net
110

  
111
    def _delete_network(self, netid):
112
        if not netid in self.networks:
113
            return None
114
        print('Disconnect nics of network %s' % netid)
115
        self.client.disconnect_network_nics(netid)
116

  
117
        def netwait(wait):
118
            try:
119
                self.client.delete_network(netid)
120
            except ClientError:
121
                time.sleep(wait)
122
        self.do_with_progress_bar(
123
            netwait,
124
            'Delete network %s' % netid,
125
            self._waits[:7])
126
        return self.networks.pop(netid)
127

  
128
    def _wait_for_network(self, netid, status):
129

  
130
        def netwait(wait):
131
            r = self.client.get_network_details(netid)
132
            if r['status'] == status:
133
                return
134
            time.sleep(wait)
135
        self.do_with_progress_bar(
136
            netwait,
137
            'Wait network %s to reach status %s' % (netid, status),
138
            self._waits[:5])
139

  
140
    def _wait_for_nic(self, netid, servid, in_creation=True):
141
        self._wait_for_network(netid, 'ACTIVE')
142

  
143
        def nicwait(wait):
144
            nics = self.client.list_server_nics(servid)
145
            for net in nics:
146
                found_nic = net['network_id'] == netid
147
                if (in_creation and found_nic) or not (
148
                        in_creation or found_nic):
149
                    return
150
            time.sleep(wait)
151
        self.do_with_progress_bar(
152
            nicwait,
153
            'Wait nic-%s-%s to %sconnect' % (
154
                netid,
155
                servid,
156
                '' if in_creation else 'dis'),
157
            self._waits[:5])
158
        for net in self.client.list_server_nics(servid):
159
            if netid == net['network_id']:
160
                return True
161
        return False
162

  
163
    def _has_status(self, servid, status):
164
        r = self.client.get_server_details(servid)
165
        return r['status'] == status
166

  
167
    def _wait_for_status(self, servid, status):
168
        (wait_bar, wait_cb) = self._safe_progress_bar(
169
            'Server %s in %s' % (servid, status))
170
        self.client.wait_server(servid, status, wait_cb=wait_cb)
171
        self._safe_progress_bar_finish(wait_bar)
172

  
173
    def test_parallel_creation(self):
174
        """test create with multiple threads
175
        Do not use this in regular livetest
176
        """
177
        from kamaki.clients import SilentEvent
178
        c1 = SilentEvent(
179
            self._create_server,
180
            self.servname1,
181
            self.flavorid,
182
            self.img)
183
        c2 = SilentEvent(
184
            self._create_server,
185
            self.servname2,
186
            self.flavorid + 2,
187
            self.img)
188
        c3 = SilentEvent(
189
            self._create_server,
190
            self.servname1,
191
            self.flavorid,
192
            self.img)
193
        c4 = SilentEvent(
194
            self._create_server,
195
            self.servname2,
196
            self.flavorid + 2,
197
            self.img)
198
        c5 = SilentEvent(
199
            self._create_server,
200
            self.servname1,
201
            self.flavorid,
202
            self.img)
203
        c6 = SilentEvent(
204
            self._create_server,
205
            self.servname2,
206
            self.flavorid + 2,
207
            self.img)
208
        c7 = SilentEvent(
209
            self._create_server,
210
            self.servname1,
211
            self.flavorid,
212
            self.img)
213
        c8 = SilentEvent(
214
            self._create_server,
215
            self.servname2,
216
            self.flavorid + 2,
217
            self.img)
218
        c1.start()
219
        c2.start()
220
        c3.start()
221
        c4.start()
222
        c5.start()
223
        c6.start()
224
        c7.start()
225
        c8.start()
226

  
227
    def test_create_server(self):
228
        """Test create_server"""
229
        self.server1 = self._create_server(
230
            self.servname1,
231
            self.flavorid,
232
            self.img)
233
        self._wait_for_status(self.server1['id'], 'BUILD')
234
        self._test_0010_create_server()
235

  
236
    def _test_0010_create_server(self):
237
        self.assertEqual(self.server1["name"], self.servname1)
238
        self.assertEqual(self.server1["flavorRef"], self.flavorid)
239
        self.assertEqual(self.server1["imageRef"], self.img)
240
        self.assertEqual(self.server1["status"], "BUILD")
241

  
242
    def test_list_servers(self):
243
        """Test list servers"""
244
        self.server1 = self._create_server(
245
            self.servname1,
246
            self.flavorid,
247
            self.img)
248
        self.server2 = self._create_server(
249
            self.servname2,
250
            self.flavorid + 2,
251
            self.img)
252
        self._test_0020_list_servers()
253

  
254
    def _test_0020_list_servers(self):
255
        servers = self.client.list_servers()
256
        dservers = self.client.list_servers(detail=True)
257

  
258
        """detailed and simple are same size"""
259
        self.assertEqual(len(dservers), len(servers))
260
        for i in range(len(servers)):
261
            for field in (
262
                    'created',
263
                    'flavorRef',
264
                    'hostId',
265
                    'imageRef',
266
                    'progress',
267
                    'status',
268
                    'updated'):
269
                self.assertFalse(field in servers[i])
270
                self.assertTrue(field in dservers[i])
271

  
272
        """detailed and simple contain same names"""
273
        names = sorted(map(lambda x: x["name"], servers))
274
        dnames = sorted(map(lambda x: x["name"], dservers))
275
        self.assertEqual(names, dnames)
276

  
277
    def _test_0030_wait_test_servers_to_build(self):
278
        """Pseudo-test to wait for VMs to load"""
279
        print('')
280
        self._wait_for_status(self.server1['id'], 'BUILD')
281
        self._wait_for_status(self.server2['id'], 'BUILD')
282

  
283
    def test_get_server_details(self):
284
        """Test get_server_details"""
285
        self.server1 = self._create_server(
286
            self.servname1,
287
            self.flavorid,
288
            self.img)
289
        self._wait_for_status(self.server1['id'], 'BUILD')
290
        self._test_0040_get_server_details()
291

  
292
    def _test_0040_get_server_details(self):
293
        r = self.client.get_server_details(self.server1['id'])
294
        self.assertEqual(r["name"], self.servname1)
295
        self.assertEqual(r["flavorRef"], self.flavorid)
296
        self.assertEqual(r["imageRef"], self.img)
297
        self.assertEqual(r["status"], "ACTIVE")
298

  
299
    def test_update_server_name(self):
300
        """Test update_server_name"""
301
        self.server1 = self._create_server(
302
            self.servname1,
303
            self.flavorid,
304
            self.img)
305
        self._test_0050_update_server_name()
306

  
307
    def _test_0050_update_server_name(self):
308
        new_name = self.servname1 + '_new_name'
309
        self.client.update_server_name(self.server1['id'], new_name)
310
        r = self.client.get_server_details(
311
            self.server1['id'],
312
            success=(200, 400))
313
        self.assertEqual(r['name'], new_name)
314
        changed = self.servers.pop(self.servname1)
315
        changed['name'] = new_name
316
        self.servers[new_name] = changed
317

  
318
    def test_reboot_server(self):
319
        """Test reboot server"""
320
        self.server1 = self._create_server(
321
            self.servname1,
322
            self.flavorid,
323
            self.img)
324
        self._wait_for_status(self.server1['id'], 'BUILD')
325
        self.server2 = self._create_server(
326
            self.servname2,
327
            self.flavorid + 1,
328
            self.img)
329
        self._wait_for_status(self.server2['id'], 'BUILD')
330
        self._test_0060_reboot_server()
331
        self._wait_for_status(self.server1['id'], 'REBOOT')
332
        self._wait_for_status(self.server2['id'], 'REBOOT')
333

  
334
    def _test_0060_reboot_server(self):
335
        self.client.reboot_server(self.server1['id'])
336
        self.assertTrue(self._has_status(self.server1['id'], 'REBOOT'))
337
        self.client.reboot_server(self.server2['id'], hard=True)
338
        self.assertTrue(self._has_status(self.server2['id'], 'REBOOT'))
339

  
340
    def _test_0070_wait_test_servers_to_reboot(self):
341
        """Pseudo-test to wait for VMs to load"""
342
        print('')
343
        self._wait_for_status(self.server1['id'], 'REBOOT')
344
        self._wait_for_status(self.server2['id'], 'REBOOT')
345

  
346
    def test_create_server_metadata(self):
347
        """Test create_server_metadata"""
348
        self.server1 = self._create_server(
349
            self.servname1,
350
            self.flavorid,
351
            self.img)
352
        self._test_0080_create_server_metadata()
353

  
354
    def _test_0080_create_server_metadata(self):
355
        r1 = self.client.create_server_metadata(
356
            self.server1['id'],
357
            'mymeta',
358
            'mymeta val')
359
        self.assertTrue('mymeta' in r1)
360
        r2 = self.client.get_server_metadata(self.server1['id'], 'mymeta')
361
        self.assert_dicts_are_deeply_equal(r1, r2)
362

  
363
    def test_get_server_metadata(self):
364
        """Test get server_metadata"""
365
        self.server1 = self._create_server(
366
            self.servname1,
367
            self.flavorid,
368
            self.img)
369
        self._test_0090_get_server_metadata()
370

  
371
    def _test_0090_get_server_metadata(self):
372
        self.client.create_server_metadata(
373
            self.server1['id'],
374
            'mymeta_0',
375
            'val_0')
376
        r = self.client.get_server_metadata(self.server1['id'], 'mymeta_0')
377
        self.assertEqual(r['mymeta_0'], 'val_0')
378

  
379
    def test_update_server_metadata(self):
380
        """Test update_server_metadata"""
381
        self.server1 = self._create_server(
382
            self.servname1,
383
            self.flavorid,
384
            self.img)
385
        self._test_0100_update_server_metadata()
386

  
387
    def _test_0100_update_server_metadata(self):
388
        r1 = self.client.create_server_metadata(
389
            self.server1['id'],
390
            'mymeta3',
391
            'val2')
392
        self.assertTrue('mymeta3'in r1)
393
        r2 = self.client.update_server_metadata(
394
            self.server1['id'],
395
            mymeta3='val3')
396
        self.assertTrue(r2['mymeta3'], 'val3')
397

  
398
    def test_delete_server_metadata(self):
399
        """Test delete_server_metadata"""
400
        self.server1 = self._create_server(
401
            self.servname1,
402
            self.flavorid,
403
            self.img)
404
        self._test_0110_delete_server_metadata()
405

  
406
    def _test_0110_delete_server_metadata(self):
407
        r1 = self.client.create_server_metadata(
408
            self.server1['id'],
409
            'mymeta',
410
            'val')
411
        self.assertTrue('mymeta' in r1)
412
        self.client.delete_server_metadata(self.server1['id'], 'mymeta')
413
        try:
414
            self.client.get_server_metadata(self.server1['id'], 'mymeta')
415
            raise ClientError('Wrong Error', status=100)
416
        except ClientError as err:
417
            self.assertEqual(err.status, 404)
418

  
419
    def test_list_flavors(self):
420
        """Test flavors_get"""
421
        self._test_0120_list_flavors()
422

  
423
    def _test_0120_list_flavors(self):
424
        r = self.client.list_flavors()
425
        self.assertTrue(len(r) > 1)
426
        r = self.client.list_flavors(detail=True)
427
        self.assertTrue('SNF:disk_template' in r[0])
428

  
429
    def test_get_flavor_details(self):
430
        """Test test_get_flavor_details"""
431
        self._test_0130_get_flavor_details()
432

  
433
    def _test_0130_get_flavor_details(self):
434
        r = self.client.get_flavor_details(self.flavorid)
435
        self.assert_dicts_are_deeply_equal(self._flavor_details, r)
436

  
437
    def test_list_images(self):
438
        """Test list_images"""
439
        self._test_0140_list_images()
440

  
441
    def _test_0140_list_images(self):
442
        r = self.client.list_images()
443
        self.assertTrue(len(r) > 1)
444
        r = self.client.list_images(detail=True)
445
        for detailed_img in r:
446
            if detailed_img['id'] == self.img:
447
                break
448
        self.assert_dicts_are_deeply_equal(detailed_img, self.img_details)
449

  
450
    def test_get_image_details(self):
451
        """Test image_details"""
452
        self._test_0150_get_image_details()
453

  
454
    def _test_0150_get_image_details(self):
455
        r = self.client.get_image_details(self.img)
456
        self.assert_dicts_are_deeply_equal(r, self.img_details)
457

  
458
    def test_get_image_metadata(self):
459
        """Test get_image_metadata"""
460
        self._test_0160_get_image_metadata()
461

  
462
    def _test_0160_get_image_metadata(self):
463
        r = self.client.get_image_metadata(self.img)
464
        self.assert_dicts_are_deeply_equal(
465
            self.img_details['metadata']['values'], r)
466
        for key, val in self.img_details['metadata']['values'].items():
467
            r = self.client.get_image_metadata(self.img, key)
468
            self.assertEqual(r[key], val)
469

  
470
    def test_shutdown_server(self):
471
        """Test shutdown_server"""
472
        self.server1 = self._create_server(
473
            self.servname1,
474
            self.flavorid,
475
            self.img)
476
        self._wait_for_status(self.server1['id'], 'BUILD')
477
        self._test_0170_shutdown_server()
478

  
479
    def _test_0170_shutdown_server(self):
480
        self.client.shutdown_server(self.server1['id'])
481
        self._wait_for_status(self.server1['id'], 'ACTIVE')
482
        r = self.client.get_server_details(self.server1['id'])
483
        self.assertEqual(r['status'], 'STOPPED')
484

  
485
    def test_start_server(self):
486
        """Test start_server"""
487
        self.server1 = self._create_server(
488
            self.servname1,
489
            self.flavorid,
490
            self.img)
491
        self._wait_for_status(self.server1['id'], 'BUILD')
492
        self.client.shutdown_server(self.server1['id'])
493
        self._wait_for_status(self.server1['id'], 'ACTIVE')
494
        self._test_0180_start_server()
495

  
496
    def _test_0180_start_server(self):
497
        self.client.start_server(self.server1['id'])
498
        self._wait_for_status(self.server1['id'], 'STOPPED')
499
        r = self.client.get_server_details(self.server1['id'])
500
        self.assertEqual(r['status'], 'ACTIVE')
501

  
502
    def test_get_server_console(self):
503
        """Test get_server_console"""
504
        self.server2 = self._create_server(
505
            self.servname2,
506
            self.flavorid + 2,
507
            self.img)
508
        self._wait_for_status(self.server2['id'], 'BUILD')
509
        self._test_0190_get_server_console()
510

  
511
    def _test_0190_get_server_console(self):
512
        r = self.client.get_server_console(self.server2['id'])
513
        self.assertTrue('host' in r)
514
        self.assertTrue('password' in r)
515
        self.assertTrue('port' in r)
516
        self.assertTrue('type' in r)
517

  
518
    def test_get_firewall_profile(self):
519
        """Test get_firewall_profile"""
520
        self.server1 = self._create_server(
521
            self.servname1,
522
            self.flavorid,
523
            self.img)
524
        self._test_0200_get_firewall_profile()
525

  
526
    def _test_0200_get_firewall_profile(self):
527
        self._wait_for_status(self.server1['id'], 'BUILD')
528
        fprofile = self.client.get_firewall_profile(self.server1['id'])
529
        self.assertTrue(fprofile in self.PROFILES)
530

  
531
    def test_set_firewall_profile(self):
532
        """Test set_firewall_profile"""
533
        self.server1 = self._create_server(
534
            self.servname1,
535
            self.flavorid,
536
            self.img)
537
        self._test_0210_set_firewall_profile()
538

  
539
    def _test_0210_set_firewall_profile(self):
540

  
541
        self._wait_for_status(self.server1['id'], 'BUILD')
542
        PROFILES = ['DISABLED', 'ENABLED', 'DISABLED', 'PROTECTED']
543
        fprofile = self.client.get_firewall_profile(self.server1['id'])
544
        print('')
545
        count_success = 0
546
        for counter, fprofile in enumerate(PROFILES):
547
            npos = counter + 1
548
            try:
549
                nprofile = PROFILES[npos]
550
            except IndexError:
551
                nprofile = PROFILES[0]
552
            print('\tprofile swap %s: %s -> %s' % (npos, fprofile, nprofile))
553
            self.client.set_firewall_profile(self.server1['id'], nprofile)
554
            time.sleep(0.5)
555
            self.client.reboot_server(self.server1['id'], hard=True)
556
            time.sleep(1)
557
            self._wait_for_status(self.server1['id'], 'REBOOT')
558
            time.sleep(0.5)
559
            changed = self.client.get_firewall_profile(self.server1['id'])
560
            try:
561
                self.assertEqual(changed, nprofile)
562
            except AssertionError as err:
563
                if count_success:
564
                    print('\tFAIL in swap #%s' % npos)
565
                    break
566
                else:
567
                    raise err
568
            count_success += 1
569

  
570
    def test_get_server_stats(self):
571
        self.server1 = self._create_server(
572
            self.servname1,
573
            self.flavorid,
574
            self.img)
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff