~ubuntu-branches/ubuntu/trusty/drizzle/trusty

« back to all changes in this revision

Viewing changes to tests/kewpie/lib/sys_mgmt/port_management.py

  • Committer: Package Import Robot
  • Author(s): Clint Byrum
  • Date: 2012-06-19 10:46:49 UTC
  • mfrom: (1.1.6)
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20120619104649-e2l0ggd4oz3um0f4
Tags: upstream-7.1.36-stable
ImportĀ upstreamĀ versionĀ 7.1.36-stable

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#! /usr/bin/env python
 
2
# -*- mode: python; indent-tabs-mode: nil; -*-
 
3
# vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
 
4
#
 
5
# Copyright (C) 2010 Patrick Crews
 
6
#
 
7
# This program is free software; you can redistribute it and/or modify
 
8
# it under the terms of the GNU General Public License as published by
 
9
# the Free Software Foundation; either version 2 of the License, or
 
10
# (at your option) any later version.
 
11
#
 
12
# This program is distributed in the hope that it will be useful,
 
13
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
# GNU General Public License for more details.
 
16
#
 
17
# You should have received a copy of the GNU General Public License
 
18
# along with this program; if not, write to the Free Software
 
19
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
20
 
 
21
"""port_management.py
 
22
   code for dealing with the various tasks
 
23
   around handing out and managing server ports
 
24
   that we need to run tests
 
25
 
 
26
"""
 
27
 
 
28
# imports
 
29
import os
 
30
import sys
 
31
 
 
32
class portManager:
 
33
    """ class for doing the work of handing out and tracking ports """
 
34
    def __init__(self, system_manager, debug = 0):
 
35
        # This is a file that can be read into a dictionary
 
36
        # it is in port:owner format
 
37
        self.skip_keys = [ 'port_file_delimiter'
 
38
                         , 'system_manager'
 
39
                         ]
 
40
        self.working_dir = "/tmp"
 
41
        self.file_prefix = "dbqp_port"
 
42
        self.port_file_delimiter = ':' # what we use to separate port:owner 
 
43
        self.debug = debug
 
44
        self.logging = system_manager.logging
 
45
        self.system_manager = system_manager
 
46
        self.logging.debug_class(self)
 
47
        
 
48
 
 
49
    def get_port_block(self, requester, base_port, block_size):
 
50
        """ Try to return a block of ports of size
 
51
            block_size, starting with base_port
 
52
 
 
53
            We take a target port and increment it
 
54
            until we find an unused port.  We make
 
55
            no guarantee of continuous ports, only
 
56
            that we will try to return block_size
 
57
            ports for use
 
58
    
 
59
            We can probably get fancier / smarter in the future
 
60
            but this should work for now :-/
 
61
 
 
62
        """
 
63
        assigned_ports = []
 
64
        current_port = base_port
 
65
        while len(assigned_ports) != block_size:
 
66
            new_port = (self.get_port(requester, current_port))
 
67
            assigned_ports.append(new_port)
 
68
            current_port = new_port+1
 
69
        return assigned_ports
 
70
 
 
71
    def get_port(self, requester, desired_port):
 
72
        """ Try to lock in the desired_port
 
73
            if not, we increment the value until
 
74
            we find an unused port.
 
75
            We take max / min port values from test-run.pl
 
76
            This is a bit bobo, but will work for now...
 
77
 
 
78
        """
 
79
        searching_for_port = 1
 
80
        attempt_count = 5000
 
81
        attempts_remain = attempt_count
 
82
        max_port_value = 32767
 
83
        min_port_value = 5001
 
84
        while searching_for_port and attempts_remain:
 
85
            # Check if the port is used
 
86
            if self.check_port_status(desired_port): 
 
87
                # assign it
 
88
                self.assign_port(requester, desired_port)
 
89
                return desired_port
 
90
            else: # increment the port and try again
 
91
                desired_port = desired_port + 1
 
92
                if desired_port >= max_port_value:
 
