Remove ajaxterm from Nova
Removes copy of ajaxterm code, nova-ajax-console-proxy, and support for get_ajax_console from Nova proper. Implements blueprint remove-ajaxterm Fixes bug 917963 Change-Id: I2c0ff427c53c0f63a18b10475d6b4cbe9a085d83
This commit is contained in:
parent
ae377f42e9
commit
71410724cd
|
@ -1,146 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
# pylint: disable=C0103
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2010 United States Government as represented by the
|
||||
# Administrator of the National Aeronautics and Space Administration.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed 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.
|
||||
|
||||
"""Ajax Console Proxy Server"""
|
||||
|
||||
from eventlet import greenthread
|
||||
from eventlet.green import urllib2
|
||||
|
||||
import exceptions
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import urlparse
|
||||
|
||||
# If ../nova/__init__.py exists, add ../ to Python search path, so that
|
||||
# it will override what happens to be installed in /usr/(local/)lib/python...
|
||||
possible_topdir = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]),
|
||||
os.pardir,
|
||||
os.pardir))
|
||||
if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')):
|
||||
sys.path.insert(0, possible_topdir)
|
||||
|
||||
|
||||
from nova import flags
|
||||
from nova import log as logging
|
||||
from nova.openstack.common import cfg
|
||||
from nova import rpc
|
||||
from nova import service
|
||||
from nova import utils
|
||||
from nova import wsgi
|
||||
|
||||
|
||||
ajax_console_idle_timeout_opt = \
|
||||
cfg.IntOpt('ajax_console_idle_timeout',
|
||||
default=300,
|
||||
help='Seconds before idle connection destroyed')
|
||||
|
||||
FLAGS = flags.FLAGS
|
||||
FLAGS.add_option(ajax_console_idle_timeout_opt)
|
||||
|
||||
LOG = logging.getLogger('nova.ajax_console_proxy')
|
||||
|
||||
|
||||
class AjaxConsoleProxy(object):
|
||||
tokens = {}
|
||||
|
||||
def __call__(self, env, start_response):
|
||||
try:
|
||||
if 'QUERY_STRING' in env:
|
||||
req_url = '%s://%s%s?%s' % (env['wsgi.url_scheme'],
|
||||
env['HTTP_HOST'],
|
||||
env['PATH_INFO'],
|
||||
env['QUERY_STRING'])
|
||||
else:
|
||||
req_url = '%s://%s%s' % (env['wsgi.url_scheme'],
|
||||
env['HTTP_HOST'],
|
||||
env['PATH_INFO'])
|
||||
|
||||
if 'HTTP_REFERER' in env:
|
||||
auth_url = env['HTTP_REFERER']
|
||||
else:
|
||||
auth_url = req_url
|
||||
|
||||
auth_params = urlparse.parse_qs(urlparse.urlparse(auth_url).query)
|
||||
parsed_url = urlparse.urlparse(req_url)
|
||||
|
||||
auth_info = AjaxConsoleProxy.tokens[auth_params['token'][0]]
|
||||
args = auth_info['args']
|
||||
auth_info['last_activity'] = time.time()
|
||||
|
||||
remote_url = ("http://%s:%s%s?token=%s" % (
|
||||
str(args['host']),
|
||||
str(args['port']),
|
||||
parsed_url.path,
|
||||
str(args['token'])))
|
||||
|
||||
opener = urllib2.urlopen(remote_url, env['wsgi.input'].read())
|
||||
body = opener.read()
|
||||
info = opener.info()
|
||||
|
||||
start_response("200 OK", info.dict.items())
|
||||
return body
|
||||
except (exceptions.KeyError):
|
||||
if env['PATH_INFO'] != '/favicon.ico':
|
||||
LOG.audit("Unauthorized request %s, %s"
|
||||
% (req_url, str(env)))
|
||||
start_response("401 NOT AUTHORIZED", [])
|
||||
return "Not Authorized"
|
||||
except Exception, exc:
|
||||
LOG.exception(exc)
|
||||
start_response("500 ERROR", [])
|
||||
return "Server Error"
|
||||
|
||||
def register_listeners(self):
|
||||
class TopicProxy():
|
||||
@staticmethod
|
||||
def authorize_ajax_console(context, **kwargs):
|
||||
AjaxConsoleProxy.tokens[kwargs['token']] = \
|
||||
{'args': kwargs, 'last_activity': time.time()}
|
||||
|
||||
self.conn = rpc.create_connection(new=True)
|
||||
self.conn.create_consumer(
|
||||
FLAGS.ajax_console_proxy_topic,
|
||||
TopicProxy)
|
||||
|
||||
def delete_expired_tokens():
|
||||
now = time.time()
|
||||
to_delete = []
|
||||
for k, v in AjaxConsoleProxy.tokens.items():
|
||||
if now - v['last_activity'] > FLAGS.ajax_console_idle_timeout:
|
||||
to_delete.append(k)
|
||||
|
||||
for k in to_delete:
|
||||
del AjaxConsoleProxy.tokens[k]
|
||||
|
||||
self.conn.consume_in_thread()
|
||||
utils.LoopingCall(delete_expired_tokens).start(1)
|
||||
|
||||
if __name__ == '__main__':
|
||||
utils.default_flagfile()
|
||||
FLAGS(sys.argv)
|
||||
logging.setup()
|
||||
acp_port = FLAGS.ajax_console_proxy_port
|
||||
acp = AjaxConsoleProxy()
|
||||
acp.register_listeners()
|
||||
server = wsgi.Server("AJAX Console Proxy", acp, port=acp_port)
|
||||
service.serve(server)
|
||||
service.wait()
|
||||
acp.conn.close()
|
|
@ -1573,19 +1573,6 @@ class API(base.Base):
|
|||
self._cast_compute_message('inject_file', context,
|
||||
instance, params=params)
|
||||
|
||||
@wrap_check_policy
|
||||
def get_ajax_console(self, context, instance):
|
||||
"""Get a url to an AJAX Console."""
|
||||
output = self._call_compute_message('get_ajax_console',
|
||||
context,
|
||||
instance)
|
||||
rpc.cast(context, '%s' % FLAGS.ajax_console_proxy_topic,
|
||||
{'method': 'authorize_ajax_console',
|
||||
'args': {'token': output['token'], 'host': output['host'],
|
||||
'port': output['port']}})
|
||||
return {'url': '%s/?token=%s' % (FLAGS.ajax_console_proxy_url,
|
||||
output['token'])}
|
||||
|
||||
@wrap_check_policy
|
||||
def get_vnc_console(self, context, instance, console_type):
|
||||
"""Get a url to an instance Console."""
|
||||
|
|
|
@ -1551,15 +1551,6 @@ class ComputeManager(manager.SchedulerDependentManager):
|
|||
else:
|
||||
return '\n'.join(log.split('\n')[-int(length):])
|
||||
|
||||
@exception.wrap_exception(notifier=notifier, publisher_id=publisher_id())
|
||||
@wrap_instance_fault
|
||||
def get_ajax_console(self, context, instance_uuid):
|
||||
"""Return connection information for an ajax console."""
|
||||
context = context.elevated()
|
||||
LOG.debug(_("instance %s: getting ajax console"), instance_uuid)
|
||||
instance_ref = self.db.instance_get_by_uuid(context, instance_uuid)
|
||||
return self.driver.get_ajax_console(instance_ref)
|
||||
|
||||
@exception.wrap_exception(notifier=notifier, publisher_id=publisher_id())
|
||||
@wrap_instance_fault
|
||||
def get_vnc_console(self, context, instance_uuid, console_type):
|
||||
|
|
|
@ -250,15 +250,6 @@ global_opts = [
|
|||
cfg.StrOpt('network_topic',
|
||||
default='network',
|
||||
help='the topic network nodes listen on'),
|
||||
cfg.StrOpt('ajax_console_proxy_topic',
|
||||
default='ajax_proxy',
|
||||
help='the topic ajax proxy nodes listen on'),
|
||||
cfg.StrOpt('ajax_console_proxy_url',
|
||||
default='http://127.0.0.1:8000',
|
||||
help='URL of ajax console proxy, in the form http://host:port'),
|
||||
cfg.IntOpt('ajax_console_proxy_port',
|
||||
default=8000,
|
||||
help='port that ajax_console_proxy binds'),
|
||||
cfg.StrOpt('vsa_topic',
|
||||
default='vsa',
|
||||
help='the topic that nova-vsa service listens on'),
|
||||
|
|
|
@ -93,10 +93,6 @@ def get_open_port(start_port, end_port):
|
|||
return int((start_port + end_port) / 2)
|
||||
|
||||
|
||||
def run_ajaxterm(cmd, token, port):
|
||||
pass
|
||||
|
||||
|
||||
def get_fs_info(path):
|
||||
return {'total': 128 * (1024 ** 3),
|
||||
'used': 44 * (1024 ** 3),
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
"compute:lock": [],
|
||||
"compute:unlock": [],
|
||||
|
||||
"compute:get_ajax_console": [],
|
||||
"compute:get_vnc_console": [],
|
||||
"compute:get_console_output": [],
|
||||
|
||||
|
|
|
@ -724,16 +724,6 @@ class ComputeTestCase(BaseTestCase):
|
|||
self.assertEqual(output, 'ANOTHER\nLAST LINE')
|
||||
self.compute.terminate_instance(self.context, instance['uuid'])
|
||||
|
||||
def test_ajax_console(self):
|
||||
"""Make sure we can get console output from instance"""
|
||||
instance = self._create_fake_instance()
|
||||
self.compute.run_instance(self.context, instance['uuid'])
|
||||
|
||||
console = self.compute.get_ajax_console(self.context,
|
||||
instance['uuid'])
|
||||
self.assert_(set(['token', 'host', 'port']).issubset(console.keys()))
|
||||
self.compute.terminate_instance(self.context, instance['uuid'])
|
||||
|
||||
def test_novnc_vnc_console(self):
|
||||
"""Make sure we can a vnc console for an instance."""
|
||||
instance = self._create_fake_instance()
|
||||
|
@ -2990,17 +2980,6 @@ class ComputeAPITestCase(BaseTestCase):
|
|||
'novnc')
|
||||
self.compute_api.delete(self.context, instance)
|
||||
|
||||
def test_ajax_console(self):
|
||||
"""Make sure we can an ajax console for an instance."""
|
||||
def ajax_rpc_call_wrapper(*args, **kwargs):
|
||||
return {'token': 'asdf', 'host': '0.0.0.0', 'port': 8080}
|
||||
|
||||
self.stubs.Set(rpc, 'call', ajax_rpc_call_wrapper)
|
||||
|
||||
instance = self._create_fake_instance()
|
||||
console = self.compute_api.get_ajax_console(self.context, instance)
|
||||
self.compute_api.delete(self.context, instance)
|
||||
|
||||
def test_console_output(self):
|
||||
instance = self._create_fake_instance()
|
||||
console = self.compute_api.get_console_output(self.context, instance)
|
||||
|
|
|
@ -1925,20 +1925,6 @@ disk size: 4.4M''', ''))
|
|||
finally:
|
||||
os.unlink(dst_path)
|
||||
|
||||
def test_run_ajaxterm(self):
|
||||
self.mox.StubOutWithMock(utils, 'execute')
|
||||
token = 's3cr3tt0ken'
|
||||
shell_cmd = 'shell-cmd.py'
|
||||
port = 2048
|
||||
utils.execute(mox.IgnoreArg(),
|
||||
'--command', shell_cmd,
|
||||
'-t', token,
|
||||
'-p', port)
|
||||
|
||||
# Start test
|
||||
self.mox.ReplayAll()
|
||||
libvirt_utils.run_ajaxterm(shell_cmd, token, port)
|
||||
|
||||
def test_get_fs_info(self):
|
||||
# Use a 1024-byte block size (df -k) because OS X does not support
|
||||
# the -B flag
|
||||
|
|
|
@ -288,14 +288,6 @@ class _VirtDriverTestCase(test.TestCase):
|
|||
console_output = self.connection.get_console_output(instance_ref)
|
||||
self.assertTrue(isinstance(console_output, basestring))
|
||||
|
||||
@catch_notimplementederror
|
||||
def test_get_ajax_console(self):
|
||||
instance_ref, network_info = self._get_running_instance()
|
||||
ajax_console = self.connection.get_ajax_console(instance_ref)
|
||||
self.assertIn('token', ajax_console)
|
||||
self.assertIn('host', ajax_console)
|
||||
self.assertIn('port', ajax_console)
|
||||
|
||||
@catch_notimplementederror
|
||||
def test_get_vnc_console(self):
|
||||
instance_ref, network_info = self._get_running_instance()
|
||||
|
|
|
@ -259,6 +259,3 @@ class VMWareAPIVMTestCase(test.TestCase):
|
|||
|
||||
def test_get_console_output(self):
|
||||
pass
|
||||
|
||||
def test_get_ajax_console(self):
|
||||
pass
|
||||
|
|
|
@ -191,10 +191,6 @@ class ComputeDriver(object):
|
|||
# TODO(Vek): Need to pass context in for access to auth_token
|
||||
raise NotImplementedError()
|
||||
|
||||
def get_ajax_console(self, instance):
|
||||
# TODO(Vek): Need to pass context in for access to auth_token
|
||||
raise NotImplementedError()
|
||||
|
||||
def get_vnc_console(self, instance):
|
||||
# TODO(Vek): Need to pass context in for access to auth_token
|
||||
raise NotImplementedError()
|
||||
|
|
|
@ -219,11 +219,6 @@ class FakeConnection(driver.ComputeDriver):
|
|||
def get_console_output(self, instance):
|
||||
return 'FAKE CONSOLE OUTPUT\nANOTHER\nLAST LINE'
|
||||
|
||||
def get_ajax_console(self, instance):
|
||||
return {'token': 'FAKETOKEN',
|
||||
'host': 'fakeajaxconsole.com',
|
||||
'port': 6969}
|
||||
|
||||
def get_vnc_console(self, instance):
|
||||
return {'internal_access_path': 'FAKE',
|
||||
'host': 'fakevncconsole.com',
|
||||
|
|
|
@ -102,9 +102,6 @@ libvirt_opts = [
|
|||
cfg.BoolOpt('use_cow_images',
|
||||
default=True,
|
||||
help='Whether to use cow images'),
|
||||
cfg.StrOpt('ajaxterm_portrange',
|
||||
default='10000-12000',
|
||||
help='Range of ports that ajaxterm should try to bind'),
|
||||
cfg.StrOpt('cpuinfo_xml_template',
|
||||
default=utils.abspath('virt/cpuinfo.xml.template'),
|
||||
help='CpuInfo XML Template (Used only live migration now)'),
|
||||
|
@ -777,29 +774,6 @@ class LibvirtConnection(driver.ComputeDriver):
|
|||
|
||||
return libvirt_utils.load_file(fpath)
|
||||
|
||||
@exception.wrap_exception()
|
||||
def get_ajax_console(self, instance):
|
||||
def get_pty_for_instance(instance_name):
|
||||
virt_dom = self._lookup_by_name(instance_name)
|
||||
xml = virt_dom.XMLDesc(0)
|
||||
dom = minidom.parseString(xml)
|
||||
|
||||
for serial in dom.getElementsByTagName('serial'):
|
||||
if serial.getAttribute('type') == 'pty':
|
||||
source = serial.getElementsByTagName('source')[0]
|
||||
return source.getAttribute('path')
|
||||
|
||||
start_port, end_port = FLAGS.ajaxterm_portrange.split("-")
|
||||
port = libvirt_utils.get_open_port(int(start_port), int(end_port))
|
||||
token = str(uuid.uuid4())
|
||||
host = instance['host']
|
||||
|
||||
ajaxterm_cmd = 'sudo netcat - %s' \
|
||||
% get_pty_for_instance(instance['name'])
|
||||
|
||||
libvirt_utils.run_ajaxterm(ajaxterm_cmd, token, port)
|
||||
return {'token': token, 'host': host, 'port': port}
|
||||
|
||||
@staticmethod
|
||||
def get_host_ip_addr():
|
||||
return FLAGS.my_ip
|
||||
|
|
|
@ -237,18 +237,6 @@ def get_open_port(start_port, end_port):
|
|||
raise Exception(_('Unable to find an open port'))
|
||||
|
||||
|
||||
def run_ajaxterm(cmd, token, port):
|
||||
"""Run ajaxterm
|
||||
|
||||
:param cmd: Command to connect to
|
||||
:param token: Token to require for authentication
|
||||
:param port: Port to run on
|
||||
"""
|
||||
cmd = ['%s/tools/ajaxterm/ajaxterm.py' % utils.novadir(),
|
||||
'--command', cmd, '-t', token, '-p', port]
|
||||
execute(*cmd)
|
||||
|
||||
|
||||
def get_fs_info(path):
|
||||
"""Get free/used/total space info for a filesystem
|
||||
|
||||
|
|
|
@ -719,10 +719,6 @@ class VMWareVMOps(object):
|
|||
else:
|
||||
return ""
|
||||
|
||||
def get_ajax_console(self, instance):
|
||||
"""Return link to instance's ajax console."""
|
||||
return 'http://fakeajaxconsole/fake_url'
|
||||
|
||||
def _set_machine_id(self, client_factory, instance, network_info):
|
||||
"""
|
||||
Set the machine id of the VM for guest tools to pick up and reconfigure
|
||||
|
|
|
@ -174,10 +174,6 @@ class VMWareESXConnection(driver.ComputeDriver):
|
|||
"""Return snapshot of console."""
|
||||
return self._vmops.get_console_output(instance)
|
||||
|
||||
def get_ajax_console(self, instance):
|
||||
"""Return link to instance's ajax console."""
|
||||
return self._vmops.get_ajax_console(instance)
|
||||
|
||||
def get_volume_connector(self, _instance):
|
||||
"""Return volume connector information"""
|
||||
# TODO(vish): When volume attaching is supported, return the
|
||||
|
|
|
@ -1425,11 +1425,6 @@ class VMOps(object):
|
|||
# TODO: implement this to fix pylint!
|
||||
return 'FAKE CONSOLE OUTPUT of instance'
|
||||
|
||||
def get_ajax_console(self, instance):
|
||||
"""Return link to instance's ajax console."""
|
||||
# TODO: implement this!
|
||||
return 'http://fakeajaxconsole/fake_url'
|
||||
|
||||
def get_vnc_console(self, instance):
|
||||
"""Return connection info for a vnc console."""
|
||||
vm_ref = self._get_vm_opaque_ref(instance)
|
||||
|
|
|
@ -337,12 +337,8 @@ class XenAPIConnection(driver.ComputeDriver):
|
|||
"""Return snapshot of console"""
|
||||
return self._vmops.get_console_output(instance)
|
||||
|
||||
def get_ajax_console(self, instance):
|
||||
"""Return link to instance's ajax console"""
|
||||
return self._vmops.get_ajax_console(instance)
|
||||
|
||||
def get_vnc_console(self, instance):
|
||||
"""Return link to instance's ajax console"""
|
||||
"""Return link to instance's VNC console"""
|
||||
return self._vmops.get_vnc_console(instance)
|
||||
|
||||
def get_volume_connector(self, _instance):
|
||||
|
|
|
@ -94,8 +94,7 @@ function run_pep8 {
|
|||
# Opt-out files from pep8
|
||||
ignore_scripts="*.sh:*nova-debug:*clean-vlans"
|
||||
ignore_files="*eventlet-patch:*pip-requires"
|
||||
ignore_dirs="*ajaxterm*"
|
||||
GLOBIGNORE="$ignore_scripts:$ignore_files:$ignore_dirs"
|
||||
GLOBIGNORE="$ignore_scripts:$ignore_files"
|
||||
srcfiles=`find bin -type f ! -name "nova.conf*"`
|
||||
srcfiles+=" `find tools/*`"
|
||||
srcfiles+=" nova setup.py plugins/xenserver/xenapi/etc/xapi.d/plugins/glance"
|
||||
|
@ -124,8 +123,7 @@ function run_hacking {
|
|||
# Opt-out files from pep8
|
||||
ignore_scripts="*.sh:*nova-debug:*clean-vlans:*.swp"
|
||||
ignore_files="*eventlet-patch:*pip-requires"
|
||||
ignore_dirs="*ajaxterm*"
|
||||
GLOBIGNORE="$ignore_scripts:$ignore_files:$ignore_dirs"
|
||||
GLOBIGNORE="$ignore_scripts:$ignore_files"
|
||||
srcfiles=`find bin -type f ! -name "nova.conf*"`
|
||||
srcfiles+=" `find tools/*`"
|
||||
srcfiles+=" nova setup.py plugins/xenserver/xenapi/etc/xapi.d/plugins/glance"
|
||||
|
|
1
setup.py
1
setup.py
|
@ -82,7 +82,6 @@ setup(name='nova',
|
|||
data_files=find_data_files('share/nova', 'tools'),
|
||||
scripts=['bin/clear_rabbit_queues',
|
||||
'bin/instance-usage-audit',
|
||||
'bin/nova-ajax-console-proxy',
|
||||
'bin/nova-all',
|
||||
'bin/nova-api',
|
||||
'bin/nova-api-ec2',
|
||||
|
|
|
@ -1,120 +0,0 @@
|
|||
= [http://antony.lesuisse.org/qweb/trac/wiki/AjaxTerm Ajaxterm] =
|
||||
|
||||
Ajaxterm is a web based terminal. It was totally inspired and works almost
|
||||
exactly like http://anyterm.org/ except it's much easier to install (see
|
||||
comparaison with anyterm below).
|
||||
|
||||
Ajaxterm written in python (and some AJAX javascript for client side) and depends only on python2.3 or better.[[BR]]
|
||||
Ajaxterm is '''very simple to install''' on Linux, MacOS X, FreeBSD, Solaris, cygwin and any Unix that runs python2.3.[[BR]]
|
||||
Ajaxterm was written by Antony Lesuisse (email: al AT udev.org), License Public Domain.
|
||||
|
||||
Use the [/qweb/forum/viewforum.php?id=2 Forum], if you have any question or remark.
|
||||
|
||||
== News ==
|
||||
|
||||
* 2006-10-29: v0.10 allow space in login, cgi launch fix, redhat init
|
||||
* 2006-07-12: v0.9 change uid, daemon fix (Daniel Fischer)
|
||||
* 2006-07-04: v0.8 add login support to ssh (Sven Geggus), change max width to 256
|
||||
* 2006-05-31: v0.7 minor fixes, daemon option
|
||||
* 2006-05-23: v0.6 Applied debian and gentoo patches, renamed to Ajaxterm, default port 8022
|
||||
|
||||
== Download and Install ==
|
||||
|
||||
* Release: [/qweb/files/Ajaxterm-0.10.tar.gz Ajaxterm-0.10.tar.gz]
|
||||
* Browse src: [/qweb/trac/browser/trunk/ajaxterm/ ajaxterm/]
|
||||
|
||||
To install Ajaxterm issue the following commands:
|
||||
{{{
|
||||
wget http://antony.lesuisse.org/qweb/files/Ajaxterm-0.10.tar.gz
|
||||
tar zxvf Ajaxterm-0.10.tar.gz
|
||||
cd Ajaxterm-0.10
|
||||
./ajaxterm.py
|
||||
}}}
|
||||
Then point your browser to this URL : http://localhost:8022/
|
||||
|
||||
== Screenshot ==
|
||||
|
||||
{{{
|
||||
#!html
|
||||
<center><img src="/qweb/trac/attachment/wiki/AjaxTerm/scr.png?format=raw" alt="ajaxterm screenshot" style=""/></center>
|
||||
}}}
|
||||
|
||||
== Documentation and Caveats ==
|
||||
|
||||
* Ajaxterm only support latin1, if you use Ubuntu or any LANG==en_US.UTF-8 distribution don't forget to "unset LANG".
|
||||
|
||||
* If run as root ajaxterm will run /bin/login, otherwise it will run ssh
|
||||
localhost. To use an other command use the -c option.
|
||||
|
||||
* By default Ajaxterm only listen at 127.0.0.1:8022. For remote access, it is
|
||||
strongly recommended to use '''https SSL/TLS''', and that is simple to
|
||||
configure if you use the apache web server using mod_proxy.[[BR]][[BR]]
|
||||
Using ssl will also speed up ajaxterm (probably because of keepalive).[[BR]][[BR]]
|
||||
Here is an configuration example:
|
||||
|
||||
{{{
|
||||
Listen 443
|
||||
NameVirtualHost *:443
|
||||
|
||||
<VirtualHost *:443>
|
||||
ServerName localhost
|
||||
SSLEngine On
|
||||
SSLCertificateKeyFile ssl/apache.pem
|
||||
SSLCertificateFile ssl/apache.pem
|
||||
|
||||
ProxyRequests Off
|
||||
<Proxy *>
|
||||
Order deny,allow
|
||||
Allow from all
|
||||
</Proxy>
|
||||
ProxyPass /ajaxterm/ http://localhost:8022/
|
||||
ProxyPassReverse /ajaxterm/ http://localhost:8022/
|
||||
</VirtualHost>
|
||||
}}}
|
||||
|
||||
* Using GET HTTP request seems to speed up ajaxterm, just click on GET in the
|
||||
interface, but be warned that your keystrokes might be loggued (by apache or
|
||||
any proxy). I usually enable it after the login.
|
||||
|
||||
* Ajaxterm commandline usage:
|
||||
|
||||
{{{
|
||||
usage: ajaxterm.py [options]
|
||||
|
||||
options:
|
||||
-h, --help show this help message and exit
|
||||
-pPORT, --port=PORT Set the TCP port (default: 8022)
|
||||
-cCMD, --command=CMD set the command (default: /bin/login or ssh localhost)
|
||||
-l, --log log requests to stderr (default: quiet mode)
|
||||
-d, --daemon run as daemon in the background
|
||||
-PPIDFILE, --pidfile=PIDFILE
|
||||
set the pidfile (default: /var/run/ajaxterm.pid)
|
||||
-iINDEX_FILE, --index=INDEX_FILE
|
||||
default index file (default: ajaxterm.html)
|
||||
-uUID, --uid=UID Set the daemon's user id
|
||||
}}}
|
||||
|
||||
* Ajaxterm was first written as a demo for qweb (my web framework), but
|
||||
actually doesn't use many features of qweb.
|
||||
|
||||
* Compared to anyterm:
|
||||
* There are no partial updates, ajaxterm updates either all the screen or
|
||||
nothing. That make the code simpler and I also think it's faster. HTTP
|
||||
replies are always gzencoded. When used in 80x25 mode, almost all of
|
||||
them are below the 1500 bytes (size of an ethernet frame) and we just
|
||||
replace the screen with the reply (no javascript string handling).
|
||||
* Ajaxterm polls the server for updates with an exponentially growing
|
||||
timeout when the screen hasn't changed. The timeout is also resetted as
|
||||
soon as a key is pressed. Anyterm blocks on a pending request and use a
|
||||
parallel connection for keypresses. The anyterm approch is better
|
||||
when there aren't any keypress.
|
||||
|
||||
* Ajaxterm files are released in the Public Domain, (except [http://sarissa.sourceforge.net/doc/ sarissa*] which are LGPL).
|
||||
|
||||
== TODO ==
|
||||
|
||||
* insert mode ESC [ 4 h
|
||||
* change size x,y from gui (sending signal)
|
||||
* vt102 graphic codepage
|
||||
* use innerHTML or prototype instead of sarissa
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
.TH ajaxterm "1" "May 2006" "ajaxterm 0.5" "User commands"
|
||||
.SH NAME
|
||||
ajaxterm \- Web based terminal written in python
|
||||
|
||||
.SH DESCRITPION
|
||||
\fBajaxterm\fR is a web based terminal written in python and some AJAX
|
||||
javascript for client side.
|
||||
It can use almost any web browser and even works through firewalls.
|
||||
|
||||
.SH USAGE
|
||||
\fBajaxterm.py\fR [options]
|
||||
|
||||
.SH OPTIONS
|
||||
A summary of the options supported by \fBajaxterm\fR is included below.
|
||||
\fB-h, --help\fR show this help message and exit
|
||||
\fB-pPORT, --port=PORT\fR Set the TCP port (default: 8022)
|
||||
\fB-cCMD, --command=CMD\fR set the command (default: /bin/login or ssh localhost)
|
||||
\fB-l, --log\fR log requests to stderr (default: quiet mode)
|
||||
|
||||
.SH AUTHOR
|
||||
Antony Lesuisse <al@udev.org>
|
||||
|
||||
This manual page was written for the Debian system by
|
||||
Julien Valroff <julien@kirya.net> (but may be used by others).
|
||||
|
||||
.SH "REPORTING BUGS"
|
||||
Report any bugs to the author: Antony Lesuisse <al@udev.org>
|
||||
|
||||
.SH COPYRIGHT
|
||||
Copyright Antony Lesuisse <al@udev.org>
|
||||
|
||||
.SH SEE ALSO
|
||||
- \fBajaxterm\fR wiki page: http://antony.lesuisse.org/qweb/trac/wiki/AjaxTerm
|
||||
.br
|
||||
- \fBajaxterm\fR forum: http://antony.lesuisse.org/qweb/forum/viewforum.php?id=2
|
|
@ -1,64 +0,0 @@
|
|||
pre.stat {
|
||||
margin: 0px;
|
||||
padding: 4px;
|
||||
display: block;
|
||||
font-family: monospace;
|
||||
white-space: pre;
|
||||
background-color: black;
|
||||
border-top: 1px solid black;
|
||||
color: white;
|
||||
}
|
||||
pre.stat span {
|
||||
padding: 0px;
|
||||
}
|
||||
pre.stat .on {
|
||||
background-color: #080;
|
||||
font-weight: bold;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
}
|
||||
pre.stat .off {
|
||||
background-color: #888;
|
||||
font-weight: bold;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
}
|
||||
pre.term {
|
||||
margin: 0px;
|
||||
padding: 4px;
|
||||
display: block;
|
||||
font-family: monospace;
|
||||
white-space: pre;
|
||||
background-color: black;
|
||||
border-top: 1px solid white;
|
||||
color: #eee;
|
||||
}
|
||||
pre.term span.f0 { color: #000; }
|
||||
pre.term span.f1 { color: #b00; }
|
||||
pre.term span.f2 { color: #0b0; }
|
||||
pre.term span.f3 { color: #bb0; }
|
||||
pre.term span.f4 { color: #00b; }
|
||||
pre.term span.f5 { color: #b0b; }
|
||||
pre.term span.f6 { color: #0bb; }
|
||||
pre.term span.f7 { color: #bbb; }
|
||||
pre.term span.f8 { color: #666; }
|
||||
pre.term span.f9 { color: #f00; }
|
||||
pre.term span.f10 { color: #0f0; }
|
||||
pre.term span.f11 { color: #ff0; }
|
||||
pre.term span.f12 { color: #00f; }
|
||||
pre.term span.f13 { color: #f0f; }
|
||||
pre.term span.f14 { color: #0ff; }
|
||||
pre.term span.f15 { color: #fff; }
|
||||
pre.term span.b0 { background-color: #000; }
|
||||
pre.term span.b1 { background-color: #b00; }
|
||||
pre.term span.b2 { background-color: #0b0; }
|
||||
pre.term span.b3 { background-color: #bb0; }
|
||||
pre.term span.b4 { background-color: #00b; }
|
||||
pre.term span.b5 { background-color: #b0b; }
|
||||
pre.term span.b6 { background-color: #0bb; }
|
||||
pre.term span.b7 { background-color: #bbb; }
|
||||
|
||||
body { background-color: #888; }
|
||||
#term {
|
||||
float: left;
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Ajaxterm</title>
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
|
||||
<link rel="stylesheet" type="text/css" href="ajaxterm.css"/>
|
||||
<script type="text/javascript" src="sarissa.js"></script>
|
||||
<script type="text/javascript" src="sarissa_dhtml.js"></script>
|
||||
<script type="text/javascript" src="ajaxterm.js"></script>
|
||||
<script type="text/javascript">
|
||||
/*
|
||||
ajaxterm.py creates a random session_id to demultiplex multiple connections,
|
||||
and to add a layer of security - in its shipping form, ajaxterm accepted any session_id
|
||||
and was susceptible to an easy exploit
|
||||
*/
|
||||
SESSION_ID = '$session_id';
|
||||
window.onload=function() {
|
||||
t=ajaxterm.Terminal("term",80,25);
|
||||
};
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="term"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -1,279 +0,0 @@
|
|||
ajaxterm={};
|
||||
ajaxterm.Terminal_ctor=function(id,width,height) {
|
||||
var ie=0;
|
||||
if(window.ActiveXObject)
|
||||
ie=1;
|
||||
var sid=""+SESSION_ID;
|
||||
var query0="s="+sid+"&w="+width+"&h="+height;
|
||||
var query1=query0+"&c=1&k=";
|
||||
var buf="";
|
||||
var timeout;
|
||||
var error_timeout;
|
||||
var keybuf=[];
|
||||
var sending=0;
|
||||
var rmax=1;
|
||||
|
||||
var div=document.getElementById(id);
|
||||
var dstat=document.createElement('pre');
|
||||
var sled=document.createElement('span');
|
||||
var opt_get=document.createElement('a');
|
||||
var opt_color=document.createElement('a');
|
||||
var opt_paste=document.createElement('a');
|
||||
var sdebug=document.createElement('span');
|
||||
var dterm=document.createElement('div');
|
||||
|
||||
function debug(s) {
|
||||
sdebug.innerHTML=s;
|
||||
}
|
||||
function error() {
|
||||
sled.className='off';
|
||||
debug("Connection lost timeout ts:"+((new Date).getTime()));
|
||||
}
|
||||
function opt_add(opt,name) {
|
||||
opt.className='off';
|
||||
opt.innerHTML=' '+name+' ';
|
||||
dstat.appendChild(opt);
|
||||
dstat.appendChild(document.createTextNode(' '));
|
||||
}
|
||||
function do_get(event) {
|
||||
opt_get.className=(opt_get.className=='off')?'on':'off';
|
||||
debug('GET '+opt_get.className);
|
||||
}
|
||||
function do_color(event) {
|
||||
var o=opt_color.className=(opt_color.className=='off')?'on':'off';
|
||||
if(o=='on')
|
||||
query1=query0+"&c=1&k=";
|
||||
else
|
||||
query1=query0+"&k=";
|
||||
debug('Color '+opt_color.className);
|
||||
}
|
||||
function mozilla_clipboard() {
|
||||
// mozilla sucks
|
||||
try {
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
} catch (err) {
|
||||
debug('Access denied, <a href="http://kb.mozillazine.org/Granting_JavaScript_access_to_the_clipboard" target="_blank">more info</a>');
|
||||
return undefined;
|
||||
}
|
||||
var clip = Components.classes["@mozilla.org/widget/clipboard;1"].createInstance(Components.interfaces.nsIClipboard);
|
||||
var trans = Components.classes["@mozilla.org/widget/transferable;1"].createInstance(Components.interfaces.nsITransferable);
|
||||
if (!clip || !trans) {
|
||||
return undefined;
|
||||
}
|
||||
trans.addDataFlavor("text/unicode");
|
||||
clip.getData(trans,clip.kGlobalClipboard);
|
||||
var str=new Object();
|
||||
var strLength=new Object();
|
||||
try {
|
||||
trans.getTransferData("text/unicode",str,strLength);
|
||||
} catch(err) {
|
||||
return "";
|
||||
}
|
||||
if (str) {
|
||||
str=str.value.QueryInterface(Components.interfaces.nsISupportsString);
|
||||
}
|
||||
if (str) {
|
||||
return str.data.substring(0,strLength.value / 2);
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
function do_paste(event) {
|
||||
var p=undefined;
|
||||
if (window.clipboardData) {
|
||||
p=window.clipboardData.getData("Text");
|
||||
} else if(window.netscape) {
|
||||
p=mozilla_clipboard();
|
||||
}
|
||||
if (p) {
|
||||
debug('Pasted');
|
||||
queue(encodeURIComponent(p));
|
||||
} else {
|
||||
}
|
||||
}
|
||||
function update() {
|
||||
// debug("ts: "+((new Date).getTime())+" rmax:"+rmax);
|
||||
if(sending==0) {
|
||||
sending=1;
|
||||
sled.className='on';
|
||||
var r=new XMLHttpRequest();
|
||||
var send="";
|
||||
while(keybuf.length>0) {
|
||||
send+=keybuf.pop();
|
||||
}
|
||||
var query=query1+send;
|
||||
if(opt_get.className=='on') {
|
||||
r.open("GET","u?"+query,true);
|
||||
if(ie) {
|
||||
r.setRequestHeader("If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT");
|
||||
}
|
||||
} else {
|
||||
r.open("POST","u",true);
|
||||
}
|
||||
r.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
|
||||
r.onreadystatechange = function () {
|
||||
// debug("xhr:"+((new Date).getTime())+" state:"+r.readyState+" status:"+r.status+" statusText:"+r.statusText);
|
||||
if (r.readyState==4) {
|
||||
if(r.status==200) {
|
||||
window.clearTimeout(error_timeout);
|
||||
de=r.responseXML.documentElement;
|
||||
if(de.tagName=="pre") {
|
||||
if(ie) {
|
||||
Sarissa.updateContentFromNode(de, dterm);
|
||||
} else {
|
||||
Sarissa.updateContentFromNode(de, dterm);
|
||||
// old=div.firstChild;
|
||||
// div.replaceChild(de,old);
|
||||
}
|
||||
rmax=100;
|
||||
} else {
|
||||
rmax*=2;
|
||||
if(rmax>2000)
|
||||
rmax=2000;
|
||||
}
|
||||
sending=0;
|
||||
sled.className='off';
|
||||
timeout=window.setTimeout(update,rmax);
|
||||
} else {
|
||||
debug("Connection error status:"+r.status);
|
||||
}
|
||||
}
|
||||
}
|
||||
error_timeout=window.setTimeout(error,5000);
|
||||
if(opt_get.className=='on') {
|
||||
r.send(null);
|
||||
} else {
|
||||
r.send(query);
|
||||
}
|
||||
}
|
||||
}
|
||||
function queue(s) {
|
||||
keybuf.unshift(s);
|
||||
if(sending==0) {
|
||||
window.clearTimeout(timeout);
|
||||
timeout=window.setTimeout(update,1);
|
||||
}
|
||||
}
|
||||
function keypress(ev) {
|
||||
if (!ev) var ev=window.event;
|
||||
// s="kp keyCode="+ev.keyCode+" which="+ev.which+" shiftKey="+ev.shiftKey+" ctrlKey="+ev.ctrlKey+" altKey="+ev.altKey;
|
||||
// debug(s);
|
||||
// return false;
|
||||
// else { if (!ev.ctrlKey || ev.keyCode==17) { return; }
|
||||
var kc;
|
||||
var k="";
|
||||
if (ev.keyCode)
|
||||
kc=ev.keyCode;
|
||||
if (ev.which)
|
||||
kc=ev.which;
|
||||
if (ev.altKey) {
|
||||
if (kc>=65 && kc<=90)
|
||||
kc+=32;
|
||||
if (kc>=97 && kc<=122) {
|
||||
k=String.fromCharCode(27)+String.fromCharCode(kc);
|
||||
}
|
||||
} else if (ev.ctrlKey) {
|
||||
if (kc>=65 && kc<=90) k=String.fromCharCode(kc-64); // Ctrl-A..Z
|
||||
else if (kc>=97 && kc<=122) k=String.fromCharCode(kc-96); // Ctrl-A..Z
|
||||
else if (kc==54) k=String.fromCharCode(30); // Ctrl-^
|
||||
else if (kc==109) k=String.fromCharCode(31); // Ctrl-_
|
||||
else if (kc==219) k=String.fromCharCode(27); // Ctrl-[
|
||||
else if (kc==220) k=String.fromCharCode(28); // Ctrl-\
|
||||
else if (kc==221) k=String.fromCharCode(29); // Ctrl-]
|
||||
else if (kc==219) k=String.fromCharCode(29); // Ctrl-]
|
||||
else if (kc==219) k=String.fromCharCode(0); // Ctrl-@
|
||||
} else if (ev.which==0) {
|
||||
if (kc==9) k=String.fromCharCode(9); // Tab
|
||||
else if (kc==8) k=String.fromCharCode(127); // Backspace
|
||||
else if (kc==27) k=String.fromCharCode(27); // Escape
|
||||
else {
|
||||
if (kc==33) k="[5~"; // PgUp
|
||||
else if (kc==34) k="[6~"; // PgDn
|
||||
else if (kc==35) k="[4~"; // End
|
||||
else if (kc==36) k="[1~"; // Home
|
||||
else if (kc==37) k="[D"; // Left
|
||||
else if (kc==38) k="[A"; // Up
|
||||
else if (kc==39) k="[C"; // Right
|
||||
else if (kc==40) k="[B"; // Down
|
||||
else if (kc==45) k="[2~"; // Ins
|
||||
else if (kc==46) k="[3~"; // Del
|
||||
else if (kc==112) k="[[A"; // F1
|
||||
else if (kc==113) k="[[B"; // F2
|
||||
else if (kc==114) k="[[C"; // F3
|
||||
else if (kc==115) k="[[D"; // F4
|
||||
else if (kc==116) k="[[E"; // F5
|
||||
else if (kc==117) k="[17~"; // F6
|
||||
else if (kc==118) k="[18~"; // F7
|
||||
else if (kc==119) k="[19~"; // F8
|
||||
else if (kc==120) k="[20~"; // F9
|
||||
else if (kc==121) k="[21~"; // F10
|
||||
else if (kc==122) k="[23~"; // F11
|
||||
else if (kc==123) k="[24~"; // F12
|
||||
if (k.length) {
|
||||
k=String.fromCharCode(27)+k;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (kc==8)
|
||||
k=String.fromCharCode(127); // Backspace
|
||||
else
|
||||
k=String.fromCharCode(kc);
|
||||
}
|
||||
if(k.length) {
|
||||
// queue(encodeURIComponent(k));
|
||||
if(k=="+") {
|
||||
queue("%2B");
|
||||
} else {
|
||||
queue(escape(k));
|
||||
}
|
||||
}
|
||||
ev.cancelBubble=true;
|
||||
if (ev.stopPropagation) ev.stopPropagation();
|
||||
if (ev.preventDefault) ev.preventDefault();
|
||||
return false;
|
||||
}
|
||||
function keydown(ev) {
|
||||
if (!ev) var ev=window.event;
|
||||
if (ie) {
|
||||
// s="kd keyCode="+ev.keyCode+" which="+ev.which+" shiftKey="+ev.shiftKey+" ctrlKey="+ev.ctrlKey+" altKey="+ev.altKey;
|
||||
// debug(s);
|
||||
o={9:1,8:1,27:1,33:1,34:1,35:1,36:1,37:1,38:1,39:1,40:1,45:1,46:1,112:1,
|
||||
113:1,114:1,115:1,116:1,117:1,118:1,119:1,120:1,121:1,122:1,123:1};
|
||||
if (o[ev.keyCode] || ev.ctrlKey || ev.altKey) {
|
||||
ev.which=0;
|
||||
return keypress(ev);
|
||||
}
|
||||
}
|
||||
}
|
||||
function init() {
|
||||
sled.appendChild(document.createTextNode('\xb7'));
|
||||
sled.className='off';
|
||||
dstat.appendChild(sled);
|
||||
dstat.appendChild(document.createTextNode(' '));
|
||||
opt_add(opt_color,'Colors');
|
||||
opt_color.className='on';
|
||||
opt_add(opt_get,'GET');
|
||||
opt_add(opt_paste,'Paste');
|
||||
dstat.appendChild(sdebug);
|
||||
dstat.className='stat';
|
||||
div.appendChild(dstat);
|
||||
div.appendChild(dterm);
|
||||
if(opt_color.addEventListener) {
|
||||
opt_get.addEventListener('click',do_get,true);
|
||||
opt_color.addEventListener('click',do_color,true);
|
||||
opt_paste.addEventListener('click',do_paste,true);
|
||||
} else {
|
||||
opt_get.attachEvent("onclick", do_get);
|
||||
opt_color.attachEvent("onclick", do_color);
|
||||
opt_paste.attachEvent("onclick", do_paste);
|
||||
}
|
||||
document.onkeypress=keypress;
|
||||
document.onkeydown=keydown;
|
||||
timeout=window.setTimeout(update,100);
|
||||
}
|
||||
init();
|
||||
}
|
||||
ajaxterm.Terminal=function(id,width,height) {
|
||||
return new this.Terminal_ctor(id,width,height);
|
||||
}
|
||||
|
|
@ -1,586 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
""" Ajaxterm """
|
||||
|
||||
import array,cgi,fcntl,glob,mimetypes,optparse,os,pty,random,re,signal,select,sys,threading,time,termios,struct,pwd
|
||||
|
||||
os.chdir(os.path.normpath(os.path.dirname(__file__)))
|
||||
# Optional: Add QWeb in sys path
|
||||
sys.path[0:0]=glob.glob('../../python')
|
||||
|
||||
import qweb
|
||||
import string, subprocess, uuid
|
||||
|
||||
global g_server
|
||||
TIMEOUT=300
|
||||
|
||||
class Terminal:
|
||||
def __init__(self,width=80,height=24):
|
||||
self.width=width
|
||||
self.height=height
|
||||
self.init()
|
||||
self.reset()
|
||||
def init(self):
|
||||
self.esc_seq={
|
||||
"\x00": None,
|
||||
"\x05": self.esc_da,
|
||||
"\x07": None,
|
||||
"\x08": self.esc_0x08,
|
||||
"\x09": self.esc_0x09,
|
||||
"\x0a": self.esc_0x0a,
|
||||
"\x0b": self.esc_0x0a,
|
||||
"\x0c": self.esc_0x0a,
|
||||
"\x0d": self.esc_0x0d,
|
||||
"\x0e": None,
|
||||
"\x0f": None,
|
||||
"\x1b#8": None,
|
||||
"\x1b=": None,
|
||||
"\x1b>": None,
|
||||
"\x1b(0": None,
|
||||
"\x1b(A": None,
|
||||
"\x1b(B": None,
|
||||
"\x1b[c": self.esc_da,
|
||||
"\x1b[0c": self.esc_da,
|
||||
"\x1b]R": None,
|
||||
"\x1b7": self.esc_save,
|
||||
"\x1b8": self.esc_restore,
|
||||
"\x1bD": None,
|
||||
"\x1bE": None,
|
||||
"\x1bH": None,
|
||||
"\x1bM": self.esc_ri,
|
||||
"\x1bN": None,
|
||||
"\x1bO": None,
|
||||
"\x1bZ": self.esc_da,
|
||||
"\x1ba": None,
|
||||
"\x1bc": self.reset,
|
||||
"\x1bn": None,
|
||||
"\x1bo": None,
|
||||
}
|
||||
for k,v in self.esc_seq.items():
|
||||
if v==None:
|
||||
self.esc_seq[k]=self.esc_ignore
|
||||
# regex
|
||||
d={
|
||||
r'\[\??([0-9;]*)([@ABCDEFGHJKLMPXacdefghlmnqrstu`])' : self.csi_dispatch,
|
||||
r'\]([^\x07]+)\x07' : self.esc_ignore,
|
||||
}
|
||||
self.esc_re=[]
|
||||
for k,v in d.items():
|
||||
self.esc_re.append((re.compile('\x1b'+k),v))
|
||||
# define csi sequences
|
||||
self.csi_seq={
|
||||
'@': (self.csi_at,[1]),
|
||||
'`': (self.csi_G,[1]),
|
||||
'J': (self.csi_J,[0]),
|
||||
'K': (self.csi_K,[0]),
|
||||
}
|
||||
for i in [i[4] for i in dir(self) if i.startswith('csi_') and len(i)==5]:
|
||||
if not self.csi_seq.has_key(i):
|
||||
self.csi_seq[i]=(getattr(self,'csi_'+i),[1])
|
||||
# Init 0-256 to latin1 and html translation table
|
||||
self.trl1=""
|
||||
for i in range(256):
|
||||
if i<32:
|
||||
self.trl1+=" "
|
||||
elif i<127 or i>160:
|
||||
self.trl1+=chr(i)
|
||||
else:
|
||||
self.trl1+="?"
|
||||
self.trhtml=""
|
||||
for i in range(256):
|
||||
if i==0x0a or (i>32 and i<127) or i>160:
|
||||
self.trhtml+=chr(i)
|
||||
elif i<=32:
|
||||
self.trhtml+="\xa0"
|
||||
else:
|
||||
self.trhtml+="?"
|
||||
def reset(self,s=""):
|
||||
self.scr=array.array('i',[0x000700]*(self.width*self.height))
|
||||
self.st=0
|
||||
self.sb=self.height-1
|
||||
self.cx_bak=self.cx=0
|
||||
self.cy_bak=self.cy=0
|
||||
self.cl=0
|
||||
self.sgr=0x000700
|
||||
self.buf=""
|
||||
self.outbuf=""
|
||||
self.last_html=""
|
||||
def peek(self,y1,x1,y2,x2):
|
||||
return self.scr[self.width*y1+x1:self.width*y2+x2]
|
||||
def poke(self,y,x,s):
|
||||
pos=self.width*y+x
|
||||
self.scr[pos:pos+len(s)]=s
|
||||
def zero(self,y1,x1,y2,x2):
|
||||
w=self.width*(y2-y1)+x2-x1+1
|
||||
z=array.array('i',[0x000700]*w)
|
||||
self.scr[self.width*y1+x1:self.width*y2+x2+1]=z
|
||||
def scroll_up(self,y1,y2):
|
||||
self.poke(y1,0,self.peek(y1+1,0,y2,self.width))
|
||||
self.zero(y2,0,y2,self.width-1)
|
||||
def scroll_down(self,y1,y2):
|
||||
self.poke(y1+1,0,self.peek(y1,0,y2-1,self.width))
|
||||
self.zero(y1,0,y1,self.width-1)
|
||||
def scroll_right(self,y,x):
|
||||
self.poke(y,x+1,self.peek(y,x,y,self.width))
|
||||
self.zero(y,x,y,x)
|
||||
def cursor_down(self):
|
||||
if self.cy>=self.st and self.cy<=self.sb:
|
||||
self.cl=0
|
||||
q,r=divmod(self.cy+1,self.sb+1)
|
||||
if q:
|
||||
self.scroll_up(self.st,self.sb)
|
||||
self.cy=self.sb
|
||||
else:
|
||||
self.cy=r
|
||||
def cursor_right(self):
|
||||
q,r=divmod(self.cx+1,self.width)
|
||||
if q:
|
||||
self.cl=1
|
||||
else:
|
||||
self.cx=r
|
||||
def echo(self,c):
|
||||
if self.cl:
|
||||
self.cursor_down()
|
||||
self.cx=0
|
||||
self.scr[(self.cy*self.width)+self.cx]=self.sgr|ord(c)
|
||||
self.cursor_right()
|
||||
def esc_0x08(self,s):
|
||||
self.cx=max(0,self.cx-1)
|
||||
def esc_0x09(self,s):
|
||||
x=self.cx+8
|
||||
q,r=divmod(x,8)
|
||||
self.cx=(q*8)%self.width
|
||||
def esc_0x0a(self,s):
|
||||
self.cursor_down()
|
||||
def esc_0x0d(self,s):
|
||||
self.cl=0
|
||||
self.cx=0
|
||||
def esc_save(self,s):
|
||||
self.cx_bak=self.cx
|
||||
self.cy_bak=self.cy
|
||||
def esc_restore(self,s):
|
||||
self.cx=self.cx_bak
|
||||
self.cy=self.cy_bak
|
||||
self.cl=0
|
||||
def esc_da(self,s):
|
||||
self.outbuf="\x1b[?6c"
|
||||
def esc_ri(self,s):
|
||||
self.cy=max(self.st,self.cy-1)
|
||||
if self.cy==self.st:
|
||||
self.scroll_down(self.st,self.sb)
|
||||
def esc_ignore(self,*s):
|
||||
pass
|
||||
# print "term:ignore: %s"%repr(s)
|
||||
def csi_dispatch(self,seq,mo):
|
||||
# CSI sequences
|
||||
s=mo.group(1)
|
||||
c=mo.group(2)
|
||||
f=self.csi_seq.get(c,None)
|
||||
if f:
|
||||
try:
|
||||
l=[min(int(i),1024) for i in s.split(';') if len(i)<4]
|
||||
except ValueError:
|
||||
l=[]
|
||||
if len(l)==0:
|
||||
l=f[1]
|
||||
f[0](l)
|
||||
# else:
|
||||
# print 'csi ignore',c,l
|
||||
def csi_at(self,l):
|
||||
for i in range(l[0]):
|
||||
self.scroll_right(self.cy,self.cx)
|
||||
def csi_A(self,l):
|
||||
self.cy=max(self.st,self.cy-l[0])
|
||||
def csi_B(self,l):
|
||||
self.cy=min(self.sb,self.cy+l[0])
|
||||
def csi_C(self,l):
|
||||
self.cx=min(self.width-1,self.cx+l[0])
|
||||
self.cl=0
|
||||
def csi_D(self,l):
|
||||
self.cx=max(0,self.cx-l[0])
|
||||
self.cl=0
|
||||
def csi_E(self,l):
|
||||
self.csi_B(l)
|
||||
self.cx=0
|
||||
self.cl=0
|
||||
def csi_F(self,l):
|
||||
self.csi_A(l)
|
||||
self.cx=0
|
||||
self.cl=0
|
||||
def csi_G(self,l):
|
||||
self.cx=min(self.width,l[0])-1
|
||||
def csi_H(self,l):
|
||||
if len(l)<2: l=[1,1]
|
||||
self.cx=min(self.width,l[1])-1
|
||||
self.cy=min(self.height,l[0])-1
|
||||
self.cl=0
|
||||
def csi_J(self,l):
|
||||
if l[0]==0:
|
||||
self.zero(self.cy,self.cx,self.height-1,self.width-1)
|
||||
elif l[0]==1:
|
||||
self.zero(0,0,self.cy,self.cx)
|
||||
elif l[0]==2:
|
||||
self.zero(0,0,self.height-1,self.width-1)
|
||||
def csi_K(self,l):
|
||||
if l[0]==0:
|
||||
self.zero(self.cy,self.cx,self.cy,self.width-1)
|
||||
elif l[0]==1:
|
||||
self.zero(self.cy,0,self.cy,self.cx)
|
||||
elif l[0]==2:
|
||||
self.zero(self.cy,0,self.cy,self.width-1)
|
||||
def csi_L(self,l):
|
||||
for i in range(l[0]):
|
||||
if self.cy<self.sb:
|
||||
self.scroll_down(self.cy,self.sb)
|
||||
def csi_M(self,l):
|
||||
if self.cy>=self.st and self.cy<=self.sb:
|
||||
for i in range(l[0]):
|
||||
self.scroll_up(self.cy,self.sb)
|
||||
def csi_P(self,l):
|
||||
w,cx,cy=self.width,self.cx,self.cy
|
||||
end=self.peek(cy,cx,cy,w)
|
||||
self.csi_K([0])
|
||||
self.poke(cy,cx,end[l[0]:])
|
||||
def csi_X(self,l):
|
||||
self.zero(self.cy,self.cx,self.cy,self.cx+l[0])
|
||||
def csi_a(self,l):
|
||||
self.csi_C(l)
|
||||
def csi_c(self,l):
|
||||
#'\x1b[?0c' 0-8 cursor size
|
||||
pass
|
||||
def csi_d(self,l):
|
||||
self.cy=min(self.height,l[0])-1
|
||||
def csi_e(self,l):
|
||||
self.csi_B(l)
|
||||
def csi_f(self,l):
|
||||
self.csi_H(l)
|
||||
def csi_h(self,l):
|
||||
if l[0]==4:
|
||||
pass
|
||||
# print "insert on"
|
||||
def csi_l(self,l):
|
||||
if l[0]==4:
|
||||
pass
|
||||
# print "insert off"
|
||||
def csi_m(self,l):
|
||||
for i in l:
|
||||
if i==0 or i==39 or i==49 or i==27:
|
||||
self.sgr=0x000700
|
||||
elif i==1:
|
||||
self.sgr=(self.sgr|0x000800)
|
||||
elif i==7:
|
||||
self.sgr=0x070000
|
||||
elif i>=30 and i<=37:
|
||||
c=i-30
|
||||
self.sgr=(self.sgr&0xff08ff)|(c<<8)
|
||||
elif i>=40 and i<=47:
|
||||
c=i-40
|
||||
self.sgr=(self.sgr&0x00ffff)|(c<<16)
|
||||
# else:
|
||||
# print "CSI sgr ignore",l,i
|
||||
# print 'sgr: %r %x'%(l,self.sgr)
|
||||
def csi_r(self,l):
|
||||
if len(l)<2: l=[0,self.height]
|
||||
self.st=min(self.height-1,l[0]-1)
|
||||
self.sb=min(self.height-1,l[1]-1)
|
||||
self.sb=max(self.st,self.sb)
|
||||
def csi_s(self,l):
|
||||
self.esc_save(0)
|
||||
def csi_u(self,l):
|
||||
self.esc_restore(0)
|
||||
def escape(self):
|
||||
e=self.buf
|
||||
if len(e)>32:
|
||||
# print "error %r"%e
|
||||
self.buf=""
|
||||
elif e in self.esc_seq:
|
||||
self.esc_seq[e](e)
|
||||
self.buf=""
|
||||
else:
|
||||
for r,f in self.esc_re:
|
||||
mo=r.match(e)
|
||||
if mo:
|
||||
f(e,mo)
|
||||
self.buf=""
|
||||
break
|
||||
# if self.buf=='': print "ESC %r\n"%e
|
||||
def write(self,s):
|
||||
for i in s:
|
||||
if len(self.buf) or (i in self.esc_seq):
|
||||
self.buf+=i
|
||||
self.escape()
|
||||
elif i == '\x1b':
|
||||
self.buf+=i
|
||||
else:
|
||||
self.echo(i)
|
||||
def read(self):
|
||||
b=self.outbuf
|
||||
self.outbuf=""
|
||||
return b
|
||||
def dump(self):
|
||||
r=''
|
||||
for i in self.scr:
|
||||
r+=chr(i&255)
|
||||
return r
|
||||
def dumplatin1(self):
|
||||
return self.dump().translate(self.trl1)
|
||||
def dumphtml(self,color=1):
|
||||
h=self.height
|
||||
w=self.width
|
||||
r=""
|
||||
span=""
|
||||
span_bg,span_fg=-1,-1
|
||||
for i in range(h*w):
|
||||
q,c=divmod(self.scr[i],256)
|
||||
if color:
|
||||
bg,fg=divmod(q,256)
|
||||
else:
|
||||
bg,fg=0,7
|
||||
if i==self.cy*w+self.cx:
|
||||
bg,fg=1,7
|
||||
if (bg!=span_bg or fg!=span_fg or i==h*w-1):
|
||||
if len(span):
|
||||
r+='<span class="f%d b%d">%s</span>'%(span_fg,span_bg,cgi.escape(span.translate(self.trhtml)))
|
||||
span=""
|
||||
span_bg,span_fg=bg,fg
|
||||
span+=chr(c)
|
||||
if i%w==w-1:
|
||||
span+='\n'
|
||||
r='<?xml version="1.0" encoding="ISO-8859-1"?><pre class="term">%s</pre>'%r
|
||||
if self.last_html==r:
|
||||
return '<?xml version="1.0"?><idem></idem>'
|
||||
else:
|
||||
self.last_html=r
|
||||
# print self
|
||||
return r
|
||||
def __repr__(self):
|
||||
d=self.dumplatin1()
|
||||
r=""
|
||||
for i in range(self.height):
|
||||
r+="|%s|\n"%d[self.width*i:self.width*(i+1)]
|
||||
return r
|
||||
|
||||
class SynchronizedMethod:
|
||||
def __init__(self,lock,orig):
|
||||
self.lock=lock
|
||||
self.orig=orig
|
||||
def __call__(self,*l):
|
||||
self.lock.acquire()
|
||||
r=self.orig(*l)
|
||||
self.lock.release()
|
||||
return r
|
||||
|
||||
class Multiplex:
|
||||
def __init__(self,cmd=None):
|
||||
signal.signal(signal.SIGCHLD, signal.SIG_IGN)
|
||||
self.cmd=cmd
|
||||
self.proc={}
|
||||
self.lock=threading.RLock()
|
||||
self.thread=threading.Thread(target=self.loop)
|
||||
self.alive=1
|
||||
self.lastActivity=time.time()
|
||||
# synchronize methods
|
||||
for name in ['create','fds','proc_read','proc_write','dump','die','run']:
|
||||
orig=getattr(self,name)
|
||||
setattr(self,name,SynchronizedMethod(self.lock,orig))
|
||||
self.thread.start()
|
||||
def create(self,w=80,h=25):
|
||||
pid,fd=pty.fork()
|
||||
if pid==0:
|
||||
try:
|
||||
fdl=[int(i) for i in os.listdir('/proc/self/fd')]
|
||||
except OSError:
|
||||
fdl=range(256)
|
||||
for i in [i for i in fdl if i>2]:
|
||||
try:
|
||||
os.close(i)
|
||||
except OSError:
|
||||
pass
|
||||
if self.cmd:
|
||||
cmd=['/bin/sh','-c',self.cmd]
|
||||
elif os.getuid()==0:
|
||||
cmd=['/bin/login']
|
||||
else:
|
||||
sys.stdout.write("Login: ")
|
||||
login=sys.stdin.readline().strip()
|
||||
if re.match('^[0-9A-Za-z-_. ]+$',login):
|
||||
cmd=['ssh']
|
||||
cmd+=['-oPreferredAuthentications=keyboard-interactive,password']
|
||||
cmd+=['-oNoHostAuthenticationForLocalhost=yes']
|
||||
cmd+=['-oLogLevel=FATAL']
|
||||
cmd+=['-F/dev/null','-l',login,'localhost']
|
||||
else:
|
||||
os._exit(0)
|
||||
env={}
|
||||
env["COLUMNS"]=str(w)
|
||||
env["LINES"]=str(h)
|
||||
env["TERM"]="linux"
|
||||
env["PATH"]=os.environ['PATH']
|
||||
os.execvpe(cmd[0],cmd,env)
|
||||
else:
|
||||
fcntl.fcntl(fd, fcntl.F_SETFL, os.O_NONBLOCK)
|
||||
# python bug http://python.org/sf/1112949 on amd64
|
||||
fcntl.ioctl(fd, struct.unpack('i',struct.pack('I',termios.TIOCSWINSZ))[0], struct.pack("HHHH",h,w,0,0))
|
||||
self.proc[fd]={'pid':pid,'term':Terminal(w,h),'buf':'','time':time.time()}
|
||||
return fd
|
||||
def die(self):
|
||||
self.alive=0
|
||||
def run(self):
|
||||
return self.alive
|
||||
def fds(self):
|
||||
return self.proc.keys()
|
||||
def proc_kill(self,fd):
|
||||
if fd in self.proc:
|
||||
self.proc[fd]['time']=0
|
||||
t=time.time()
|
||||
for i in self.proc.keys():
|
||||
t0=self.proc[i]['time']
|
||||
if (t-t0)>TIMEOUT:
|
||||
try:
|
||||
os.close(i)
|
||||
os.kill(self.proc[i]['pid'],signal.SIGTERM)
|
||||
except (IOError,OSError):
|
||||
pass
|
||||
del self.proc[i]
|
||||
def proc_read(self,fd):
|
||||
try:
|
||||
t=self.proc[fd]['term']
|
||||
t.write(os.read(fd,65536))
|
||||
reply=t.read()
|
||||
if reply:
|
||||
os.write(fd,reply)
|
||||
self.proc[fd]['time']=time.time()
|
||||
except (KeyError,IOError,OSError):
|
||||
self.proc_kill(fd)
|
||||
def proc_write(self,fd,s):
|
||||
try:
|
||||
os.write(fd,s)
|
||||
except (IOError,OSError):
|
||||
self.proc_kill(fd)
|
||||
def dump(self,fd,color=1):
|
||||
try:
|
||||
return self.proc[fd]['term'].dumphtml(color)
|
||||
except KeyError:
|
||||
return False
|
||||
def loop(self):
|
||||
while self.run():
|
||||
fds=self.fds()
|
||||
i,o,e=select.select(fds, [], [], 1.0)
|
||||
if time.time() - self.lastActivity > TIMEOUT:
|
||||
global g_server
|
||||
g_server.shutdown()
|
||||
for fd in i:
|
||||
self.proc_read(fd)
|
||||
if len(i):
|
||||
time.sleep(0.002)
|
||||
for i in self.proc.keys():
|
||||
try:
|
||||
os.close(i)
|
||||
os.kill(self.proc[i]['pid'],signal.SIGTERM)
|
||||
except (IOError,OSError):
|
||||
pass
|
||||
|
||||
class AjaxTerm:
|
||||
def __init__(self,cmd=None,index_file='ajaxterm.html',token=None):
|
||||
self.files={}
|
||||
self.token=token
|
||||
for i in ['css','html','js']:
|
||||
for j in glob.glob('*.%s'%i):
|
||||
self.files[j]=file(j).read()
|
||||
self.files['index']=file(index_file).read()
|
||||
self.mime = mimetypes.types_map.copy()
|
||||
self.mime['.html']= 'text/html; charset=UTF-8'
|
||||
self.multi = Multiplex(cmd)
|
||||
self.session = {}
|
||||
def __call__(self, environ, start_response):
|
||||
req = qweb.QWebRequest(environ, start_response,session=None)
|
||||
if req.PATH_INFO.endswith('/u'):
|
||||
s=req.REQUEST["s"]
|
||||
k=req.REQUEST["k"]
|
||||
c=req.REQUEST["c"]
|
||||
w=req.REQUEST.int("w")
|
||||
h=req.REQUEST.int("h")
|
||||
if s in self.session:
|
||||
term=self.session[s]
|
||||
else:
|
||||
raise Exception('Not Authorized')
|
||||
# The original code below was insecure, because it allowed unauthorized sessions to be created
|
||||
# if not (w>2 and w<256 and h>2 and h<100):
|
||||
# w,h=80,25
|
||||
# term=self.session[s]=self.multi.create(w,h)
|
||||
if k:
|
||||
self.multi.proc_write(term,k)
|
||||
time.sleep(0.002)
|
||||
self.multi.lastActivity = time.time();
|
||||
dump=self.multi.dump(term,c)
|
||||
req.response_headers['Content-Type']='text/xml'
|
||||
if isinstance(dump,str):
|
||||
req.write(dump)
|
||||
req.response_gzencode=1
|
||||
else:
|
||||
del self.session[s]
|
||||
req.write('<?xml version="1.0"?><idem></idem>')
|
||||
# print "sessions %r"%self.session
|
||||
else:
|
||||
n=os.path.basename(req.PATH_INFO)
|
||||
if n in self.files:
|
||||
req.response_headers['Content-Type'] = self.mime.get(os.path.splitext(n)[1].lower(), 'application/octet-stream')
|
||||
req.write(self.files[n])
|
||||
elif req.REQUEST['token'] == self.token:
|
||||
req.response_headers['Content-Type'] = 'text/html; charset=UTF-8'
|
||||
session_id = str(uuid.uuid4())
|
||||
req.write(string.Template(self.files['index']).substitute(session_id=session_id))
|
||||
term=self.session[session_id]=self.multi.create(80,25)
|
||||
else:
|
||||
raise Exception("Not Authorized")
|
||||
return req
|
||||
|
||||
def main():
|
||||
parser = optparse.OptionParser()
|
||||
parser.add_option("-p", "--port", dest="port", default="8022", help="Set the TCP port (default: 8022)")
|
||||
parser.add_option("-c", "--command", dest="cmd", default=None,help="set the command (default: /bin/login or ssh 0.0.0.0)")
|
||||
parser.add_option("-l", "--log", action="store_true", dest="log",default=0,help="log requests to stderr (default: quiet mode)")
|
||||
parser.add_option("-d", "--daemon", action="store_true", dest="daemon", default=0, help="run as daemon in the background")
|
||||
parser.add_option("-P", "--pidfile",dest="pidfile",default="/var/run/ajaxterm.pid",help="set the pidfile (default: /var/run/ajaxterm.pid)")
|
||||
parser.add_option("-i", "--index", dest="index_file", default="ajaxterm.html",help="default index file (default: ajaxterm.html)")
|
||||
parser.add_option("-u", "--uid", dest="uid", help="Set the daemon's user id")
|
||||
parser.add_option("-t", "--token", dest="token", help="Set authorization token")
|
||||
(o, a) = parser.parse_args()
|
||||
if o.daemon:
|
||||
pid=os.fork()
|
||||
if pid == 0:
|
||||
#os.setsid() ?
|
||||
os.setpgrp()
|
||||
nullin = file('/dev/null', 'r')
|
||||
nullout = file('/dev/null', 'w')
|
||||
os.dup2(nullin.fileno(), sys.stdin.fileno())
|
||||
os.dup2(nullout.fileno(), sys.stdout.fileno())
|
||||
os.dup2(nullout.fileno(), sys.stderr.fileno())
|
||||
if os.getuid()==0 and o.uid:
|
||||
try:
|
||||
os.setuid(int(o.uid))
|
||||
except:
|
||||
os.setuid(pwd.getpwnam(o.uid).pw_uid)
|
||||
else:
|
||||
try:
|
||||
file(o.pidfile,'w+').write(str(pid)+'\n')
|
||||
except:
|
||||
pass
|
||||
print 'AjaxTerm at http://0.0.0.0:%s/ pid: %d' % (o.port,pid)
|
||||
sys.exit(0)
|
||||
else:
|
||||
print 'AjaxTerm at http://0.0.0.0:%s/' % o.port
|
||||
at=AjaxTerm(o.cmd,o.index_file,o.token)
|
||||
# f=lambda:os.system('firefox http://localhost:%s/&'%o.port)
|
||||
# qweb.qweb_wsgi_autorun(at,ip='localhost',port=int(o.port),threaded=0,log=o.log,callback_ready=None)
|
||||
try:
|
||||
global g_server
|
||||
g_server = qweb.QWebWSGIServer(at,ip='0.0.0.0',port=int(o.port),threaded=0,log=o.log)
|
||||
g_server.serve_forever()
|
||||
except KeyboardInterrupt,e:
|
||||
sys.excepthook(*sys.exc_info())
|
||||
at.multi.die()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import optparse,os
|
||||
|
||||
parser = optparse.OptionParser()
|
||||
parser.add_option("", "--prefix", dest="prefix",default="/usr/local",help="installation prefix (default: /usr/local)")
|
||||
parser.add_option("", "--confdir", dest="confdir", default="/etc",help="configuration files directory prefix (default: /etc)")
|
||||
parser.add_option("", "--port", dest="port", default="8022", help="set the listening TCP port (default: 8022)")
|
||||
parser.add_option("", "--command", dest="cmd", default=None,help="set the command (default: /bin/login or ssh localhost)")
|
||||
(o, a) = parser.parse_args()
|
||||
|
||||
print "Configuring prefix=",o.prefix," port=",o.port
|
||||
|
||||
etc=o.confdir
|
||||
port=o.port
|
||||
cmd=o.cmd
|
||||
bin=os.path.join(o.prefix,"bin")
|
||||
lib=os.path.join(o.prefix,"share/ajaxterm")
|
||||
man=os.path.join(o.prefix,"share/man/man1")
|
||||
|
||||
file("ajaxterm.bin","w").write(file("configure.ajaxterm.bin").read()%locals())
|
||||
file("Makefile","w").write(file("configure.makefile").read()%locals())
|
||||
|
||||
if os.path.isfile("/etc/gentoo-release"):
|
||||
file("ajaxterm.initd","w").write(file("configure.initd.gentoo").read()%locals())
|
||||
elif os.path.isfile("/etc/fedora-release") or os.path.isfile("/etc/redhat-release"):
|
||||
file("ajaxterm.initd","w").write(file("configure.initd.redhat").read()%locals())
|
||||
else:
|
||||
file("ajaxterm.initd","w").write(file("configure.initd.debian").read()%locals())
|
||||
|
||||
os.system("chmod a+x ajaxterm.bin")
|
||||
os.system("chmod a+x ajaxterm.initd")
|
|
@ -1,2 +0,0 @@
|
|||
#!/bin/sh
|
||||
PYTHONPATH=%(lib)s exec %(lib)s/ajaxterm.py $@
|
|
@ -1,33 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
PATH=/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin
|
||||
DAEMON=%(bin)s/ajaxterm
|
||||
PORT=%(port)s
|
||||
PIDFILE=/var/run/ajaxterm.pid
|
||||
|
||||
[ -x "$DAEMON" ] || exit 0
|
||||
|
||||
#. /lib/lsb/init-functions
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
echo "Starting ajaxterm on port $PORT"
|
||||
start-stop-daemon --start --pidfile $PIDFILE --exec $DAEMON -- --daemon --port=$PORT --uid=nobody || return 2
|
||||
;;
|
||||
stop)
|
||||
echo "Stopping ajaxterm"
|
||||
start-stop-daemon --stop --pidfile $PIDFILE
|
||||
rm -f $PIDFILE
|
||||
;;
|
||||
restart|force-reload)
|
||||
$0 stop
|
||||
sleep 1
|
||||
$0 start
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload}" >&2
|
||||
exit 3
|
||||
;;
|
||||
esac
|
||||
|
||||
:
|
|
@ -1,27 +0,0 @@
|
|||
#!/sbin/runscript
|
||||
|
||||
# AjaxTerm Gentoo script, 08 May 2006 Mark Gillespie
|
||||
|
||||
DAEMON=%(bin)s/ajaxterm
|
||||
PORT=%(port)s
|
||||
PIDFILE=/var/run/ajaxterm.pid
|
||||
|
||||
depend()
|
||||
{
|
||||
need net
|
||||
}
|
||||
|
||||
start()
|
||||
{
|
||||
ebegin "Starting AjaxTerm on port $PORT"
|
||||
start-stop-daemon --start --pidfile $PIDFILE --exec $DAEMON -- --daemon --port=$PORT --uid=nobody
|
||||
eend $?
|
||||
}
|
||||
|
||||
stop()
|
||||
{
|
||||
ebegin "Stopping AjaxTerm"
|
||||
start-stop-daemon --stop --pidfile $PIDFILE
|
||||
rm -f $PIDFILE
|
||||
eend $?
|
||||
}
|
|
@ -1,75 +0,0 @@
|
|||
#
|
||||
# ajaxterm Startup script for ajaxterm
|
||||
#
|
||||
# chkconfig: - 99 99
|
||||
# description: Ajaxterm is a yadda yadda yadda
|
||||
# processname: ajaxterm
|
||||
# pidfile: /var/run/ajaxterm.pid
|
||||
# version: 1.0 Kevin Reichhart - ajaxterminit at lastname dot org
|
||||
|
||||
# Source function library.
|
||||
. /etc/rc.d/init.d/functions
|
||||
|
||||
if [ -f /etc/sysconfig/ajaxterm ]; then
|
||||
. /etc/sysconfig/ajaxterm
|
||||
fi
|
||||
|
||||
ajaxterm=/usr/local/bin/ajaxterm
|
||||
prog=ajaxterm
|
||||
pidfile=${PIDFILE-/var/run/ajaxterm.pid}
|
||||
lockfile=${LOCKFILE-/var/lock/subsys/ajaxterm}
|
||||
port=${PORT-8022}
|
||||
user=${xUSER-nobody}
|
||||
RETVAL=0
|
||||
|
||||
|
||||
start() {
|
||||
echo -n $"Starting $prog: "
|
||||
daemon $ajaxterm --daemon --port=$port --uid=$user $OPTIONS
|
||||
RETVAL=$?
|
||||
echo
|
||||
[ $RETVAL = 0 ] && touch ${lockfile}
|
||||
return $RETVAL
|
||||
}
|
||||
stop() {
|
||||
echo -n $"Stopping $prog: "
|
||||
killproc $ajaxterm
|
||||
RETVAL=$?
|
||||
echo
|
||||
[ $RETVAL = 0 ] && rm -f ${lockfile} ${pidfile}
|
||||
}
|
||||
reload() {
|
||||
echo -n $"Reloading $prog: "
|
||||
killproc $ajaxterm -HUP
|
||||
RETVAL=$?
|
||||
echo
|
||||
}
|
||||
|
||||
# See how we were called.
|
||||
case "$1" in
|
||||
start)
|
||||
start
|
||||
;;
|
||||
stop)
|
||||
stop
|
||||
;;
|
||||
status)
|
||||
status python ajaxterm
|
||||
RETVAL=$?
|
||||
;;
|
||||
restart)
|
||||
stop
|
||||
start
|
||||
;;
|
||||
condrestart)
|
||||
if [ -f ${pidfile} ] ; then
|
||||
stop
|
||||
start
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo $"Usage: $prog {start|stop|restart|condrestart}"
|
||||
exit 1
|
||||
esac
|
||||
|
||||
exit $RETVAL
|
|
@ -1,20 +0,0 @@
|
|||
build:
|
||||
true
|
||||
|
||||
install:
|
||||
install -d "%(bin)s"
|
||||
install -d "%(lib)s"
|
||||
install ajaxterm.bin "%(bin)s/ajaxterm"
|
||||
install ajaxterm.initd "%(etc)s/init.d/ajaxterm"
|
||||
install -m 644 ajaxterm.css ajaxterm.html ajaxterm.js qweb.py sarissa.js sarissa_dhtml.js "%(lib)s"
|
||||
install -m 755 ajaxterm.py "%(lib)s"
|
||||
gzip --best -c ajaxterm.1 > ajaxterm.1.gz
|
||||
install -d "%(man)s"
|
||||
install ajaxterm.1.gz "%(man)s"
|
||||
|
||||
clean:
|
||||
rm ajaxterm.bin
|
||||
rm ajaxterm.initd
|
||||
rm ajaxterm.1.gz
|
||||
rm Makefile
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -1,647 +0,0 @@
|
|||
/**
|
||||
* ====================================================================
|
||||
* About
|
||||
* ====================================================================
|
||||
* Sarissa is an ECMAScript library acting as a cross-browser wrapper for native XML APIs.
|
||||
* The library supports Gecko based browsers like Mozilla and Firefox,
|
||||
* Internet Explorer (5.5+ with MSXML3.0+), Konqueror, Safari and a little of Opera
|
||||
* @version 0.9.6.1
|
||||
* @author: Manos Batsis, mailto: mbatsis at users full stop sourceforge full stop net
|
||||
* ====================================================================
|
||||
* Licence
|
||||
* ====================================================================
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 or
|
||||
* the GNU Lesser General Public License version 2.1 as published by
|
||||
* the Free Software Foundation (your choice between the two).
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License or GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* or GNU Lesser General Public License along with this program; if not,
|
||||
* write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* or visit http://www.gnu.org
|
||||
*
|
||||
*/
|
||||
/**
|
||||
* <p>Sarissa is a utility class. Provides "static" methods for DOMDocument and
|
||||
* XMLHTTP objects, DOM Node serializatrion to XML strings and other goodies.</p>
|
||||
* @constructor
|
||||
*/
|
||||
function Sarissa(){};
|
||||
/** @private */
|
||||
Sarissa.PARSED_OK = "Document contains no parsing errors";
|
||||
/**
|
||||
* Tells you whether transformNode and transformNodeToObject are available. This functionality
|
||||
* is contained in sarissa_ieemu_xslt.js and is deprecated. If you want to control XSLT transformations
|
||||
* use the XSLTProcessor
|
||||
* @deprecated
|
||||
* @type boolean
|
||||
*/
|
||||
Sarissa.IS_ENABLED_TRANSFORM_NODE = false;
|
||||
/**
|
||||
* tells you whether XMLHttpRequest (or equivalent) is available
|
||||
* @type boolean
|
||||
*/
|
||||
Sarissa.IS_ENABLED_XMLHTTP = false;
|
||||
/**
|
||||
* tells you whether selectNodes/selectSingleNode is available
|
||||
* @type boolean
|
||||
*/
|
||||
Sarissa.IS_ENABLED_SELECT_NODES = false;
|
||||
var _sarissa_iNsCounter = 0;
|
||||
var _SARISSA_IEPREFIX4XSLPARAM = "";
|
||||
var _SARISSA_HAS_DOM_IMPLEMENTATION = document.implementation && true;
|
||||
var _SARISSA_HAS_DOM_CREATE_DOCUMENT = _SARISSA_HAS_DOM_IMPLEMENTATION && document.implementation.createDocument;
|
||||
var _SARISSA_HAS_DOM_FEATURE = _SARISSA_HAS_DOM_IMPLEMENTATION && document.implementation.hasFeature;
|
||||
var _SARISSA_IS_MOZ = _SARISSA_HAS_DOM_CREATE_DOCUMENT && _SARISSA_HAS_DOM_FEATURE;
|
||||
var _SARISSA_IS_SAFARI = (navigator.userAgent && navigator.vendor && (navigator.userAgent.toLowerCase().indexOf("applewebkit") != -1 || navigator.vendor.indexOf("Apple") != -1));
|
||||
var _SARISSA_IS_IE = document.all && window.ActiveXObject && navigator.userAgent.toLowerCase().indexOf("msie") > -1 && navigator.userAgent.toLowerCase().indexOf("opera") == -1;
|
||||
if(!window.Node || !window.Node.ELEMENT_NODE){
|
||||
var Node = {ELEMENT_NODE: 1, ATTRIBUTE_NODE: 2, TEXT_NODE: 3, CDATA_SECTION_NODE: 4, ENTITY_REFERENCE_NODE: 5, ENTITY_NODE: 6, PROCESSING_INSTRUCTION_NODE: 7, COMMENT_NODE: 8, DOCUMENT_NODE: 9, DOCUMENT_TYPE_NODE: 10, DOCUMENT_FRAGMENT_NODE: 11, NOTATION_NODE: 12};
|
||||
};
|
||||
|
||||
// IE initialization
|
||||
if(_SARISSA_IS_IE){
|
||||
// for XSLT parameter names, prefix needed by IE
|
||||
_SARISSA_IEPREFIX4XSLPARAM = "xsl:";
|
||||
// used to store the most recent ProgID available out of the above
|
||||
var _SARISSA_DOM_PROGID = "";
|
||||
var _SARISSA_XMLHTTP_PROGID = "";
|
||||
/**
|
||||
* Called when the Sarissa_xx.js file is parsed, to pick most recent
|
||||
* ProgIDs for IE, then gets destroyed.
|
||||
* @param idList an array of MSXML PROGIDs from which the most recent will be picked for a given object
|
||||
* @param enabledList an array of arrays where each array has two items; the index of the PROGID for which a certain feature is enabled
|
||||
*/
|
||||
pickRecentProgID = function (idList, enabledList){
|
||||
// found progID flag
|
||||
var bFound = false;
|
||||
for(var i=0; i < idList.length && !bFound; i++){
|
||||
try{
|
||||
var oDoc = new ActiveXObject(idList[i]);
|
||||
o2Store = idList[i];
|
||||
bFound = true;
|
||||
for(var j=0;j<enabledList.length;j++)
|
||||
if(i <= enabledList[j][1])
|
||||
Sarissa["IS_ENABLED_"+enabledList[j][0]] = true;
|
||||
}catch (objException){
|
||||
// trap; try next progID
|
||||
};
|
||||
};
|
||||
if (!bFound)
|
||||
throw "Could not retreive a valid progID of Class: " + idList[idList.length-1]+". (original exception: "+e+")";
|
||||
idList = null;
|
||||
return o2Store;
|
||||
};
|
||||
// pick best available MSXML progIDs
|
||||
_SARISSA_DOM_PROGID = pickRecentProgID(["Msxml2.DOMDocument.5.0", "Msxml2.DOMDocument.4.0", "Msxml2.DOMDocument.3.0", "MSXML2.DOMDocument", "MSXML.DOMDocument", "Microsoft.XMLDOM"], [["SELECT_NODES", 2],["TRANSFORM_NODE", 2]]);
|
||||
_SARISSA_XMLHTTP_PROGID = pickRecentProgID(["Msxml2.XMLHTTP.5.0", "Msxml2.XMLHTTP.4.0", "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP", "Microsoft.XMLHTTP"], [["XMLHTTP", 4]]);
|
||||
_SARISSA_THREADEDDOM_PROGID = pickRecentProgID(["Msxml2.FreeThreadedDOMDocument.5.0", "MSXML2.FreeThreadedDOMDocument.4.0", "MSXML2.FreeThreadedDOMDocument.3.0"]);
|
||||
_SARISSA_XSLTEMPLATE_PROGID = pickRecentProgID(["Msxml2.XSLTemplate.5.0", "Msxml2.XSLTemplate.4.0", "MSXML2.XSLTemplate.3.0"], [["XSLTPROC", 2]]);
|
||||
// we dont need this anymore
|
||||
pickRecentProgID = null;
|
||||
//============================================
|
||||
// Factory methods (IE)
|
||||
//============================================
|
||||
// see non-IE version
|
||||
Sarissa.getDomDocument = function(sUri, sName){
|
||||
var oDoc = new ActiveXObject(_SARISSA_DOM_PROGID);
|
||||
// if a root tag name was provided, we need to load it in the DOM
|
||||
// object
|
||||
if (sName){
|
||||
// if needed, create an artifical namespace prefix the way Moz
|
||||
// does
|
||||
if (sUri){
|
||||
oDoc.loadXML("<a" + _sarissa_iNsCounter + ":" + sName + " xmlns:a" + _sarissa_iNsCounter + "=\"" + sUri + "\" />");
|
||||
// don't use the same prefix again
|
||||
++_sarissa_iNsCounter;
|
||||
}
|
||||
else
|
||||
oDoc.loadXML("<" + sName + "/>");
|
||||
};
|
||||
return oDoc;
|
||||
};
|
||||
// see non-IE version
|
||||
Sarissa.getParseErrorText = function (oDoc) {
|
||||
var parseErrorText = Sarissa.PARSED_OK;
|
||||
if(oDoc.parseError != 0){
|
||||
parseErrorText = "XML Parsing Error: " + oDoc.parseError.reason +
|
||||
"\nLocation: " + oDoc.parseError.url +
|
||||
"\nLine Number " + oDoc.parseError.line + ", Column " +
|
||||
oDoc.parseError.linepos +
|
||||
":\n" + oDoc.parseError.srcText +
|
||||
"\n";
|
||||
for(var i = 0; i < oDoc.parseError.linepos;i++){
|
||||
parseErrorText += "-";
|
||||
};
|
||||
parseErrorText += "^\n";
|
||||
};
|
||||
return parseErrorText;
|
||||
};
|
||||
// see non-IE version
|
||||
Sarissa.setXpathNamespaces = function(oDoc, sNsSet) {
|
||||
oDoc.setProperty("SelectionLanguage", "XPath");
|
||||
oDoc.setProperty("SelectionNamespaces", sNsSet);
|
||||
};
|
||||
/**
|
||||
* Basic implementation of Mozilla's XSLTProcessor for IE.
|
||||
* Reuses the same XSLT stylesheet for multiple transforms
|
||||
* @constructor
|
||||
*/
|
||||
XSLTProcessor = function(){
|
||||
this.template = new ActiveXObject(_SARISSA_XSLTEMPLATE_PROGID);
|
||||
this.processor = null;
|
||||
};
|
||||
/**
|
||||
* Impoprts the given XSLT DOM and compiles it to a reusable transform
|
||||
* @argument xslDoc The XSLT DOMDocument to import
|
||||
*/
|
||||
XSLTProcessor.prototype.importStylesheet = function(xslDoc){
|
||||
// convert stylesheet to free threaded
|
||||
var converted = new ActiveXObject(_SARISSA_THREADEDDOM_PROGID);
|
||||
converted.loadXML(xslDoc.xml);
|
||||
this.template.stylesheet = converted;
|
||||
this.processor = this.template.createProcessor();
|
||||
// (re)set default param values
|
||||
this.paramsSet = new Array();
|
||||
};
|
||||
/**
|
||||
* Transform the given XML DOM
|
||||
* @argument sourceDoc The XML DOMDocument to transform
|
||||
* @return The transformation result as a DOM Document
|
||||
*/
|
||||
XSLTProcessor.prototype.transformToDocument = function(sourceDoc){
|
||||
this.processor.input = sourceDoc;
|
||||
var outDoc = new ActiveXObject(_SARISSA_DOM_PROGID);
|
||||
this.processor.output = outDoc;
|
||||
this.processor.transform();
|
||||
return outDoc;
|
||||
};
|
||||
/**
|
||||
* Set global XSLT parameter of the imported stylesheet
|
||||
* @argument nsURI The parameter namespace URI
|
||||
* @argument name The parameter base name
|
||||
* @argument value The new parameter value
|
||||
*/
|
||||
XSLTProcessor.prototype.setParameter = function(nsURI, name, value){
|
||||
/* nsURI is optional but cannot be null */
|
||||
if(nsURI){
|
||||
this.processor.addParameter(name, value, nsURI);
|
||||
}else{
|
||||
this.processor.addParameter(name, value);
|
||||
};
|
||||
/* update updated params for getParameter */
|
||||
if(!this.paramsSet[""+nsURI]){
|
||||
this.paramsSet[""+nsURI] = new Array();
|
||||
};
|
||||
this.paramsSet[""+nsURI][name] = value;
|
||||
};
|
||||
/**
|
||||
* Gets a parameter if previously set by setParameter. Returns null
|
||||
* otherwise
|
||||
* @argument name The parameter base name
|
||||
* @argument value The new parameter value
|
||||
* @return The parameter value if reviously set by setParameter, null otherwise
|
||||
*/
|
||||
XSLTProcessor.prototype.getParameter = function(nsURI, name){
|
||||
nsURI = nsURI || "";
|
||||
if(nsURI in this.paramsSet && name in this.paramsSet[nsURI]){
|
||||
return this.paramsSet[nsURI][name];
|
||||
}else{
|
||||
return null;
|
||||
};
|
||||
};
|
||||
}
|
||||
else{ /* end IE initialization, try to deal with real browsers now ;-) */
|
||||
if(_SARISSA_HAS_DOM_CREATE_DOCUMENT){
|
||||
/**
|
||||
* <p>Ensures the document was loaded correctly, otherwise sets the
|
||||
* parseError to -1 to indicate something went wrong. Internal use</p>
|
||||
* @private
|
||||
*/
|
||||
Sarissa.__handleLoad__ = function(oDoc){
|
||||
if (!oDoc.documentElement || oDoc.documentElement.tagName == "parsererror")
|
||||
oDoc.parseError = -1;
|
||||
Sarissa.__setReadyState__(oDoc, 4);
|
||||
};
|
||||
/**
|
||||
* <p>Attached by an event handler to the load event. Internal use.</p>
|
||||
* @private
|
||||
*/
|
||||
_sarissa_XMLDocument_onload = function(){
|
||||
Sarissa.__handleLoad__(this);
|
||||
};
|
||||
/**
|
||||
* <p>Sets the readyState property of the given DOM Document object.
|
||||
* Internal use.</p>
|
||||
* @private
|
||||
* @argument oDoc the DOM Document object to fire the
|
||||
* readystatechange event
|
||||
* @argument iReadyState the number to change the readystate property to
|
||||
*/
|
||||
Sarissa.__setReadyState__ = function(oDoc, iReadyState){
|
||||
oDoc.readyState = iReadyState;
|
||||
if (oDoc.onreadystatechange != null && typeof oDoc.onreadystatechange == "function")
|
||||
oDoc.onreadystatechange();
|
||||
};
|
||||
Sarissa.getDomDocument = function(sUri, sName){
|
||||
var oDoc = document.implementation.createDocument(sUri?sUri:"", sName?sName:"", null);
|
||||
oDoc.addEventListener("load", _sarissa_XMLDocument_onload, false);
|
||||
return oDoc;
|
||||
};
|
||||
if(false && window.XMLDocument){
|
||||
/**
|
||||
* <p>Emulate IE's onreadystatechange attribute</p>
|
||||
*/
|
||||
XMLDocument.prototype.onreadystatechange = null;
|
||||
/**
|
||||
* <p>Emulates IE's readyState property, which always gives an integer from 0 to 4:</p>
|
||||
* <ul><li>1 == LOADING,</li>
|
||||
* <li>2 == LOADED,</li>
|
||||
* <li>3 == INTERACTIVE,</li>
|
||||
* <li>4 == COMPLETED</li></ul>
|
||||
*/
|
||||
XMLDocument.prototype.readyState = 0;
|
||||
/**
|
||||
* <p>Emulate IE's parseError attribute</p>
|
||||
*/
|
||||
XMLDocument.prototype.parseError = 0;
|
||||
|
||||
// NOTE: setting async to false will only work with documents
|
||||
// called over HTTP (meaning a server), not the local file system,
|
||||
// unless you are using Moz 1.4+.
|
||||
// BTW the try>catch block is for 1.4; I haven't found a way to check if
|
||||
// the property is implemented without
|
||||
// causing an error and I dont want to use user agent stuff for that...
|
||||
var _SARISSA_SYNC_NON_IMPLEMENTED = false;// ("async" in XMLDocument.prototype) ? false: true;
|
||||
/**
|
||||
* <p>Keeps a handle to the original load() method. Internal use and only
|
||||
* if Mozilla version is lower than 1.4</p>
|
||||
* @private
|
||||
*/
|
||||
XMLDocument.prototype._sarissa_load = XMLDocument.prototype.load;
|
||||
|
||||
/**
|
||||
* <p>Overrides the original load method to provide synchronous loading for
|
||||
* Mozilla versions prior to 1.4, using an XMLHttpRequest object (if
|
||||
* async is set to false)</p>
|
||||
* @returns the DOM Object as it was before the load() call (may be empty)
|
||||
*/
|
||||
XMLDocument.prototype.load = function(sURI) {
|
||||
var oDoc = document.implementation.createDocument("", "", null);
|
||||
Sarissa.copyChildNodes(this, oDoc);
|
||||
this.parseError = 0;
|
||||
Sarissa.__setReadyState__(this, 1);
|
||||
try {
|
||||
if(this.async == false && _SARISSA_SYNC_NON_IMPLEMENTED) {
|
||||
var tmp = new XMLHttpRequest();
|
||||
tmp.open("GET", sURI, false);
|
||||
tmp.send(null);
|
||||
Sarissa.__setReadyState__(this, 2);
|
||||
Sarissa.copyChildNodes(tmp.responseXML, this);
|
||||
Sarissa.__setReadyState__(this, 3);
|
||||
}
|
||||
else {
|
||||
this._sarissa_load(sURI);
|
||||
};
|
||||
}
|
||||
catch (objException) {
|
||||
this.parseError = -1;
|
||||
}
|
||||
finally {
|
||||
if(this.async == false){
|
||||
Sarissa.__handleLoad__(this);
|
||||
};
|
||||
};
|
||||
return oDoc;
|
||||
};
|
||||
|
||||
|
||||
}//if(window.XMLDocument)
|
||||
else if(document.implementation && document.implementation.hasFeature && document.implementation.hasFeature('LS', '3.0')){
|
||||
Document.prototype.async = true;
|
||||
Document.prototype.onreadystatechange = null;
|
||||
Document.prototype.parseError = 0;
|
||||
Document.prototype.load = function(sURI) {
|
||||
var parser = document.implementation.createLSParser(this.async ? document.implementation.MODE_ASYNCHRONOUS : document.implementation.MODE_SYNCHRONOUS, null);
|
||||
if(this.async){
|
||||
var self = this;
|
||||
parser.addEventListener("load",
|
||||
function(e) {
|
||||
self.readyState = 4;
|
||||
Sarissa.copyChildNodes(e.newDocument, self.documentElement, false);
|
||||
self.onreadystatechange.call();
|
||||
},
|
||||
false);
|
||||
};
|
||||
try {
|
||||
var oDoc = parser.parseURI(sURI);
|
||||
}
|
||||
catch(e){
|
||||
this.parseError = -1;
|
||||
};
|
||||
if(!this.async)
|
||||
Sarissa.copyChildNodes(oDoc, this.documentElement, false);
|
||||
return oDoc;
|
||||
};
|
||||
/**
|
||||
* <p>Factory method to obtain a new DOM Document object</p>
|
||||
* @argument sUri the namespace of the root node (if any)
|
||||
* @argument sUri the local name of the root node (if any)
|
||||
* @returns a new DOM Document
|
||||
*/
|
||||
Sarissa.getDomDocument = function(sUri, sName){
|
||||
return document.implementation.createDocument(sUri?sUri:"", sName?sName:"", null);
|
||||
};
|
||||
};
|
||||
};//if(_SARISSA_HAS_DOM_CREATE_DOCUMENT)
|
||||
};
|
||||
//==========================================
|
||||
// Common stuff
|
||||
//==========================================
|
||||
if(!window.DOMParser){
|
||||
/*
|
||||
* DOMParser is a utility class, used to construct DOMDocuments from XML strings
|
||||
* @constructor
|
||||
*/
|
||||
DOMParser = function() {
|
||||
};
|
||||
if(_SARISSA_IS_SAFARI){
|
||||
/**
|
||||
* Construct a new DOM Document from the given XMLstring
|
||||
* @param sXml the given XML string
|
||||
* @param contentType the content type of the document the given string represents (one of text/xml, application/xml, application/xhtml+xml).
|
||||
* @return a new DOM Document from the given XML string
|
||||
*/
|
||||
DOMParser.prototype.parseFromString = function(sXml, contentType){
|
||||
if(contentType.toLowerCase() != "application/xml"){
|
||||
throw "Cannot handle content type: \"" + contentType + "\"";
|
||||
};
|
||||
var xmlhttp = new XMLHttpRequest();
|
||||
xmlhttp.open("GET", "data:text/xml;charset=utf-8," + encodeURIComponent(str), false);
|
||||
xmlhttp.send(null);
|
||||
return xmlhttp.responseXML;
|
||||
};
|
||||
}else if(Sarissa.getDomDocument && Sarissa.getDomDocument() && "loadXML" in Sarissa.getDomDocument()){
|
||||
DOMParser.prototype.parseFromString = function(sXml, contentType){
|
||||
var doc = Sarissa.getDomDocument();
|
||||
doc.loadXML(sXml);
|
||||
return doc;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
if(window.XMLHttpRequest){
|
||||
Sarissa.IS_ENABLED_XMLHTTP = true;
|
||||
}
|
||||
else if(_SARISSA_IS_IE){
|
||||
/**
|
||||
* Emulate XMLHttpRequest
|
||||
* @constructor
|
||||
*/
|
||||
XMLHttpRequest = function() {
|
||||
return new ActiveXObject(_SARISSA_XMLHTTP_PROGID);
|
||||
};
|
||||
Sarissa.IS_ENABLED_XMLHTTP = true;
|
||||
};
|
||||
|
||||
if(!window.document.importNode && _SARISSA_IS_IE){
|
||||
try{
|
||||
/**
|
||||
* Implements importNode for the current window document in IE using innerHTML.
|
||||
* Testing showed that DOM was multiple times slower than innerHTML for this,
|
||||
* sorry folks. If you encounter trouble (who knows what IE does behind innerHTML)
|
||||
* please gimme a call.
|
||||
* @param oNode the Node to import
|
||||
* @param bChildren whether to include the children of oNode
|
||||
* @returns the imported node for further use
|
||||
*/
|
||||
window.document.importNode = function(oNode, bChildren){
|
||||
var importNode = document.createElement("div");
|
||||
if(bChildren)
|
||||
importNode.innerHTML = Sarissa.serialize(oNode);
|
||||
else
|
||||
importNode.innerHTML = Sarissa.serialize(oNode.cloneNode(false));
|
||||
return importNode.firstChild;
|
||||
};
|
||||
}catch(e){};
|
||||
};
|
||||
if(!Sarissa.getParseErrorText){
|
||||
/**
|
||||
* <p>Returns a human readable description of the parsing error. Usefull
|
||||
* for debugging. Tip: append the returned error string in a <pre>
|
||||
* element if you want to render it.</p>
|
||||
* <p>Many thanks to Christian Stocker for the initial patch.</p>
|
||||
* @argument oDoc The target DOM document
|
||||
* @returns The parsing error description of the target Document in
|
||||
* human readable form (preformated text)
|
||||
*/
|
||||
Sarissa.getParseErrorText = function (oDoc){
|
||||
var parseErrorText = Sarissa.PARSED_OK;
|
||||
if(oDoc && oDoc.parseError && oDoc.parseError != 0){
|
||||
/*moz*/
|
||||
if(oDoc.documentElement.tagName == "parsererror"){
|
||||
parseErrorText = oDoc.documentElement.firstChild.data;
|
||||
parseErrorText += "\n" + oDoc.documentElement.firstChild.nextSibling.firstChild.data;
|
||||
}/*konq*/
|
||||
else{
|
||||
parseErrorText = Sarissa.getText(oDoc.documentElement);/*.getElementsByTagName("h1")[0], false) + "\n";
|
||||
parseErrorText += Sarissa.getText(oDoc.documentElement.getElementsByTagName("body")[0], false) + "\n";
|
||||
parseErrorText += Sarissa.getText(oDoc.documentElement.getElementsByTagName("pre")[0], false);*/
|
||||
};
|
||||
};
|
||||
return parseErrorText;
|
||||
};
|
||||
};
|
||||
Sarissa.getText = function(oNode, deep){
|
||||
var s = "";
|
||||
var nodes = oNode.childNodes;
|
||||
for(var i=0; i < nodes.length; i++){
|
||||
var node = nodes[i];
|
||||
var nodeType = node.nodeType;
|
||||
if(nodeType == Node.TEXT_NODE || nodeType == Node.CDATA_SECTION_NODE){
|
||||
s += node.data;
|
||||
}else if(deep == true
|
||||
&& (nodeType == Node.ELEMENT_NODE
|
||||
|| nodeType == Node.DOCUMENT_NODE
|
||||
|| nodeType == Node.DOCUMENT_FRAGMENT_NODE)){
|
||||
s += Sarissa.getText(node, true);
|
||||
};
|
||||
};
|
||||
return s;
|
||||
};
|
||||
if(window.XMLSerializer){
|
||||
/**
|
||||
* <p>Factory method to obtain the serialization of a DOM Node</p>
|
||||
* @returns the serialized Node as an XML string
|
||||
*/
|
||||
Sarissa.serialize = function(oDoc){
|
||||
var s = null;
|
||||
if(oDoc){
|
||||
s = oDoc.innerHTML?oDoc.innerHTML:(new XMLSerializer()).serializeToString(oDoc);
|
||||
};
|
||||
return s;
|
||||
};
|
||||
}else{
|
||||
if(Sarissa.getDomDocument && (Sarissa.getDomDocument("","foo", null)).xml){
|
||||
// see non-IE version
|
||||
Sarissa.serialize = function(oDoc) {
|
||||
var s = null;
|
||||
if(oDoc){
|
||||
s = oDoc.innerHTML?oDoc.innerHTML:oDoc.xml;
|
||||
};
|
||||
return s;
|
||||
};
|
||||
/**
|
||||
* Utility class to serialize DOM Node objects to XML strings
|
||||
* @constructor
|
||||
*/
|
||||
XMLSerializer = function(){};
|
||||
/**
|
||||
* Serialize the given DOM Node to an XML string
|
||||
* @param oNode the DOM Node to serialize
|
||||
*/
|
||||
XMLSerializer.prototype.serializeToString = function(oNode) {
|
||||
return oNode.xml;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* strips tags from a markup string
|
||||
*/
|
||||
Sarissa.stripTags = function (s) {
|
||||
return s.replace(/<[^>]+>/g,"");
|
||||
};
|
||||
/**
|
||||
* <p>Deletes all child nodes of the given node</p>
|
||||
* @argument oNode the Node to empty
|
||||
*/
|
||||
Sarissa.clearChildNodes = function(oNode) {
|
||||
// need to check for firstChild due to opera 8 bug with hasChildNodes
|
||||
while(oNode.firstChild){
|
||||
oNode.removeChild(oNode.firstChild);
|
||||
};
|
||||
};
|
||||
/**
|
||||
* <p> Copies the childNodes of nodeFrom to nodeTo</p>
|
||||
* <p> <b>Note:</b> The second object's original content is deleted before
|
||||
* the copy operation, unless you supply a true third parameter</p>
|
||||
* @argument nodeFrom the Node to copy the childNodes from
|
||||
* @argument nodeTo the Node to copy the childNodes to
|
||||
* @argument bPreserveExisting whether to preserve the original content of nodeTo, default is false
|
||||
*/
|
||||
Sarissa.copyChildNodes = function(nodeFrom, nodeTo, bPreserveExisting) {
|
||||
if((!nodeFrom) || (!nodeTo)){
|
||||
throw "Both source and destination nodes must be provided";
|
||||
};
|
||||
if(!bPreserveExisting){
|
||||
Sarissa.clearChildNodes(nodeTo);
|
||||
};
|
||||
var ownerDoc = nodeTo.nodeType == Node.DOCUMENT_NODE ? nodeTo : nodeTo.ownerDocument;
|
||||
var nodes = nodeFrom.childNodes;
|
||||
if(ownerDoc.importNode && (!_SARISSA_IS_IE)) {
|
||||
for(var i=0;i < nodes.length;i++) {
|
||||
nodeTo.appendChild(ownerDoc.importNode(nodes[i], true));
|
||||
};
|
||||
}
|
||||
else{
|
||||
for(var i=0;i < nodes.length;i++) {
|
||||
nodeTo.appendChild(nodes[i].cloneNode(true));
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* <p> Moves the childNodes of nodeFrom to nodeTo</p>
|
||||
* <p> <b>Note:</b> The second object's original content is deleted before
|
||||
* the move operation, unless you supply a true third parameter</p>
|
||||
* @argument nodeFrom the Node to copy the childNodes from
|
||||
* @argument nodeTo the Node to copy the childNodes to
|
||||
* @argument bPreserveExisting whether to preserve the original content of nodeTo, default is
|
||||
*/
|
||||
Sarissa.moveChildNodes = function(nodeFrom, nodeTo, bPreserveExisting) {
|
||||
if((!nodeFrom) || (!nodeTo)){
|
||||
throw "Both source and destination nodes must be provided";
|
||||
};
|
||||
if(!bPreserveExisting){
|
||||
Sarissa.clearChildNodes(nodeTo);
|
||||
};
|
||||
var nodes = nodeFrom.childNodes;
|
||||
// if within the same doc, just move, else copy and delete
|
||||
if(nodeFrom.ownerDocument == nodeTo.ownerDocument){
|
||||
while(nodeFrom.firstChild){
|
||||
nodeTo.appendChild(nodeFrom.firstChild);
|
||||
};
|
||||
}else{
|
||||
var ownerDoc = nodeTo.nodeType == Node.DOCUMENT_NODE ? nodeTo : nodeTo.ownerDocument;
|
||||
if(ownerDoc.importNode && (!_SARISSA_IS_IE)) {
|
||||
for(var i=0;i < nodes.length;i++) {
|
||||
nodeTo.appendChild(ownerDoc.importNode(nodes[i], true));
|
||||
};
|
||||
}else{
|
||||
for(var i=0;i < nodes.length;i++) {
|
||||
nodeTo.appendChild(nodes[i].cloneNode(true));
|
||||
};
|
||||
};
|
||||
Sarissa.clearChildNodes(nodeFrom);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* <p>Serialize any object to an XML string. All properties are serialized using the property name
|
||||
* as the XML element name. Array elements are rendered as <code>array-item</code> elements,
|
||||
* using their index/key as the value of the <code>key</code> attribute.</p>
|
||||
* @argument anyObject the object to serialize
|
||||
* @argument objectName a name for that object
|
||||
* @return the XML serializationj of the given object as a string
|
||||
*/
|
||||
Sarissa.xmlize = function(anyObject, objectName, indentSpace){
|
||||
indentSpace = indentSpace?indentSpace:'';
|
||||
var s = indentSpace + '<' + objectName + '>';
|
||||
var isLeaf = false;
|
||||
if(!(anyObject instanceof Object) || anyObject instanceof Number || anyObject instanceof String
|
||||
|| anyObject instanceof Boolean || anyObject instanceof Date){
|
||||
s += Sarissa.escape(""+anyObject);
|
||||
isLeaf = true;
|
||||
}else{
|
||||
s += "\n";
|
||||
var itemKey = '';
|
||||
var isArrayItem = anyObject instanceof Array;
|
||||
for(var name in anyObject){
|
||||
s += Sarissa.xmlize(anyObject[name], (isArrayItem?"array-item key=\""+name+"\"":name), indentSpace + " ");
|
||||
};
|
||||
s += indentSpace;
|
||||
};
|
||||
return s += (objectName.indexOf(' ')!=-1?"</array-item>\n":"</" + objectName + ">\n");
|
||||
};
|
||||
|
||||
/**
|
||||
* Escape the given string chacters that correspond to the five predefined XML entities
|
||||
* @param sXml the string to escape
|
||||
*/
|
||||
Sarissa.escape = function(sXml){
|
||||
return sXml.replace(/&/g, "&")
|
||||
.replace(/</g, "<")
|
||||
.replace(/>/g, ">")
|
||||
.replace(/"/g, """)
|
||||
.replace(/'/g, "'");
|
||||
};
|
||||
|
||||
/**
|
||||
* Unescape the given string. This turns the occurences of the predefined XML
|
||||
* entities to become the characters they represent correspond to the five predefined XML entities
|
||||
* @param sXml the string to unescape
|
||||
*/
|
||||
Sarissa.unescape = function(sXml){
|
||||
return sXml.replace(/'/g,"'")
|
||||
.replace(/"/g,"\"")
|
||||
.replace(/>/g,">")
|
||||
.replace(/</g,"<")
|
||||
.replace(/&/g,"&");
|
||||
};
|
||||
// EOF
|
|
@ -1,105 +0,0 @@
|
|||
/**
|
||||
* ====================================================================
|
||||
* About
|
||||
* ====================================================================
|
||||
* Sarissa cross browser XML library - AJAX module
|
||||
* @version 0.9.6.1
|
||||
* @author: Copyright Manos Batsis, mailto: mbatsis at users full stop sourceforge full stop net
|
||||
*
|
||||
* This module contains some convinient AJAX tricks based on Sarissa
|
||||
*
|
||||
* ====================================================================
|
||||
* Licence
|
||||
* ====================================================================
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 or
|
||||
* the GNU Lesser General Public License version 2.1 as published by
|
||||
* the Free Software Foundation (your choice between the two).
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License or GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* or GNU Lesser General Public License along with this program; if not,
|
||||
* write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* or visit http://www.gnu.org
|
||||
*
|
||||
*/
|
||||
/**
|
||||
* Update an element with response of a GET request on the given URL.
|
||||
* @addon
|
||||
* @param sFromUrl the URL to make the request to
|
||||
* @param oTargetElement the element to update
|
||||
* @param xsltproc (optional) the transformer to use on the returned
|
||||
* content before updating the target element with it
|
||||
*/
|
||||
Sarissa.updateContentFromURI = function(sFromUrl, oTargetElement, xsltproc) {
|
||||
try{
|
||||
oTargetElement.style.cursor = "wait";
|
||||
var xmlhttp = new XMLHttpRequest();
|
||||
xmlhttp.open("GET", sFromUrl);
|
||||
function sarissa_dhtml_loadHandler() {
|
||||
if (xmlhttp.readyState == 4) {
|
||||
oTargetElement.style.cursor = "auto";
|
||||
Sarissa.updateContentFromNode(xmlhttp.responseXML, oTargetElement, xsltproc);
|
||||
};
|
||||
};
|
||||
xmlhttp.onreadystatechange = sarissa_dhtml_loadHandler;
|
||||
xmlhttp.send(null);
|
||||
oTargetElement.style.cursor = "auto";
|
||||
}
|
||||
catch(e){
|
||||
oTargetElement.style.cursor = "auto";
|
||||
throw e;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Update an element's content with the given DOM node.
|
||||
* @addon
|
||||
* @param sFromUrl the URL to make the request to
|
||||
* @param oTargetElement the element to update
|
||||
* @param xsltproc (optional) the transformer to use on the given
|
||||
* DOM node before updating the target element with it
|
||||
*/
|
||||
Sarissa.updateContentFromNode = function(oNode, oTargetElement, xsltproc) {
|
||||
try {
|
||||
oTargetElement.style.cursor = "wait";
|
||||
Sarissa.clearChildNodes(oTargetElement);
|
||||
// check for parsing errors
|
||||
var ownerDoc = oNode.nodeType == Node.DOCUMENT_NODE?oNode:oNode.ownerDocument;
|
||||
if(ownerDoc.parseError && ownerDoc.parseError != 0) {
|
||||
var pre = document.createElement("pre");
|
||||
pre.appendChild(document.createTextNode(Sarissa.getParseErrorText(ownerDoc)));
|
||||
oTargetElement.appendChild(pre);
|
||||
}
|
||||
else {
|
||||
// transform if appropriate
|
||||
if(xsltproc) {
|
||||
oNode = xsltproc.transformToDocument(oNode);
|
||||
};
|
||||
// be smart, maybe the user wants to display the source instead
|
||||
if(oTargetElement.tagName.toLowerCase == "textarea" || oTargetElement.tagName.toLowerCase == "input") {
|
||||
oTargetElement.value = Sarissa.serialize(oNode);
|
||||
}
|
||||
else {
|
||||
// ok that was not smart; it was paranoid. Keep up the good work by trying to use DOM instead of innerHTML
|
||||
if(oNode.nodeType == Node.DOCUMENT_NODE || oNode.ownerDocument.documentElement == oNode) {
|
||||
oTargetElement.innerHTML = Sarissa.serialize(oNode);
|
||||
}
|
||||
else{
|
||||
oTargetElement.appendChild(oTargetElement.ownerDocument.importNode(oNode, true));
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
catch(e) {
|
||||
throw e;
|
||||
}
|
||||
finally{
|
||||
oTargetElement.style.cursor = "auto";
|
||||
};
|
||||
};
|
||||
|
|
@ -1,169 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
# pylint: disable=C0103
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2010 United States Government as represented by the
|
||||
# Administrator of the National Aeronautics and Space Administration.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed 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.
|
||||
|
||||
"""Euca add-on to use ajax console"""
|
||||
|
||||
import getopt
|
||||
import os
|
||||
import sys
|
||||
|
||||
# If ../nova/__init__.py exists, add ../ to Python search path, so that
|
||||
# it will override what happens to be installed in /usr/(local/)lib/python...
|
||||
possible_topdir = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]),
|
||||
os.pardir,
|
||||
os.pardir))
|
||||
if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')):
|
||||
sys.path.insert(0, possible_topdir)
|
||||
|
||||
import boto
|
||||
import nova
|
||||
import boto.ec2.connection
|
||||
import euca2ools
|
||||
|
||||
usage_string = """
|
||||
Retrieves a url to an ajax console terminal
|
||||
|
||||
euca-get-ajax-console [-h, --help] [--version] [--debug] instance_id
|
||||
|
||||
REQUIRED PARAMETERS
|
||||
|
||||
instance_id: unique identifier for the instance show the console output for.
|
||||
|
||||
OPTIONAL PARAMETERS
|
||||
|
||||
"""
|
||||
|
||||
|
||||
# This class extends boto to add AjaxConsole functionality
|
||||
class NovaEC2Connection(boto.ec2.connection.EC2Connection):
|
||||
|
||||
def get_ajax_console(self, instance_id):
|
||||
"""
|
||||
Retrieves a console connection for the specified instance.
|
||||
|
||||
:type instance_id: string
|
||||
:param instance_id: The instance ID of a running instance on the cloud.
|
||||
|
||||
:rtype: :class:`AjaxConsole`
|
||||
"""
|
||||
|
||||
class AjaxConsole:
|
||||
def __init__(self, parent=None):
|
||||
self.parent = parent
|
||||
self.instance_id = None
|
||||
self.url = None
|
||||
|
||||
def startElement(self, name, attrs, connection):
|
||||
return None
|
||||
|
||||
def endElement(self, name, value, connection):
|
||||
if name == 'instanceId':
|
||||
self.instance_id = value
|
||||
elif name == 'url':
|
||||
self.url = value
|
||||
else:
|
||||
setattr(self, name, value)
|
||||
|
||||
params = {}
|
||||
self.build_list_params(params, [instance_id], 'InstanceId')
|
||||
return self.get_object('GetAjaxConsole', params, AjaxConsole)
|
||||
pass
|
||||
|
||||
|
||||
def override_connect_ec2(aws_access_key_id=None,
|
||||
aws_secret_access_key=None, **kwargs):
|
||||
return NovaEC2Connection(aws_access_key_id,
|
||||
aws_secret_access_key, **kwargs)
|
||||
|
||||
# override boto's connect_ec2 method, so that we can use NovaEC2Connection
|
||||
# (This is for Euca2ools 1.2)
|
||||
boto.connect_ec2 = override_connect_ec2
|
||||
|
||||
# Override Euca2ools' EC2Connection class (which it gets from boto)
|
||||
# (This is for Euca2ools 1.3)
|
||||
euca2ools.EC2Connection = NovaEC2Connection
|
||||
|
||||
|
||||
def usage(status=1):
|
||||
print usage_string
|
||||
euca2ools.Util().usage()
|
||||
sys.exit(status)
|
||||
|
||||
|
||||
def version():
|
||||
print euca2ools.Util().version()
|
||||
sys.exit()
|
||||
|
||||
|
||||
def display_console_output(console_output):
|
||||
print console_output.instance_id
|
||||
print console_output.timestamp
|
||||
print console_output.output
|
||||
|
||||
|
||||
def display_ajax_console_output(console_output):
|
||||
print console_output.url
|
||||
|
||||
|
||||
def main():
|
||||
try:
|
||||
euca = euca2ools.Euca2ool()
|
||||
except Exception, e:
|
||||
print e
|
||||
usage()
|
||||
|
||||
instance_id = None
|
||||
|
||||
for name, value in euca.opts:
|
||||
if name in ('-h', '--help'):
|
||||
usage(0)
|
||||
elif name == '--version':
|
||||
version()
|
||||
elif name == '--debug':
|
||||
debug = True
|
||||
|
||||
for arg in euca.args:
|
||||
instance_id = arg
|
||||
break
|
||||
|
||||
if instance_id:
|
||||
try:
|
||||
euca.validate_instance_id(instance_id)
|
||||
except euca2ools.InstanceValidationError:
|
||||
print 'Invalid instance id'
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
euca_conn = euca.make_connection()
|
||||
except Exception, e:
|
||||
print e.message
|
||||
sys.exit(1)
|
||||
try:
|
||||
console_output = euca_conn.get_ajax_console(instance_id)
|
||||
except Exception, ex:
|
||||
euca.display_error_and_exit('%s' % ex)
|
||||
|
||||
display_ajax_console_output(console_output)
|
||||
else:
|
||||
print 'instance_id must be specified'
|
||||
usage()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
Loading…
Reference in New Issue