manhole can now be opend/closed TTW

git-svn-id: svn://svn.cy55.de/Zope3/src/cybertools/trunk@1102 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
helmutm 2006-03-01 10:47:55 +00:00
parent 9f0cfba50d
commit af872764f5
5 changed files with 137 additions and 58 deletions

View file

@ -2,46 +2,3 @@
$Id$ $Id$
""" """
from twisted.internet import reactor, protocol
from twisted.protocols import basic
from twisted.cred import portal, checkers
from twisted.conch import manhole, manhole_ssh
try:
from zope.app.publication.zopepublication import ZopePublication
from zope.app.component.hooks import setSite
hasZope = True
except:
hasZope = False
import time
import sys
from cStringIO import StringIO
def getManholeFactory(namespace, **passwords):
realm = manhole_ssh.TerminalRealm()
def getManhole(_):
return manhole.Manhole(namespace)
realm.chainedProtocolFactory.protocolFactory = getManhole
p = portal.Portal(realm)
p.registerChecker(
checkers.InMemoryUsernamePasswordDatabaseDontUse(**passwords))
return manhole_ssh.ConchFactory(p)
def printTime():
print 'twisted.manhole running:', time.strftime('%H:%M:%S')
reactor.callLater(60, printTime)
#reactor.callLater(10, stopReactor)
#reactor.listenTCP(5222, EchoServerFactory())
def startup(event=None):
printTime()
d = globals()
#d['event'] = event
if hasZope and event is not None:
conn =event.database.open()
root = conn.root()[ZopePublication.root_name]
d.update(locals())
reactor.listenTCP(5001, getManholeFactory(d, admin='aaa'))
if __name__ == '__main__':
startup()

View file

@ -2,10 +2,17 @@
<configure <configure
xmlns="http://namespaces.zope.org/zope" xmlns="http://namespaces.zope.org/zope"
xmlns:browser="http://namespaces.zope.org/browser"
i18n_domain="zope" i18n_domain="zope"
> >
<subscriber handler="cybertools.twisted.manhole.startup" <browser:page
for="zope.app.appsetup.interfaces.IDatabaseOpenedEvent" /> for="zope.app.applicationcontrol.interfaces.IApplicationControl"
name="manhole_control.html"
template="manhole_control.pt"
class=".manhole_control.ManholeControlView"
permission="zope.ManageApplication"
menu="zmi_views" title="Manhole Control"
/>
</configure> </configure>

View file