93
                    desired_port = min_port_value
 
94
                attempts_remain = attempts_remain - 1
 
95
        self.logging.error("Failed to assign a port in %d attempts" %attempt_count)
 
96
        sys.exit(1)
 
97
 
 
98
    def check_port_status(self, port):
 
99
        """ Check if a port is in use, via the port files
 
100
            which all copies of dbqp.py should use
 
101
 
 
102
            Not *really* sure how well this works with multiple
 
103
            dbqp.py instances...we'll see if we even need it 
 
104
            to work 
 
105
 
 
106
        """
 
107
        # check existing ports dbqp has created
 
108
        dbqp_ports = self.check_dbqp_ports()
 
109
        if port not in dbqp_ports and not self.is_port_used(port):
 
110
            return 1
 
111
        else:
 
112
            return 0
 
113
 
 
114
    def is_port_used(self, port):
 
115
        """ See if a given port is used on the system """
 
116
        retcode, output = self.system_manager.execute_cmd("netstat -lant")
 
117
        # parse our output
 
118
        entry_list = output.split("\n")
 
119
        good_data = 0
 
120
        for entry in entry_list:
 
121
            if entry.startswith('Proto'):
 
122
                good_data = 1
 
123
            elif good_data:
 
124
                # We try to catch additional output
 
125
                # like we see with freebsd
 
126
                if entry.startswith('Active'):
 
127
                    good_data = 0
 
128
                    pass
 
129
                else:
 
130
                    if self.system_manager.cur_os in [ 'FreeBSD' 
 
131
                                                     , 'Darwin' 
 
132
                                                     ]:
 
133
                        split_token = '.'
 
134
                    else:
 
135
                        split_token = ':'
 
136
                    port_candidate = entry.split()[3].split(split_token)[-1].strip()
 
137
                    if port_candidate.isdigit():
 
138
                        used_port = int(port_candidate)
 
139
                    else:
 
140
                        used_port = None # not a value we can use
 
141
                if port == used_port:
 
142
                    if entry.split()[-1] != "TIME_WAIT":
 
143
                        return 1
 
144
        return 0
 
145
 
 
146
    
 
147
 
 
148
    def check_dbqp_ports(self):
 
149
        """ Scan the files in /tmp for those files named
 
150
            dbqp_port_NNNN.  Existence indicates said port is 'locked'
 
151
 
 
152
        """
 
153
        used_ports = []
 
154
        tmp_files = os.listdir('/tmp')
 
155
        for tmp_file in tmp_files:
 
156
            if tmp_file.startswith('dbqp_port'):
 
157
                used_ports.append(int(tmp_file.split('_')[-1]))
 
158
        return used_ports
 
159
 
 
160
    def assign_port(self, owner, port):
 
161
        """Assigns a port - create a tmpfile
 
162
           with a name that 'logs' the port
 
163
           as being used
 
164
 
 
165
        """
 
166
 
 
167
        out_file = open(self.get_file_name(port),'w')
 
168
        out_file.write("%s:%d\n" %(owner, port))
 
169
        out_file.close()
 
170
 
 
171
    def free_ports(self, portlist):
 
172
       """ Clean up our ports """
 
173
       for port in portlist:
 
174
          self.free_port(port)
 
175
 
 
176
    def free_port(self, port):
 
177
       """ Free a single port - we delete the file
 
178
           that 'locks' it
 
179
 
 
180
       """
 
181
      
 
182
       self.logging.debug("Freeing port %d" %(port))
 
183
       try:
 
184
           os.remove(self.get_file_name(port))
 
185
       except OSError:
 
186
           pass
 
187
 
 
188
    def get_file_name(self, port):
 
189
        """ We generate a file name for the port """
 
190
      
 
191
        port_file_name = "%s_%s_%d" %(self.file_prefix, self.system_manager.cur_user, port )
 
192
        return os.path.join(self.working_dir, port_file_name)
 
193
        
 
194
       
 
195
       
 
196