~ubuntu-branches/ubuntu/wily/heat/wily

« back to all changes in this revision

Viewing changes to heat/openstack/common/eventlet_backdoor.py

  • Committer: Package Import Robot
  • Author(s): Corey Bryant, Corey Bryant, James Page
  • Date: 2015-07-07 17:06:19 UTC
  • mfrom: (1.1.26) (45.1.1 vivid-proposed)
  • Revision ID: package-import@ubuntu.com-20150707170619-hra2dbjpfofpou4s
Tags: 1:5.0.0~b1-0ubuntu1
[ Corey Bryant ]
* New upstream milestone for OpenStack Liberty:
  - d/control: Align (build-)depends with upstream.
  - d/p/fix-requirements.patch: Rebased.
  - d/p/sudoers_patch.patch: Rebased.

[ James Page ]
* d/s/options: Ignore any removal of egg-info data during package clean.
* d/control: Drop MySQL and PostgreSQL related BD's, not required for unit
  testing.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (c) 2012 OpenStack Foundation.
2
 
# Administrator of the National Aeronautics and Space Administration.
3
 
# All Rights Reserved.
4
 
#
5
 
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
6
 
#    not use this file except in compliance with the License. You may obtain
7
 
#    a copy of the License at
8
 
#
9
 
#         http://www.apache.org/licenses/LICENSE-2.0
10
 
#
11
 
#    Unless required by applicable law or agreed to in writing, software
12
 
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13
 
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14
 
#    License for the specific language governing permissions and limitations
15
 
#    under the License.
16
 
 
17
 
from __future__ import print_function
18
 
 
19
 
import copy
20
 
import errno
21
 
import gc
22
 
import logging
23
 
import os
24
 
import pprint
25
 
import socket
26
 
import sys
27
 
import traceback
28
 
 
29
 
import eventlet.backdoor
30
 
import greenlet
31
 
from oslo_config import cfg
32
 
 
33
 
from heat.openstack.common._i18n import _LI
34
 
 
35
 
help_for_backdoor_port = (
36
 
    "Acceptable values are 0, <port>, and <start>:<end>, where 0 results "
37
 
    "in listening on a random tcp port number; <port> results in listening "
38
 
    "on the specified port number (and not enabling backdoor if that port "
39
 
    "is in use); and <start>:<end> results in listening on the smallest "
40
 
    "unused port number within the specified range of port numbers.  The "
41
 
    "chosen port is displayed in the service's log file.")
42
 
eventlet_backdoor_opts = [
43
 
    cfg.StrOpt('backdoor_port',
44
 
               help="Enable eventlet backdoor.  %s" % help_for_backdoor_port)
45
 
]
46
 
 
47
 
CONF = cfg.CONF
48
 
CONF.register_opts(eventlet_backdoor_opts)
49
 
LOG = logging.getLogger(__name__)
50
 
 
51
 
 
52
 
def list_opts():
53
 
    """Entry point for oslo-config-generator.
54
 
    """
55
 
    return [(None, copy.deepcopy(eventlet_backdoor_opts))]
56
 
 
57
 
 
58
 
class EventletBackdoorConfigValueError(Exception):
59
 
    def __init__(self, port_range, help_msg, ex):
60
 
        msg = ('Invalid backdoor_port configuration %(range)s: %(ex)s. '
61
 
               '%(help)s' %
62
 
               {'range': port_range, 'ex': ex, 'help': help_msg})
63
 
        super(EventletBackdoorConfigValueError, self).__init__(msg)
64
 
        self.port_range = port_range
65
 
 
66
 
 
67
 
def _dont_use_this():
68
 
    print("Don't use this, just disconnect instead")
69
 
 
70
 
 
71
 
def _find_objects(t):
72
 
    return [o for o in gc.get_objects() if isinstance(o, t)]
73
 
 
74
 
 
75
 
def _print_greenthreads():
76
 
    for i, gt in enumerate(_find_objects(greenlet.greenlet)):
77
 
        print(i, gt)
78
 
        traceback.print_stack(gt.gr_frame)
79
 
        print()
80
 
 
81
 
 
82
 
def _print_nativethreads():
83
 
    for threadId, stack in sys._current_frames().items():
84
 
        print(threadId)
85
 
        traceback.print_stack(stack)
86
 
        print()
87
 
 
88
 
 
89
 
def _parse_port_range(port_range):
90
 
    if ':' not in port_range:
91
 
        start, end = port_range, port_range
92
 
    else:
93
 
        start, end = port_range.split(':', 1)
94
 
    try:
95
 
        start, end = int(start), int(end)
96
 
        if end < start:
97
 
            raise ValueError
98
 
        return start, end
99
 
    except ValueError as ex:
100
 
        raise EventletBackdoorConfigValueError(port_range, ex,
101
 
                                               help_for_backdoor_port)
102
 
 
103
 
 
104
 
def _listen(host, start_port, end_port, listen_func):
105
 
    try_port = start_port
106
 
    while True:
107
 
        try:
108
 
            return listen_func((host, try_port))
109
 
        except socket.error as exc:
110
 
            if (exc.errno != errno.EADDRINUSE or
111
 
               try_port >= end_port):
112
 
                raise
113
 
            try_port += 1
114
 
 
115
 
 
116
 
def initialize_if_enabled():
117
 
    backdoor_locals = {
118
 
        'exit': _dont_use_this,      # So we don't exit the entire process
119
 
        'quit': _dont_use_this,      # So we don't exit the entire process
120
 
        'fo': _find_objects,
121
 
        'pgt': _print_greenthreads,
122
 
        'pnt': _print_nativethreads,
123
 
    }
124
 
 
125
 
    if CONF.backdoor_port is None:
126
 
        return None
127
 
 
128
 
    start_port, end_port = _parse_port_range(str(CONF.backdoor_port))
129
 
 
130
 
    # NOTE(johannes): The standard sys.displayhook will print the value of
131
 
    # the last expression and set it to __builtin__._, which overwrites
132
 
    # the __builtin__._ that gettext sets. Let's switch to using pprint
133
 
    # since it won't interact poorly with gettext, and it's easier to
134
 
    # read the output too.
135
 
    def displayhook(val):
136
 
        if val is not None:
137
 
            pprint.pprint(val)
138
 
    sys.displayhook = displayhook
139
 
 
140
 
    sock = _listen('localhost', start_port, end_port, eventlet.listen)
141
 
 
142
 
    # In the case of backdoor port being zero, a port number is assigned by
143
 
    # listen().  In any case, pull the port number out here.
144
 
    port = sock.getsockname()[1]
145
 
    LOG.info(
146
 
        _LI('Eventlet backdoor listening on %(port)s for process %(pid)d') %
147
 
        {'port': port, 'pid': os.getpid()}
148
 
    )
149
 
    eventlet.spawn_n(eventlet.backdoor.backdoor_server, sock,
150
 
                     locals=backdoor_locals)
151
 
    return port