Thrift now a TLP - INFRA-3116

git-svn-id: https://svn.apache.org/repos/asf/thrift/branches/0.1.x@1028168 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/contrib/fb303/py/Makefile.am b/contrib/fb303/py/Makefile.am
new file mode 100644
index 0000000..060495e
--- /dev/null
+++ b/contrib/fb303/py/Makefile.am
@@ -0,0 +1,44 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+#
+
+DESTDIR ?= /
+EXTRA_DIST = setup.py src
+
+all:
+
+all-local:
+	$(thrift_home)/bin/thrift --gen py $(top_srcdir)/if/fb303.thrift
+	mv gen-py/fb303/* fb303
+	$(PYTHON) setup.py build
+
+# We're ignoring prefix here because site-packages seems to be
+# the equivalent of /usr/local/lib in Python land.
+# Old version (can't put inline because it's not portable).
+#$(PYTHON) setup.py install --prefix=$(prefix) --root=$(DESTDIR) $(PYTHON_SETUPUTIL_ARGS)
+install-exec-hook:
+	$(PYTHON) setup.py install --root=$(DESTDIR) --prefix=$(PY_PREFIX) $(PYTHON_SETUPUTIL_ARGS)
+
+
+
+clean:	clean-local
+
+clean-local:
+	$(RM) -r build
+
+check-local: all
diff --git a/contrib/fb303/py/fb303/FacebookBase.py b/contrib/fb303/py/fb303/FacebookBase.py
new file mode 100644
index 0000000..685ff20
--- /dev/null
+++ b/contrib/fb303/py/fb303/FacebookBase.py
@@ -0,0 +1,82 @@
+#!/usr/bin/env python
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+#
+
+import time
+import FacebookService
+import thrift.reflection.limited
+from ttypes import fb_status
+
+class FacebookBase(FacebookService.Iface):
+
+  def __init__(self, name):
+    self.name = name
+    self.alive = int(time.time())
+    self.counters = {}
+
+  def getName(self, ):
+    return self.name
+
+  def getVersion(self, ):
+    return ''
+
+  def getStatus(self, ):
+    return fb_status.ALIVE
+
+  def getCounters(self):
+    return self.counters
+
+  def resetCounter(self, key):
+    self.counters[key] = 0
+
+  def getCounter(self, key):
+    if self.counters.has_key(key):
+      return self.counters[key]
+    return 0
+
+  def incrementCounter(self, key):
+    self.counters[key] = self.getCounter(key) + 1
+
+  def setOption(self, key, value):
+    pass
+
+  def getOption(self, key):
+    return ""
+
+  def getOptions(self):
+    return {}
+
+  def getOptions(self):
+    return {}
+
+  def aliveSince(self):
+    return self.alive
+
+  def getCpuProfile(self, duration):
+    return ""
+
+  def getLimitedReflection(self):
+    return thrift.reflection.limited.Service()
+
+  def reinitialize(self):
+    pass
+
+  def shutdown(self):
+    pass
diff --git a/contrib/fb303/py/fb303_scripts/__init__.py b/contrib/fb303/py/fb303_scripts/__init__.py
new file mode 100644
index 0000000..f8e3a94
--- /dev/null
+++ b/contrib/fb303/py/fb303_scripts/__init__.py
@@ -0,0 +1,20 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+#
+
+__all__ = ['fb303_simple_mgmt']
diff --git a/contrib/fb303/py/fb303_scripts/fb303_simple_mgmt.py b/contrib/fb303/py/fb303_scripts/fb303_simple_mgmt.py
new file mode 100644
index 0000000..4f8ce99
--- /dev/null
+++ b/contrib/fb303/py/fb303_scripts/fb303_simple_mgmt.py
@@ -0,0 +1,195 @@
+#!/usr/bin/env python
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+#
+
+import sys, os
+from optparse import OptionParser
+
+from thrift.Thrift import *
+
+from thrift.transport import TSocket
+from thrift.transport import TTransport
+from thrift.protocol import TBinaryProtocol
+
+from fb303 import *
+from fb303.ttypes import *
+
+def service_ctrl(
+                 command,
+                 port,
+                 trans_factory = None,
+                 prot_factory = None):
+    """
+    service_ctrl is a generic function to execute standard fb303 functions
+
+    @param command: one of stop, start, reload, status, counters, name, alive
+    @param port: service's port
+    @param trans_factory: TTransportFactory to use for obtaining a TTransport. Default is
+                          TBufferedTransportFactory
+    @param prot_factory: TProtocolFactory to use for obtaining a TProtocol. Default is
+                         TBinaryProtocolFactory
+    """
+
+    if command in ["status"]:
+        try:
+            status = fb303_wrapper('status', port, trans_factory, prot_factory)
+            status_details = fb303_wrapper('get_status_details', port, trans_factory, prot_factory)
+
+            msg = fb_status_string(status)
+            if (len(status_details)):
+                msg += " - %s" % status_details
+            print msg
+
+            if (status == fb_status.ALIVE):
+                return 2
+            else:
+                return 3
+        except:
+            print "Failed to get status"
+            return 3
+
+    # scalar commands
+    if command in ["version","alive","name"]:
+        try:
+            result = fb303_wrapper(command,  port, trans_factory, prot_factory)
+            print result
+            return 0
+        except:
+            print "failed to get ",command
+            return 3
+
+    # counters
+    if command in ["counters"]:
+        try:
+            counters = fb303_wrapper('counters',  port, trans_factory, prot_factory)
+            for counter in counters:
+                print "%s: %d" % (counter, counters[counter])
+            return 0
+        except:
+            print "failed to get counters"
+            return 3
+
+
+    # Only root should be able to run the following commands
+    if os.getuid() == 0:
+        # async commands
+        if command in ["stop","reload"] :
+            try:
+                fb303_wrapper(command, port, trans_factory, prot_factory)
+                return 0
+            except:
+                print "failed to tell the service to ", command
+                return 3
+    else:
+        if command in ["stop","reload"]:
+            print "root privileges are required to stop or reload the service."
+            return 4
+
+    print "The following commands are available:"
+    for command in ["counters","name","version","alive","status"]:
+        print "\t%s" % command
+    print "The following commands are available for users with root privileges:"
+    for command in ["stop","reload"]:
+        print "\t%s" % command
+
+
+
+    return 0;
+
+
+def fb303_wrapper(command, port, trans_factory = None, prot_factory = None):
+    sock = TSocket.TSocket('localhost', port)
+
+    # use input transport factory if provided
+    if (trans_factory is None):
+        trans = TTransport.TBufferedTransport(sock)
+    else:
+        trans = trans_factory.getTransport(sock)
+
+    # use input protocol factory if provided
+    if (prot_factory is None):
+        prot = TBinaryProtocol.TBinaryProtocol(trans)
+    else:
+        prot = prot_factory.getProtocol(trans)
+
+    # initialize client and open transport
+    fb303_client = FacebookService.Client(prot, prot)
+    trans.open()
+
+    if (command == 'reload'):
+        fb303_client.reinitialize()
+
+    elif (command == 'stop'):
+        fb303_client.shutdown()
+
+    elif (command == 'status'):
+        return fb303_client.getStatus()
+
+    elif (command == 'version'):
+        return fb303_client.getVersion()
+
+    elif (command == 'get_status_details'):
+        return fb303_client.getStatusDetails()
+
+    elif (command == 'counters'):
+        return fb303_client.getCounters()
+
+    elif (command == 'name'):
+        return fb303_client.getName()
+
+    elif (command == 'alive'):
+        return fb303_client.aliveSince()
+
+    trans.close()
+
+
+def fb_status_string(status_enum):
+    if (status_enum == fb_status.DEAD):
+        return "DEAD"
+    if (status_enum == fb_status.STARTING):
+        return "STARTING"
+    if (status_enum == fb_status.ALIVE):
+        return "ALIVE"
+    if (status_enum == fb_status.STOPPING):
+        return "STOPPING"
+    if (status_enum == fb_status.STOPPED):
+        return "STOPPED"
+    if (status_enum == fb_status.WARNING):
+        return "WARNING"
+
+
+def main():
+
+    # parse command line options
+    parser = OptionParser()
+    commands=["stop","counters","status","reload","version","name","alive"]
+
+    parser.add_option("-c", "--command", dest="command", help="execute this API",
+                      choices=commands, default="status")
+    parser.add_option("-p","--port",dest="port",help="the service's port",
+                      default=9082)
+
+    (options, args) = parser.parse_args()
+    status = service_ctrl(options.command, options.port)
+    sys.exit(status)
+
+
+if __name__ == '__main__':
+    main()
diff --git a/contrib/fb303/py/setup.py b/contrib/fb303/py/setup.py
new file mode 100644
index 0000000..a29f964
--- /dev/null
+++ b/contrib/fb303/py/setup.py
@@ -0,0 +1,27 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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 distutils.core import setup
+
+setup(name='fb303',
+      version='1.0',
+      packages=['fb303', 'fb303_scripts'],
+      )
+
+