File: test_container_failures.py

package info (click to toggle)
swift 2.2.0-1%2Bdeb8u1
  • links: PTS, VCS
  • area: main
  • in suites: jessie
  • size: 7,652 kB
  • ctags: 8,973
  • sloc: python: 91,651; sh: 668; makefile: 49
file content (171 lines) | stat: -rwxr-xr-x 7,316 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
#!/usr/bin/python -u
# Copyright (c) 2010-2012 OpenStack Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from os import listdir
from os.path import join as path_join
from unittest import main, TestCase
from uuid import uuid4

from eventlet import GreenPool, Timeout
import eventlet
from sqlite3 import connect
from swiftclient import client

from swift.common import direct_client
from swift.common.exceptions import ClientException
from swift.common.utils import hash_path, readconf
from test.probe.common import get_to_final_state, kill_nonprimary_server, \
    kill_server, kill_servers, reset_environment, start_server

eventlet.monkey_patch(all=False, socket=True)


def get_db_file_path(obj_dir):
    files = sorted(listdir(obj_dir), reverse=True)
    for filename in files:
        if filename.endswith('db'):
            return path_join(obj_dir, filename)


class TestContainerFailures(TestCase):

    def setUp(self):
        (self.pids, self.port2server, self.account_ring, self.container_ring,
         self.object_ring, self.policy, self.url, self.token,
         self.account, self.configs) = reset_environment()

    def tearDown(self):
        kill_servers(self.port2server, self.pids)

    def test_one_node_fails(self):
        # Create container1
        # Kill container1 servers excepting two of the primaries
        # Delete container1
        # Restart other container1 primary server
        # Create container1/object1 (allowed because at least server thinks the
        #   container exists)
        # Get to a final state
        # Assert all container1 servers indicate container1 is alive and
        #   well with object1
        # Assert account level also indicates container1 is alive and
        #   well with object1
        container1 = 'container-%s' % uuid4()
        cpart, cnodes = self.container_ring.get_nodes(self.account, container1)
        client.put_container(self.url, self.token, container1)
        kill_nonprimary_server(cnodes, self.port2server, self.pids)
        kill_server(cnodes[0]['port'], self.port2server, self.pids)
        client.delete_container(self.url, self.token, container1)
        start_server(cnodes[0]['port'], self.port2server, self.pids)
        client.put_object(self.url, self.token, container1, 'object1', '123')
        get_to_final_state()
        for cnode in cnodes:
            self.assertEquals(
                [o['name'] for o in direct_client.direct_get_container(
                    cnode, cpart, self.account, container1)[1]],
                ['object1'])
        headers, containers = client.get_account(self.url, self.token)
        self.assertEquals(headers['x-account-container-count'], '1')
        self.assertEquals(headers['x-account-object-count'], '1')
        self.assertEquals(headers['x-account-bytes-used'], '3')

    def test_two_nodes_fail(self):
        # Create container1
        # Kill container1 servers excepting one of the primaries
        # Delete container1 directly to the one primary still up
        # Restart other container1 servers
        # Get to a final state
        # Assert all container1 servers indicate container1 is gone (happens
        #   because the one node that knew about the delete replicated to the
        #   others.)
        # Assert account level also indicates container1 is gone
        container1 = 'container-%s' % uuid4()
        cpart, cnodes = self.container_ring.get_nodes(self.account, container1)
        client.put_container(self.url, self.token, container1)
        cnp_port = kill_nonprimary_server(cnodes, self.port2server, self.pids)
        kill_server(cnodes[0]['port'], self.port2server, self.pids)
        kill_server(cnodes[1]['port'], self.port2server, self.pids)
        direct_client.direct_delete_container(cnodes[2], cpart, self.account,
                                              container1)
        start_server(cnodes[0]['port'], self.port2server, self.pids)
        start_server(cnodes[1]['port'], self.port2server, self.pids)
        start_server(cnp_port, self.port2server, self.pids)
        get_to_final_state()
        for cnode in cnodes:
            exc = None
            try:
                direct_client.direct_get_container(cnode, cpart, self.account,
                                                   container1)
            except ClientException as err:
                exc = err
            self.assertEquals(exc.http_status, 404)
        headers, containers = client.get_account(self.url, self.token)
        self.assertEquals(headers['x-account-container-count'], '0')
        self.assertEquals(headers['x-account-object-count'], '0')
        self.assertEquals(headers['x-account-bytes-used'], '0')

    def _get_container_db_files(self, container):
        opart, onodes = self.container_ring.get_nodes(self.account, container)
        onode = onodes[0]
        db_files = []
        for onode in onodes:
            node_id = (onode['port'] - 6000) / 10
            device = onode['device']
            hash_str = hash_path(self.account, container)
            server_conf = readconf(self.configs['container-server'][node_id])
            devices = server_conf['app:container-server']['devices']
            obj_dir = '%s/%s/containers/%s/%s/%s/' % (devices,
                                                      device, opart,
                                                      hash_str[-3:], hash_str)
            db_files.append(get_db_file_path(obj_dir))

        return db_files

    def test_locked_container_dbs(self):

        def run_test(num_locks, catch_503):
            container = 'container-%s' % uuid4()
            client.put_container(self.url, self.token, container)
            db_files = self._get_container_db_files(container)
            db_conns = []
            for i in range(num_locks):
                db_conn = connect(db_files[i])
                db_conn.execute('begin exclusive transaction')
                db_conns.append(db_conn)
            if catch_503:
                exc = None
                try:
                    client.delete_container(self.url, self.token, container)
                except client.ClientException as err:
                    exc = err
                self.assertEquals(exc.http_status, 503)
            else:
                client.delete_container(self.url, self.token, container)

        pool = GreenPool()
        try:
            with Timeout(15):
                pool.spawn(run_test, 1, False)
                pool.spawn(run_test, 2, True)
                pool.spawn(run_test, 3, True)
                pool.waitall()
        except Timeout as err:
            raise Exception(
                "The server did not return a 503 on container db locks, "
                "it just hangs: %s" % err)


if __name__ == '__main__':
    main()