pwyckoff | 99b000b | 2008-04-03 19:30:55 +0000 | [diff] [blame] | 1 | #!/usr/bin/env python |
| 2 | # |
| 3 | # Copyright (c) 2006- Facebook |
| 4 | # Distributed under the Thrift Software License |
| 5 | # |
| 6 | # See accompanying file LICENSE or visit the Thrift site at: |
| 7 | # http://developers.facebook.com/thrift/ |
| 8 | |
| 9 | import sys, os |
| 10 | from optparse import OptionParser |
| 11 | |
| 12 | from thrift.Thrift import * |
| 13 | |
| 14 | from thrift.transport import TSocket |
| 15 | from thrift.transport import TTransport |
| 16 | from thrift.protocol import TBinaryProtocol |
| 17 | |
| 18 | from fb303 import * |
| 19 | from fb303.ttypes import * |
| 20 | |
| 21 | def service_ctrl( |
| 22 | command, |
| 23 | port, |
| 24 | trans_factory = None, |
| 25 | prot_factory = None): |
| 26 | """ |
| 27 | service_ctrl is a generic function to execute standard fb303 functions |
| 28 | |
| 29 | @param command: one of stop, start, reload, status, counters, name, alive |
| 30 | @param port: service's port |
| 31 | @param trans_factory: TTransportFactory to use for obtaining a TTransport. Default is |
| 32 | TBufferedTransportFactory |
| 33 | @param prot_factory: TProtocolFactory to use for obtaining a TProtocol. Default is |
| 34 | TBinaryProtocolFactory |
| 35 | """ |
| 36 | |
| 37 | # Only root should be able to run these scripts, although we could relax this for some of the operations. |
| 38 | if os.getuid() != 0: |
| 39 | print "requires root." |
| 40 | return 4 |
| 41 | |
| 42 | if command in ["status"]: |
| 43 | try: |
| 44 | status = fb303_wrapper('status', port, trans_factory, prot_factory) |
| 45 | status_details = fb303_wrapper('get_status_details', port, trans_factory, prot_factory) |
| 46 | |
| 47 | msg = fb_status_string(status) |
| 48 | if (len(status_details)): |
| 49 | msg += " - %s" % status_details |
| 50 | print msg |
| 51 | |
| 52 | if (status == fb_status.ALIVE): |
| 53 | return 2 |
| 54 | else: |
| 55 | return 3 |
| 56 | except: |
| 57 | print "Failed to get status" |
| 58 | return 3 |
| 59 | |
| 60 | # async commands |
| 61 | if command in ["stop","reload"]: |
| 62 | try: |
| 63 | fb303_wrapper(command, port, trans_factory, prot_factory) |
| 64 | return 0 |
| 65 | except: |
| 66 | print "failed to tell the service to ", command |
| 67 | return 3 |
| 68 | |
| 69 | # scalar commands |
| 70 | if command in ["version","alive","name"]: |
| 71 | try: |
| 72 | result = fb303_wrapper(command, port, trans_factory, prot_factory) |
| 73 | print result |
| 74 | return 0 |
| 75 | except: |
| 76 | print "failed to get ",command |
| 77 | return 3 |
| 78 | |
| 79 | # counters |
| 80 | if command in ["counters"]: |
| 81 | try: |
| 82 | counters = fb303_wrapper('counters', port, trans_factory, prot_factory) |
| 83 | for counter in counters: |
| 84 | print "%s: %d" % (counter, counters[counter]) |
| 85 | return 0 |
| 86 | except: |
| 87 | print "failed to get counters" |
| 88 | return 3 |
| 89 | |
| 90 | return 0; |
| 91 | |
| 92 | |
| 93 | def fb303_wrapper(command, port, trans_factory = None, prot_factory = None): |
| 94 | sock = TSocket.TSocket('localhost', port) |
| 95 | |
| 96 | # use input transport factory if provided |
| 97 | if (trans_factory is None): |
| 98 | trans = TTransport.TBufferedTransport(sock) |
| 99 | else: |
| 100 | trans = trans_factory.getTransport(sock) |
| 101 | |
| 102 | # use input protocol factory if provided |
| 103 | if (prot_factory is None): |
| 104 | prot = TBinaryProtocol.TBinaryProtocol(trans) |
| 105 | else: |
| 106 | prot = prot_factory.getProtocol(trans) |
| 107 | |
| 108 | # initialize client and open transport |
| 109 | fb303_client = FacebookService.Client(prot, prot) |
| 110 | trans.open() |
| 111 | |
| 112 | if (command == 'reload'): |
| 113 | fb303_client.reinitialize() |
| 114 | |
| 115 | elif (command == 'stop'): |
| 116 | fb303_client.shutdown() |
| 117 | |
| 118 | elif (command == 'status'): |
| 119 | return fb303_client.getStatus() |
| 120 | |
| 121 | elif (command == 'version'): |
| 122 | return fb303_client.getVersion() |
| 123 | |
| 124 | elif (command == 'get_status_details'): |
| 125 | return fb303_client.getStatusDetails() |
| 126 | |
| 127 | elif (command == 'counters'): |
| 128 | return fb303_client.getCounters() |
| 129 | |
| 130 | elif (command == 'name'): |
| 131 | return fb303_client.getName() |
| 132 | |
| 133 | elif (command == 'alive'): |
| 134 | return fb303_client.aliveSince() |
| 135 | |
| 136 | trans.close() |
| 137 | |
| 138 | |
| 139 | def fb_status_string(status_enum): |
| 140 | if (status_enum == fb_status.DEAD): |
| 141 | return "DEAD" |
| 142 | if (status_enum == fb_status.STARTING): |
| 143 | return "STARTING" |
| 144 | if (status_enum == fb_status.ALIVE): |
| 145 | return "ALIVE" |
| 146 | if (status_enum == fb_status.STOPPING): |
| 147 | return "STOPPING" |
| 148 | if (status_enum == fb_status.STOPPED): |
| 149 | return "STOPPED" |
| 150 | if (status_enum == fb_status.WARNING): |
| 151 | return "WARNING" |
| 152 | |
| 153 | |
| 154 | def main(port, command): |
| 155 | status = service_ctrl(options.command, options.port) |
| 156 | sys.exit(status) |
| 157 | |
| 158 | |
| 159 | # parse command line options |
| 160 | parser = OptionParser() |
| 161 | parser.add_option("-c", "--command", dest="command", help="execute this API", choices=["stop","counters","status","reload","version","name","alive"], |
| 162 | default="status") |
| 163 | parser.add_option("-p","--port",dest="port",help="the service's port", default=9082) |
| 164 | |
| 165 | (options, args) = parser.parse_args() |
| 166 | |
| 167 | main(options.port, options.command) |