@ -15,7 +15,10 @@ running the manhole script.
In order to use it with Zope copy the cybertools.twisted-configure.zcml In order to use it with Zope copy the cybertools.twisted-configure.zcml
to the etc/package-includes directory of your Zope instance and restart to the etc/package-includes directory of your Zope instance and restart
Zope. You can then log in with ssh like shown above, using the username Zope. Open the manhole via the "Manhole Control" Tab of the "Manage process"
menu.
You can then log in with ssh like shown above, using the username
and password of the zope.manager principal defined in your principals.zcml. and password of the zope.manager principal defined in your principals.zcml.
After logging in use the `help` command to get more information. After logging in use the `help` command to get more information.
@ -26,12 +29,15 @@ $Id$
from twisted.internet import reactor, protocol, defer from twisted.internet import reactor, protocol, defer
from twisted.protocols import basic from twisted.protocols import basic
from twisted.cred import portal, checkers, credentials, error as credError from twisted.cred import portal, checkers, credentials, error as credError
from twisted.conch import manhole, manhole_ssh from twisted.conch import manhole as manhole, manhole_ssh
from zope.interface import implements from zope.interface import implements
try: try:
from zope.app.publication.zopepublication import ZopePublication from zope.app.publication.zopepublication import ZopePublication
from zope.app.component.hooks import setSite from zope.app.component.hooks import setSite
from zope.app.security.principalregistry import principalRegistry from zope.app.security.principalregistry import principalRegistry
from zope.app.security import settings
from zope.app.security.interfaces import IAuthentication
from zope.app.securitypolicy.principalrole import principalRoleManager
from zope.app import zapi from zope.app import zapi
import transaction import transaction
hasZope = True hasZope = True
@ -41,10 +47,16 @@ import time
import sys import sys
from cStringIO import StringIO from cStringIO import StringIO
listener = None
factory = None
printLog = None
port = 5001
def getManholeFactory(namespace, **passwords): def getManholeFactory(namespace, **passwords):
realm = manhole_ssh.TerminalRealm() realm = manhole_ssh.TerminalRealm()
def getManhole(_): def getManhole(_):
#return manhole.ColoredManhole(namespace)
return manhole.Manhole(namespace) return manhole.Manhole(namespace)
realm.chainedProtocolFactory.protocolFactory = getManhole realm.chainedProtocolFactory.protocolFactory = getManhole
p = portal.Portal(realm) p = portal.Portal(realm)
@ -60,18 +72,26 @@ class ZopeManagerChecker(object):
credentialInterfaces = (credentials.IUsernamePassword,) credentialInterfaces = (credentials.IUsernamePassword,)
def requestAvatarId(self, credentials): def requestAvatarId(self, credentials):
manager = principalRegistry.getPrincipal('zope.manager')
login = credentials.username login = credentials.username
password = credentials.password password = credentials.password
if login == manager.getLogin() and manager.validate(password): # TODO: This should be based on the official Zope API stuff, e.g. via:
#principalRegistry = zapi.getUtility(IAuthentication)
principal = principalRegistry.getPrincipalByLogin(login)
if principal.validate(password):
roles = principalRoleManager.getRolesForPrincipal(principal.id)
for role, setting in roles:
if role == 'zope.Manager' and setting == settings.Allow:
return defer.succeed(login) return defer.succeed(login)
return defer.fail(credError.UnauthorizedLogin(
'Insufficient permissions'))
return defer.fail(credError.UnauthorizedLogin( return defer.fail(credError.UnauthorizedLogin(
'User/password not correct')) 'User/password not correct'))
def printTime(): def printTime():
print 'twisted.manhole running:', time.strftime('%H:%M:%S') global printLog
reactor.callLater(600, printTime) print '***', time.strftime('%H:%M:%S'), '- twisted.manhole open ***'
printLog = reactor.callLater(600, printTime)
class Help(object): class Help(object):
@ -101,23 +121,32 @@ class Help(object):
help = Help() help = Help()
def startup(event=None, port=5001): def open(port=5001, request=None):
global hasZope global hasZope, factory, listener
printTime() printTime()
d = globals() d = globals()
if hasZope and event is not None: if hasZope and request is not None:
connection = event.database.open() database = request.publication.db
connection = database.open()
root = connection.root()[ZopePublication.root_name] root = connection.root()[ZopePublication.root_name]
else: else:
hasZope = False hasZope = False
d.update(locals()) d.update(locals())
namespace = {} namespace = {}
for key in ('__builtins__', 'connection', 'event', 'setSite', 'hasZope', for key in ('__builtins__', 'connection', 'event', 'setSite', 'hasZope',
'zapi', 'transaction', 'root', '__doc__', 'help'): 'zapi', 'transaction', 'root', '__doc__', 'help',
'manholeFactory', 'context'):
if key in d: if key in d:
namespace[key] = d[key] namespace[key] = d[key]
# TODO: get admin password from somewhere else or use a real checker. # TODO: get admin password from somewhere else or use a real checker.
reactor.listenTCP(port, getManholeFactory(namespace, admin='aaa')) factory = getManholeFactory(namespace, admin='aaa')
listener = reactor.listenTCP(port, factory)
def close():
global listener
listener.stopListening()
listener = None
if __name__ == '__main__': if __name__ == '__main__':
port = 5001 port = 5001

View file

@ -0,0 +1,43 @@
<html metal:use-macro="context/@@standard_macros/view"
i18n:domain="zope">
<head>
<title i18n:translate="">ZODB Controller</title>
</head>
<body>
<div metal:fill-slot="body">
<tal:update condition="view/update" />
<div class="row" tal:condition="view/isOpen">
<div class="field" i18n:translate="">Manhole is open.</div>
</div>
<div class="row" tal:condition="not:view/isOpen">
<div class="field" i18n:translate="">Manhole is closed.</div>
</div>
<form action="." method="post" tal:attributes="action request/URL">
<input type="hidden" name="form_submitted" value="true" />
<div class="row">
<span class="label"
i18n:translate="">Port</span>:
<input type="text" size="5" name="manhole.port"
tal:attributes="value view/port" />
</div>
<div class="row">
<input type="checkbox" size="5" name="manhole.setting" value="true" />
<span class="label" i18n:translate=""
tal:condition="not:view/isOpen">Open manhole</span>
<span class="label" i18n:translate=""
tal:condition="view/isOpen">Close manhole</span>
</div>
<div class="row">
<div class="controls">
<input type="submit" name="APPLY" value="Apply"
i18n:attributes="value apply-button"/>
</div>
</div>
</form>
</div>
</body>
</html>

View file

@ -0,0 +1,43 @@
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
""" Manhole Control View
$Id$
"""
__docformat__ = 'restructuredtext'
from cybertools.twisted import manhole
class ManholeControlView(object):
def isOpen(self):
return manhole.listener is not None
def toggleState(self):
if self.isOpen():
manhole.close()
else:
manhole.open(self.port(), self.request)
def port(self):
return manhole.port
def update(self):
if not self.request.get('form_submitted'):
return
port = self.request.get('manhole.port')
if port:
manhole.port = int(port)
if self.request.get('manhole.setting', False):
self.toggleState()