#718: Integrar código fuente de agente OGAgent en rama de desarrollo.
git-svn-id: https://opengnsys.es/svn/branches/version1.1@4865 a21b9725-9963-47de-94b9-378ad31fedc9remotes/github/oglive
commit
11f7a07988
|
@ -0,0 +1,72 @@
|
|||
#!/usr/bin/make -f
|
||||
# -*- makefile -*-
|
||||
|
||||
# Directories
|
||||
SOURCEDIR := ../src
|
||||
LIBDIR := $(DESTDIR)/usr/share/OGAgent
|
||||
BINDIR := $(DESTDIR)/usr/bin
|
||||
SBINDIR = $(DESTDIR)/usr/sbin
|
||||
APPSDIR := $(DESTDIR)/usr/share/applications
|
||||
CFGDIR := $(DESTDIR)/etc/ogagent
|
||||
INITDIR := $(DESTDIR)/etc/init.d
|
||||
XDGAUTOSTARTDIR := $(DESTDIR)/etc/xdg/autostart
|
||||
KDEAUTOSTARTDIR := $(DESTDIR)/usr/share/autostart
|
||||
|
||||
PYC := $(shell find $(SOURCEDIR) -name '*.py[co]')
|
||||
CACHES := $(shell find $(SOURCEDIR) -name '__pycache__')
|
||||
|
||||
clean:
|
||||
rm -rf $(PYC) $(CACHES) $(DESTDIR)
|
||||
install-ogagent:
|
||||
rm -rf $(DESTDIR)
|
||||
mkdir -p $(LIBDIR)
|
||||
mkdir -p $(BINDIR)
|
||||
mkdir -p $(SBINDIR)
|
||||
mkdir -p $(APPSDIR)
|
||||
mkdir -p $(CFGDIR)
|
||||
mkdir -p $(XDGAUTOSTARTDIR)
|
||||
mkdir -p $(KDEAUTOSTARTDIR)
|
||||
|
||||
mkdir $(LIBDIR)/img
|
||||
|
||||
# Cleans up .pyc and cache folders
|
||||
rm -f $(PYC) $(CACHES)
|
||||
|
||||
cp -r $(SOURCEDIR)/opengnsys $(LIBDIR)/opengnsys
|
||||
cp -r $(SOURCEDIR)/cfg $(LIBDIR)/cfg
|
||||
cp $(SOURCEDIR)/img/oga.png $(LIBDIR)/img
|
||||
|
||||
cp $(SOURCEDIR)/OGAgentUser.py $(LIBDIR)
|
||||
# QT Dialogs & resources
|
||||
cp $(SOURCEDIR)/*_ui.py $(LIBDIR)
|
||||
cp $(SOURCEDIR)/OGAgent_rc.py $(LIBDIR)
|
||||
|
||||
# Autostart elements for gnome/kde
|
||||
cp desktop/OGAgentTool.desktop $(XDGAUTOSTARTDIR)
|
||||
cp desktop/OGAgentTool.desktop $(KDEAUTOSTARTDIR)
|
||||
|
||||
# scripts
|
||||
cp scripts/ogagent $(BINDIR)
|
||||
cp scripts/OGAgentTool-startup $(BINDIR)
|
||||
cp scripts/OGAgentTool $(BINDIR)
|
||||
|
||||
# Fix permissions
|
||||
chmod 755 $(BINDIR)/ogagent
|
||||
chmod 755 $(BINDIR)/OGAgentTool-startup
|
||||
chmod 755 $(LIBDIR)/OGAgentUser.py
|
||||
chmod 600 $(LIBDIR)/cfg/ogagent.cfg
|
||||
|
||||
# If for red hat based, copy init.d
|
||||
ifeq ($(DISTRO),rh)
|
||||
mkdir -p $(INITDIR)
|
||||
cp debian/ogagent.init $(INITDIR)/ogagent
|
||||
chmod +x $(INITDIR)/ogagent
|
||||
ln -fs /usr/share/OGAgent/cfg/ogagent.cfg $(CFGDIR)
|
||||
ln -fs /usr/share/OGAgent/cfg/ogclient.cfg $(CFGDIR)
|
||||
endif
|
||||
|
||||
# chmod 0755 $(BINDIR)/ogagent
|
||||
uninstall:
|
||||
rm -rf $(LIBDIR)
|
||||
# rm -f $(BINDIR)/ogagent
|
||||
rm -rf $(CFGDIR)
|
|
@ -0,0 +1,34 @@
|
|||
#!/bin/bash
|
||||
|
||||
VERSION=1.0.0
|
||||
RELEASE=1
|
||||
|
||||
top=`pwd`
|
||||
|
||||
# Debian based
|
||||
dpkg-buildpackage -b -d
|
||||
|
||||
cat ogagent-template.spec |
|
||||
sed -e s/"version 0.0.0"/"version ${VERSION}"/g |
|
||||
sed -e s/"release 1"/"release ${RELEASE}"/g > ogagent-$VERSION.spec
|
||||
|
||||
# Now fix dependencies for opensuse
|
||||
cat ogagent-template.spec |
|
||||
sed -e s/"version 0.0.0"/"version ${VERSION}"/g |
|
||||
sed -e s/"name ogagent"/"name ogagent-opensuse"/g |
|
||||
sed -e s/"PyQt4"/"python-qt4"/g |
|
||||
sed -e s/"libXScrnSaver"/"libXss1"/g > ogagent-opensuse-$VERSION.spec
|
||||
|
||||
|
||||
# Right now, ogagent-xrdp-1.7.0.spec is not needed
|
||||
for pkg in ogagent-$VERSION.spec ogagent-opensuse-$VERSION.spec; do
|
||||
|
||||
rm -rf rpm
|
||||
for folder in SOURCES BUILD RPMS SPECS SRPMS; do
|
||||
mkdir -p rpm/$folder
|
||||
done
|
||||
|
||||
rpmbuild -v -bb --clean --buildroot=$top/rpm/BUILD/$pkg-root --target noarch $pkg 2>&1
|
||||
done
|
||||
|
||||
#rm ogagent-$VERSION
|
|
@ -0,0 +1,5 @@
|
|||
ogagent (1.0.0) stable; urgency=medium
|
||||
|
||||
* Initial release for OpenGnSys Agent
|
||||
|
||||
-- Adolfo Gómez García <agomez@virtualcable.es> Tue, 18 Jul 2015 03:18:22 +0200
|
|
@ -0,0 +1 @@
|
|||
9
|
|
@ -0,0 +1,15 @@
|
|||
Source: ogagent
|
||||
Section: admin
|
||||
Priority: optional
|
||||
Maintainer: Adolfo Gómez García <agomez@virtualcable.es>
|
||||
Build-Depends: debhelper (>= 7), po-debconf
|
||||
Standards-Version: 3.9.2
|
||||
Homepage: http://www.opengnsys.es
|
||||
|
||||
Package: ogagent
|
||||
Section: admin
|
||||
Priority: optional
|
||||
Architecture: all
|
||||
Depends: policykit-1(>=0.100), python-requests (>=0.8.2), python-qt4 (>=4.9), python-six(>=1.1), python-prctl(>=1.1.1), python (>=2.7), libxss1, ${misc:Depends}
|
||||
Description: Agent for OpenGnSys
|
||||
This package provides the required components to allow this machine to work on an environment managed by OpenGnSys.
|
|
@ -0,0 +1,26 @@
|
|||
Format-Specification: http://svn.debian.org/wsvn/dep/web/deps/dep5.mdwn?op=file&rev=135
|
||||
Name: udsactor
|
||||
Maintainer: Adolfo Gómez García
|
||||
Source: http://www.udsenterprise.com/
|
||||
|
||||
Copyright: 2014 Virtual Cable S.L.U.
|
||||
License: BSD-3-clause
|
||||
|
||||
License: GPL-2+
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
.
|
||||
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 for more details.
|
||||
.
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
.
|
||||
On Debian systems, the full text of the GNU General Public
|
||||
License version 2 can be found in the file
|
||||
`/usr/share/common-licenses/GPL-2'.
|
|
@ -0,0 +1 @@
|
|||
readme.txt
|
|
@ -0,0 +1,23 @@
|
|||
#!/bin/sh -e
|
||||
### BEGIN INIT INFO
|
||||
# Provides: ogagent
|
||||
# Required-Start: $local_fs $remote_fs $network $syslog $named
|
||||
# Required-Stop: $local_fs $remote_fs $network $syslog $named
|
||||
# Default-Start: 2 3 4 5
|
||||
# Default-Stop: 0 1 6
|
||||
# Short-Description: OpenGnSys Agent Service
|
||||
### END INIT INFO
|
||||
#
|
||||
|
||||
# . /lib/lsb/init-functions
|
||||
|
||||
case "$1" in
|
||||
start|stop|restart)
|
||||
/usr/bin/ogagent $1
|
||||
;;
|
||||
force-reload)
|
||||
/usr/bin/ogagent restart
|
||||
;;
|
||||
*) echo "Usage: $0 {start|stop|restart|force-reload}" >&2; exit 1 ;;
|
||||
esac
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
/usr/share/OGAgent/cfg/ogagent.cfg /etc/ogagent/ogagent.cfg
|
||||
/usr/share/OGAgent/cfg/ogclient.cfg /etc/ogagent/ogclient.cfg
|
|
@ -0,0 +1,21 @@
|
|||
#!/bin/sh
|
||||
|
||||
. /usr/share/debconf/confmodule
|
||||
|
||||
set -e
|
||||
case "$1" in
|
||||
configure)
|
||||
chmod 600 /usr/share/OGAgent/cfg/ogagent.cfg
|
||||
;;
|
||||
abort-upgrade|abort-remove|abort-deconfigure)
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "postinst called with unknown argument \`$1'" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
#DEBHELPER#
|
||||
|
||||
exit 0
|
|
@ -0,0 +1,5 @@
|
|||
# Automatically added by dh_installinit
|
||||
if [ -x "/etc/init.d/ogagent" ]; then
|
||||
update-rc.d ogagent defaults >/dev/null || exit $?
|
||||
fi
|
||||
# End automatically added section
|
|
@ -0,0 +1,10 @@
|
|||
#!/bin/sh -e
|
||||
|
||||
. /usr/share/debconf/confmodule
|
||||
|
||||
set -e
|
||||
|
||||
if [ "$1" = "purge" ] ; then
|
||||
rm -rf /usr/share/OGAgent || true > /dev/null 2>&1
|
||||
fi
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
# Automatically added by dh_installinit
|
||||
if [ "$1" = "purge" ] ; then
|
||||
update-rc.d ogagent remove >/dev/null
|
||||
fi
|
||||
|
||||
|
||||
# In case this system is running systemd, we make systemd reload the unit files
|
||||
# to pick up changes.
|
||||
if [ -d /run/systemd/system ] ; then
|
||||
systemctl --system daemon-reload >/dev/null || true
|
||||
fi
|
||||
# End automatically added section
|
|
@ -0,0 +1,2 @@
|
|||
misc:Depends=
|
||||
misc:Pre-Depends=
|
|
@ -0,0 +1,44 @@
|
|||
#!/usr/bin/make -f
|
||||
# -*- makefile -*-
|
||||
configure: configure-stamp
|
||||
configure-stamp:
|
||||
dh_testdir
|
||||
touch configure-stamp
|
||||
build: build-arch build-indep
|
||||
build-arch: build-stamp
|
||||
build-indep: build-stamp
|
||||
build-stamp: configure-stamp
|
||||
dh_testdir
|
||||
$(MAKE)
|
||||
touch $@
|
||||
clean:
|
||||
dh_testdir
|
||||
dh_testroot
|
||||
rm -f build-stamp configure-stamp
|
||||
dh_clean
|
||||
install: build
|
||||
dh_testdir
|
||||
dh_testroot
|
||||
dh_prep
|
||||
dh_installdirs
|
||||
$(MAKE) DESTDIR=$(CURDIR)/debian/ogagent install-ogagent
|
||||
binary-arch: build install
|
||||
# emptyness
|
||||
binary-indep: build install
|
||||
dh_testdir
|
||||
dh_testroot
|
||||
dh_installchangelogs
|
||||
dh_installdocs
|
||||
dh_installdebconf
|
||||
dh_installinit --no-start
|
||||
dh_python2=python
|
||||
dh_compress
|
||||
dh_link
|
||||
dh_fixperms
|
||||
dh_installdeb
|
||||
dh_shlibdeps
|
||||
dh_gencontrol
|
||||
dh_md5sums
|
||||
dh_builddeb
|
||||
binary: binary-indep
|
||||
.PHONY: build clean binary-indep binary install configure
|
|
@ -0,0 +1 @@
|
|||
3.0 (native)
|
|
@ -0,0 +1,12 @@
|
|||
[Desktop Entry]
|
||||
Name=OpenGnSys Agent Tools
|
||||
Comment=OpenGnSys Userspace tools
|
||||
Exec=/usr/bin/OGAgentTool-startup
|
||||
Icon=/usr/share/OGAgent/img/oga.png
|
||||
Terminal=false
|
||||
Type=Application
|
||||
NoDisplay=true
|
||||
X-KDE-autostart-after=panel
|
||||
X-KDE-StartupNotify=false
|
||||
X-DBUS-StartupType=Unique
|
||||
X-KDE-UniqueApplet=true
|
|
@ -0,0 +1,65 @@
|
|||
%define _topdir %(echo $PWD)/rpm
|
||||
%define name ogagent
|
||||
%define version 0.0.0
|
||||
%define release 1
|
||||
%define buildroot %{_topdir}/%{name}-%{version}-%{release}-root
|
||||
|
||||
BuildRoot: %{buildroot}
|
||||
Name: %{name}
|
||||
Version: %{version}
|
||||
Release: %{release}
|
||||
Summary: OpenGnSys Agent & tools
|
||||
License: BSD3
|
||||
Group: Admin
|
||||
Requires: python-six python-requests PyQt4 libXScrnSaver
|
||||
Vendor: Virtual Cable S.L.U.
|
||||
URL: http://www.udsenterprise.com
|
||||
Provides: ogagent
|
||||
|
||||
%define _rpmdir ../
|
||||
%define _rpmfilename %%{NAME}-%%{VERSION}-%%{RELEASE}.%%{ARCH}.rpm
|
||||
|
||||
|
||||
%install
|
||||
curdir=`pwd`
|
||||
cd ../..
|
||||
make DESTDIR=$RPM_BUILD_ROOT DISTRO=rh install-ogagent
|
||||
cd $curdir
|
||||
|
||||
%clean
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
curdir=`pwd`
|
||||
cd ../..
|
||||
make DESTDIR=$RPM_BUILD_ROOT DISTRO=rh clean
|
||||
cd $curdir
|
||||
|
||||
|
||||
%post
|
||||
systemctl enable ogagent.service > /dev/null 2>&1
|
||||
|
||||
%preun
|
||||
systemctl disable ogagent.service > /dev/null 2>&1
|
||||
systemctl stop ogagent.service > /dev/null 2>&1
|
||||
|
||||
%postun
|
||||
# $1 == 0 on uninstall, == 1 on upgrade for preun and postun (just a reminder for me... :) )
|
||||
if [ $1 -eq 0 ]; then
|
||||
rm -rf /etc/ogagent
|
||||
rm /var/log/ogagent.log
|
||||
fi
|
||||
# And, posibly, the .pyc leaved behind on /usr/share/UDSActor
|
||||
rm -rf /usr/share/OGAgent > /dev/null 2>&1
|
||||
|
||||
%description
|
||||
This package provides the required components to allow this machine to work on an environment managed by OpenGnSys.
|
||||
|
||||
%files
|
||||
%defattr(-,root,root)
|
||||
/etc/ogagent
|
||||
/etc/xdg/autostart/OGAgentTool.desktop
|
||||
/etc/init.d/ogagent
|
||||
/usr/bin/OGAgentTool-startup
|
||||
/usr/bin/ogagent
|
||||
/usr/bin/OGAgentTool
|
||||
/usr/share/OGAgent/*
|
||||
/usr/share/autostart/OGAgentTool.desktop
|
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE policyconfig PUBLIC
|
||||
"-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/PolicyKit/1/policyconfig.dtd">
|
||||
|
||||
<policyconfig>
|
||||
|
||||
<action id="org.freedesktop.policykit.pkexec.run-UDSActorConfig">
|
||||
<description>Run UDS Actor Configuration Program</description>
|
||||
<message>Authentication is required to run UDS Actor Configuration</message>
|
||||
<defaults>
|
||||
<allow_any>no</allow_any>
|
||||
<allow_inactive>no</allow_inactive>
|
||||
<allow_active>auth_admin_keep</allow_active>
|
||||
</defaults>
|
||||
<annotate key="org.freedesktop.policykit.exec.path">/usr/sbin/UDSActorConfig</annotate>
|
||||
<annotate key="org.freedesktop.policykit.exec.allow_gui">TRUE</annotate>
|
||||
</action>
|
||||
|
||||
</policyconfig>
|
|
@ -0,0 +1,3 @@
|
|||
OGAgent is the agent intended for OpengGnSys interaction.
|
||||
|
||||
Please, visit http://www.opengnsys.es for more information
|
|
@ -0,0 +1,6 @@
|
|||
#!/bin/sh
|
||||
|
||||
FOLDER=/usr/share/OGAgent
|
||||
|
||||
cd $FOLDER
|
||||
python OGAgentUser.py $@
|
|
@ -0,0 +1,10 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Simple hack to wait for systray to be present
|
||||
# Exec tool if not already runned by session manager
|
||||
ps -ef | grep "$USER" | grep -v grep | grep -v OGAgentTool-startup | grep 'OGAgentTool' -q
|
||||
# If not already running
|
||||
if [ $? -eq 1 ]; then
|
||||
sleep 5
|
||||
exec /usr/bin/OGAgentTool
|
||||
fi
|
|
@ -0,0 +1,6 @@
|
|||
#!/bin/sh
|
||||
|
||||
FOLDER=/usr/share/OGAgent
|
||||
|
||||
cd $FOLDER
|
||||
python -m opengnsys.linux.OGAgentService $@
|
|
@ -0,0 +1,11 @@
|
|||
* ¿Como sabemos la direccion del servidor?
|
||||
* Seguridad. Como hacer el agente seguro (registro con OpenGnsys). Mensajes bidireccionales
|
||||
* Mensajes. (Moderm)
|
||||
- Definir mensajes de cliente --> servidor
|
||||
- Definir mensajes servidor --> cliente
|
||||
* Logotipo OpenGnsys
|
||||
* Licencia BSD (relicenciamiento basado en OpenUDS)
|
||||
* Clientes Windows y Linux inicialmente, parte usuarios?
|
||||
* "Modern" vs "Legacy" agents
|
||||
* Particularidades
|
||||
* ¿Posibles extensiones para "consola" og?
|
|
@ -0,0 +1,3 @@
|
|||
six
|
||||
requests
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2014 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
'''
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import win32service
|
||||
import win32serviceutil
|
||||
|
||||
svc_name = "UDSActor"
|
||||
|
||||
try:
|
||||
hscm = win32service.OpenSCManager(None, None, win32service.SC_MANAGER_ALL_ACCESS)
|
||||
|
||||
try:
|
||||
hs = win32serviceutil.SmartOpenService(hscm, svc_name, win32service.SERVICE_ALL_ACCESS)
|
||||
service_failure_actions = {
|
||||
'ResetPeriod': 864000, # Time in ms after which to reset the failure count to zero.
|
||||
'RebootMsg': u'', # Not using reboot option
|
||||
'Command': u'', # Not using run-command option
|
||||
'Actions': [
|
||||
(win32service.SC_ACTION_RESTART, 5000), # action, delay in ms
|
||||
(win32service.SC_ACTION_RESTART, 5000)
|
||||
]
|
||||
}
|
||||
win32service.ChangeServiceConfig2(hs, win32service.SERVICE_CONFIG_FAILURE_ACTIONS, service_failure_actions)
|
||||
finally:
|
||||
win32service.CloseServiceHandle(hs)
|
||||
finally:
|
||||
win32service.CloseServiceHandle(hscm)
|
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||
<assemblyIdentity
|
||||
type="win32"
|
||||
name="UDSActorService"
|
||||
version="1.6.0.0"
|
||||
processorArchitecture="x86"
|
||||
/>
|
||||
<description>Description</description>
|
||||
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<security>
|
||||
<requestedPrivileges>
|
||||
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
|
||||
</requestedPrivileges>
|
||||
</security>
|
||||
</trustInfo>
|
||||
</assembly>
|
|
@ -0,0 +1,5 @@
|
|||
<RCC>
|
||||
<qresource prefix="images">
|
||||
<file>img/oga.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
|
@ -0,0 +1,338 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2014 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
'''
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import sys
|
||||
from PyQt4 import QtGui
|
||||
from PyQt4 import QtCore
|
||||
|
||||
import time
|
||||
import signal
|
||||
import json
|
||||
import six
|
||||
|
||||
from opengnsys import ipc
|
||||
from opengnsys import utils
|
||||
from opengnsys.log import logger
|
||||
from opengnsys.service import IPC_PORT
|
||||
from opengnsys import operations
|
||||
from about_dialog_ui import Ui_OGAAboutDialog
|
||||
from message_dialog_ui import Ui_OGAMessageDialog
|
||||
from opengnsys.scriptThread import ScriptExecutorThread
|
||||
from opengnsys import VERSION
|
||||
from opengnsys.config import readConfig
|
||||
from opengnsys.loader import loadModules
|
||||
|
||||
trayIcon = None
|
||||
|
||||
|
||||
def sigTerm(sigNo, stackFrame):
|
||||
if trayIcon:
|
||||
trayIcon.quit()
|
||||
|
||||
|
||||
# About dialog
|
||||
class OGAAboutDialog(QtGui.QDialog):
|
||||
def __init__(self, parent=None):
|
||||
QtGui.QDialog.__init__(self, parent)
|
||||
self.ui = Ui_OGAAboutDialog()
|
||||
self.ui.setupUi(self)
|
||||
self.ui.VersionLabel.setText("Version " + VERSION)
|
||||
|
||||
def closeDialog(self):
|
||||
self.hide()
|
||||
|
||||
|
||||
class OGAMessageDialog(QtGui.QDialog):
|
||||
def __init__(self, parent=None):
|
||||
QtGui.QDialog.__init__(self, parent)
|
||||
self.ui = Ui_OGAMessageDialog()
|
||||
self.ui.setupUi(self)
|
||||
|
||||
def message(self, message):
|
||||
self.ui.message.setText(message)
|
||||
self.show()
|
||||
|
||||
def closeDialog(self):
|
||||
self.hide()
|
||||
|
||||
|
||||
class MessagesProcessor(QtCore.QThread):
|
||||
|
||||
logoff = QtCore.pyqtSignal(name='logoff')
|
||||
message = QtCore.pyqtSignal(tuple, name='message')
|
||||
script = QtCore.pyqtSignal(QtCore.QString, name='script')
|
||||
exit = QtCore.pyqtSignal(name='exit')
|
||||
|
||||
def __init__(self, port):
|
||||
super(self.__class__, self).__init__()
|
||||
# Retries connection for a while
|
||||
for _ in range(10):
|
||||
try:
|
||||
self.ipc = ipc.ClientIPC(port)
|
||||
self.ipc.start()
|
||||
break
|
||||
except Exception:
|
||||
logger.debug('IPC Server is not reachable')
|
||||
self.ipc = None
|
||||
time.sleep(2)
|
||||
|
||||
self.running = False
|
||||
|
||||
def stop(self):
|
||||
self.running = False
|
||||
if self.ipc:
|
||||
self.ipc.stop()
|
||||
|
||||
def isAlive(self):
|
||||
return self.ipc is not None
|
||||
|
||||
def sendLogin(self, userName):
|
||||
if self.ipc:
|
||||
self.ipc.sendLogin(userName)
|
||||
|
||||
def sendLogout(self, userName):
|
||||
if self.ipc:
|
||||
self.ipc.sendLogout(userName)
|
||||
|
||||
def run(self):
|
||||
if self.ipc is None:
|
||||
return
|
||||
self.running = True
|
||||
|
||||
# Wait a bit so we ensure IPC thread is running...
|
||||
time.sleep(2)
|
||||
|
||||
while self.running and self.ipc.running:
|
||||
try:
|
||||
msg = self.ipc.getMessage()
|
||||
if msg is None:
|
||||
break
|
||||
msgId, data = msg
|
||||
logger.debug('Got Message on User Space: {}:{}'.format(msgId, data))
|
||||
if msgId == ipc.MSG_MESSAGE:
|
||||
module, message, data = data.split('\0')
|
||||
self.message.emit((module, message, data))
|
||||
elif msgId == ipc.MSG_LOGOFF:
|
||||
self.logoff.emit()
|
||||
elif msgId == ipc.MSG_SCRIPT:
|
||||
self.script.emit(QtCore.QString.fromUtf8(data))
|
||||
except Exception as e:
|
||||
try:
|
||||
logger.error('Got error on IPC thread {}'.format(utils.exceptionToMessage(e)))
|
||||
except:
|
||||
logger.error('Got error on IPC thread (an unicode error??)')
|
||||
|
||||
if self.ipc.running is False and self.running is True:
|
||||
logger.warn('Lost connection with Service, closing program')
|
||||
|
||||
self.exit.emit()
|
||||
|
||||
|
||||
class OGASystemTray(QtGui.QSystemTrayIcon):
|
||||
def __init__(self, app_, parent=None):
|
||||
self.app = app_
|
||||
|
||||
self.config = readConfig(client=True)
|
||||
|
||||
# Get opengnsys section as dict
|
||||
cfg = dict(self.config.items('opengnsys'))
|
||||
|
||||
# Set up log level
|
||||
logger.setLevel(cfg.get('log', 'INFO'))
|
||||
|
||||
self.ipcport = int(cfg.get('ipc_port', IPC_PORT))
|
||||
|
||||
# style = app.style()
|
||||
# icon = QtGui.QIcon(style.standardPixmap(QtGui.QStyle.SP_ComputerIcon))
|
||||
icon = QtGui.QIcon(':/images/img/oga.png')
|
||||
|
||||
QtGui.QSystemTrayIcon.__init__(self, icon, parent)
|
||||
self.menu = QtGui.QMenu(parent)
|
||||
exitAction = self.menu.addAction("About")
|
||||
exitAction.triggered.connect(self.about)
|
||||
self.setContextMenu(self.menu)
|
||||
self.ipc = MessagesProcessor(self.ipcport)
|
||||
|
||||
if self.ipc.isAlive() is False:
|
||||
raise Exception('No connection to service, exiting.')
|
||||
|
||||
self.timer = QtCore.QTimer()
|
||||
self.timer.timeout.connect(self.timerFnc)
|
||||
|
||||
|
||||
self.stopped = False
|
||||
|
||||
self.ipc.message.connect(self.message)
|
||||
self.ipc.exit.connect(self.quit)
|
||||
self.ipc.script.connect(self.executeScript)
|
||||
self.ipc.logoff.connect(self.logoff)
|
||||
|
||||
self.aboutDlg = OGAAboutDialog()
|
||||
self.msgDlg = OGAMessageDialog()
|
||||
|
||||
self.timer.start(1000) # Launch idle checking every 1 seconds
|
||||
|
||||
self.ipc.start()
|
||||
|
||||
def initialize(self):
|
||||
# Load modules and activate them
|
||||
# Also, sends "login" event to service
|
||||
self.modules = loadModules(self, client=True)
|
||||
logger.debug('Modules: {}'.format(list(v.name for v in self.modules)))
|
||||
|
||||
# Send init to all modules
|
||||
validMods = []
|
||||
for mod in self.modules:
|
||||
try:
|
||||
logger.debug('Activating module {}'.format(mod.name))
|
||||
mod.activate()
|
||||
validMods.append(mod)
|
||||
except Exception as e:
|
||||
logger.exception()
|
||||
logger.error("Activation of {} failed: {}".format(mod.name, utils.exceptionToMessage(e)))
|
||||
|
||||
self.modules[:] = validMods # copy instead of assignment
|
||||
|
||||
# If this is running, it's because he have logged in, inform service of this fact
|
||||
self.ipc.sendLogin(operations.getCurrentUser())
|
||||
|
||||
def deinitialize(self):
|
||||
for mod in reversed(self.modules): # Deinitialize reversed of initialization
|
||||
try:
|
||||
logger.debug('Deactivating module {}'.format(mod.name))
|
||||
mod.deactivate()
|
||||
except Exception as e:
|
||||
logger.exception()
|
||||
logger.error("Deactivation of {} failed: {}".format(mod.name, utils.exceptionToMessage(e)))
|
||||
|
||||
def timerFnc(self):
|
||||
pass
|
||||
|
||||
def message(self, msg):
|
||||
'''
|
||||
Processes the message sent asynchronously, msg is an QString
|
||||
'''
|
||||
try:
|
||||
logger.debug('msg: {}, {}'.format(type(msg), msg))
|
||||
module, message, data = msg
|
||||
except Exception as e:
|
||||
logger.error('Got exception {} processing message {}'.format(e, msg))
|
||||
return
|
||||
|
||||
for v in self.modules:
|
||||
if v.name == module: # Case Sensitive!!!!
|
||||
try:
|
||||
logger.debug('Notifying message {} to module {} with json data {}'.format(message, v.name, data))
|
||||
v.processMessage(message, json.loads(data))
|
||||
return
|
||||
except Exception as e:
|
||||
logger.error('Got exception {} processing generic message on {}'.format(e, v.name))
|
||||
|
||||
logger.error('Module {} not found, messsage {} not sent'.format(module, message))
|
||||
|
||||
def executeScript(self, script):
|
||||
logger.debug('Executing script')
|
||||
script = six.text_type(script.toUtf8()).decode('base64')
|
||||
th = ScriptExecutorThread(script)
|
||||
th.start()
|
||||
|
||||
def logoff(self):
|
||||
logger.debug('Logoff invoked')
|
||||
operations.logoff() # Invoke log off
|
||||
|
||||
def about(self):
|
||||
self.aboutDlg.exec_()
|
||||
|
||||
def quit(self):
|
||||
logger.debug('Quit invoked')
|
||||
if self.stopped is False:
|
||||
self.stopped = True
|
||||
try:
|
||||
self.deinitialize()
|
||||
except Exception:
|
||||
logger.exception()
|
||||
logger.error('Got exception deinitializing modules')
|
||||
|
||||
try:
|
||||
# If we close Client, send Logoff to Broker
|
||||
self.ipc.sendLogout(operations.getCurrentUser())
|
||||
self.timer.stop()
|
||||
self.ipc.stop()
|
||||
except Exception:
|
||||
# May we have lost connection with server, simply exit in that case
|
||||
pass
|
||||
|
||||
try:
|
||||
# operations.logoff() # Uncomment this after testing to logoff user
|
||||
pass
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
self.app.quit()
|
||||
|
||||
if __name__ == '__main__':
|
||||
app = QtGui.QApplication(sys.argv)
|
||||
|
||||
if not QtGui.QSystemTrayIcon.isSystemTrayAvailable():
|
||||
# QtGui.QMessageBox.critical(None, "Systray", "I couldn't detect any system tray on this system.")
|
||||
sys.exit(1)
|
||||
|
||||
# This is important so our app won't close on messages windows (alerts, etc...)
|
||||
QtGui.QApplication.setQuitOnLastWindowClosed(False)
|
||||
|
||||
try:
|
||||
trayIcon = OGASystemTray(app)
|
||||
except Exception as e:
|
||||
logger.exception()
|
||||
logger.error('OGA Service is not running, or it can\'t contact with OGA Server. User Tools stopped: {}'.format(utils.exceptionToMessage(e)))
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
trayIcon.initialize() # Initialize modules, etc..
|
||||
except Exception as e:
|
||||
logger.exception()
|
||||
logger.error('Exception initializing OpenGnsys User Agent {}'.format(utils.exceptionToMessage(e)))
|
||||
trayIcon.quit()
|
||||
sys.exit(1)
|
||||
|
||||
trayIcon.show()
|
||||
|
||||
# Catch kill and logout user :)
|
||||
signal.signal(signal.SIGTERM, sigTerm)
|
||||
|
||||
res = app.exec_()
|
||||
|
||||
logger.debug('Exiting')
|
||||
trayIcon.quit()
|
||||
|
||||
sys.exit(res)
|
|
@ -0,0 +1,289 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Resource object code
|
||||
#
|
||||
# Created by: The Resource Compiler for PyQt4 (Qt v4.8.6)
|
||||
#
|
||||
# WARNING! All changes made in this file will be lost!
|
||||
|
||||
from PyQt4 import QtCore
|
||||
|
||||
qt_resource_data = b"\
|
||||
\x00\x00\x0f\x42\
|
||||
\x89\
|
||||
\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
|
||||
\x00\x00\x30\x00\x00\x00\x30\x08\x06\x00\x00\x01\x20\x05\xc9\x11\
|
||||
\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x0e\xc7\x00\x00\x0e\xc7\
|
||||
\x01\x38\x92\x2f\x76\x00\x00\x0e\xf4\x49\x44\x41\x54\x78\xda\xc5\
|
||||
\x59\x07\x58\x53\xd9\x12\xbe\x29\xd4\x84\x12\x21\xf4\x22\x08\x08\
|
||||
\x02\x22\xa2\x22\x22\x22\x8a\xa0\xa0\x14\x1b\xae\x62\x05\xac\xb8\
|
||||
\x76\xd7\xde\xd6\xde\x15\xf5\xd9\x7b\x17\x51\x41\x50\x14\x10\x04\
|
||||
\x44\x94\x8e\xd2\x25\x80\x80\x48\xef\x24\xb4\xbc\x39\x59\x6e\x4c\
|
||||
\x42\xe2\x0a\xea\x7b\xf3\x7d\xe1\xde\x7b\xca\xcc\x9c\x73\xe6\xcc\
|
||||
\xfc\x33\x90\xd9\x6c\x36\x86\xe8\xe8\xe9\x9b\xe9\xab\x97\x79\x9a\
|
||||
\x62\x5d\x44\x46\x7f\xd6\x6f\x3f\xc1\xb6\xb7\x1d\xf6\xf7\xc3\xc0\
|
||||
\xf0\xf3\x53\x5c\xc6\x2e\xe4\x74\x9c\xbe\x78\xff\xcd\xc1\x9d\x2b\
|
||||
\x08\xf8\x48\x34\x48\x55\x85\x9e\x4a\x5e\xe6\x3d\x7d\x04\xfa\x40\
|
||||
\x8d\xd3\xdd\xc6\x6d\x73\x1c\x6b\x55\xd8\xd9\xd1\xf9\x88\xc3\x0a\
|
||||
\x9f\x11\x19\x93\xc8\x4e\x4e\xcb\xce\x5e\xeb\x3b\x7b\x07\x19\xe3\
|
||||
\xa1\xd1\x23\x2d\x08\xd0\x91\xcc\x91\x81\x6b\x15\x15\x9b\xb4\xd6\
|
||||
\xd6\x7a\xf0\x61\xae\x56\x1b\x77\x9d\x62\xed\xdb\xe6\x2b\x11\xfc\
|
||||
\x22\xfa\x10\x5f\x47\x47\x47\x87\x38\xc6\x4f\x6c\xee\x3a\x0e\x9f\
|
||||
\xba\x91\xd1\xa5\x00\x6a\x24\x30\x99\x2c\x39\x32\xef\x1a\x10\xed\
|
||||
\x3e\x7c\x91\xb5\x65\xad\xb7\x38\x9f\x56\x57\x6f\x3f\x79\xda\xd9\
|
||||
\xc9\x76\xae\xaa\xae\xd5\xe7\x6a\x85\x2f\x12\x71\x40\xef\x82\x9c\
|
||||
\xba\xed\xe1\x9c\x19\x13\x27\x9b\x18\xf5\x7b\x84\x77\xf8\x07\x86\
|
||||
\x5f\x98\xea\x32\xd6\x07\xbd\x57\xd7\xd4\xe9\xef\x3f\x7e\x35\x47\
|
||||
\x4d\x85\xde\x40\x3e\x70\xe2\x6a\x1e\x6a\xec\xec\xec\xe4\x4c\x6e\
|
||||
\x6f\xef\x90\x44\x4f\x34\xf8\xaf\x1d\x27\xd8\x07\x76\xac\xc0\x52\
|
||||
\xd3\x73\x36\x4d\x18\x67\x1d\x6a\x37\x72\x88\x23\xf9\xaf\x15\xf3\
|
||||
\xf4\xf8\x44\x92\x49\x4c\xa4\xce\xd5\xdb\x81\x9c\xc1\x70\x58\x71\
|
||||
\x70\x2e\xfb\x22\x5e\xbf\xdb\xcb\x55\x49\x18\x95\x55\xd4\xb4\xc0\
|
||||
\x43\x0a\x06\x5b\x9d\xba\x70\xaf\xc8\xd7\xc7\x03\xdb\xb0\xd3\xaf\
|
||||
\x43\xe4\x84\x0d\x2b\xe6\x4a\x27\xa5\x64\xb2\x07\x0f\x32\xc2\x5c\
|
||||
\x27\xd8\x6a\xc2\xc9\xb4\xed\xdf\xbe\x5c\x9c\xbb\x4b\x88\x92\xd3\
|
||||
\xb2\x66\xdd\x79\x18\x7a\x53\xd4\x0e\x71\x55\x82\x3d\x26\x6d\xd8\
|
||||
\x79\xb2\x7d\xa9\xd7\x34\x9b\x95\x4b\x66\x9a\xff\xeb\xb6\xa2\xc1\
|
||||
\x5b\xd7\xf9\xa8\xca\x50\xa5\xcb\xf0\xf3\x10\x29\x01\x1f\x80\x06\
|
||||
\xa3\xe7\xd0\xc1\xc6\x97\xdf\x27\x7d\x5c\xc0\x3b\x68\xdf\xb1\xcb\
|
||||
\x0d\x34\x79\x39\xaa\x89\xa1\xee\xca\x6e\x8b\xd6\xd3\xd1\x88\xc0\
|
||||
\x27\x7c\x29\xab\x1c\x25\x2f\x27\x13\x45\xa5\x50\x72\x86\x0e\x32\
|
||||
\x32\xa0\x50\xa4\x8f\x77\x9b\x80\x16\xbd\x69\xf5\x02\xed\xd6\xd6\
|
||||
\x36\x8a\xaa\x8a\x62\x14\xd8\x6b\xd6\xf2\x85\x1e\x46\x99\xd9\x05\
|
||||
\xec\x80\xa7\xaf\x0a\xc9\x72\xb2\xd4\xe2\xba\xfa\x46\x0d\x5c\x35\
|
||||
\xdd\xbe\xea\x51\xc0\xb5\x28\xe8\xf9\x6b\xf6\xa4\xf1\xa3\x30\x65\
|
||||
\xba\xc2\x01\xd4\x2e\x21\x21\x6e\xeb\x3e\xd1\x4e\x86\xbc\x79\x8d\
|
||||
\x97\xa6\xb0\xc5\xa1\xc1\x88\x86\x98\x0f\xb8\xfa\x22\x22\x2e\xc8\
|
||||
\x61\x8c\xd5\xc4\x80\xa0\x08\x86\xd0\x83\xcb\xc9\x2b\x74\x34\xd0\
|
||||
\xd3\xe6\x7e\x9b\x9b\x19\x4d\x44\xcf\xf8\xc4\xf4\xbe\x42\x27\xc0\
|
||||
\xe0\x50\xde\x2b\x95\x5f\x50\x82\xd1\x15\xe4\x31\xb0\x2d\xa2\x48\
|
||||
\xd3\x68\x6a\x6e\xa1\x1f\x3e\x75\x93\xb1\x75\xad\x17\xcd\xd2\xc2\
|
||||
\xb8\xcd\xef\xfc\xbd\x42\x58\xbc\x68\xe3\xcb\x67\x14\x8f\xd9\xbe\
|
||||
\xde\x87\xfa\x24\x24\xaa\xcd\xd5\xc9\x16\xf3\x99\xe3\x66\xc6\xe7\
|
||||
\x07\x78\xe9\xdc\xd5\x87\x11\x9f\x18\xc5\x76\xf8\xb7\xa6\xba\xf2\
|
||||
\xfb\xe5\x0b\x67\x0c\xc3\x7a\x41\x7c\x1a\xf1\x9a\x11\x5a\x1f\x81\
|
||||
\x80\xb1\x13\x53\x32\xe7\xdc\x7b\xf4\xe2\x1a\xde\xb7\x78\xfe\xd4\
|
||||
\xd1\xe8\xa8\x7a\x24\x20\x2a\x36\x71\x5d\xf0\x8b\x98\x83\xe8\x5d\
|
||||
\x52\x52\xa2\x6e\xd7\xc6\xc5\xf2\xf8\x00\x8b\x41\x46\xd7\x91\x00\
|
||||
\xfc\x1b\x8d\xed\x91\x80\xbc\xfc\xcf\x63\x71\xe6\x88\x78\x99\xe3\
|
||||
\xb4\x68\xfe\x14\xbb\x73\x57\x1e\xbe\xfa\xc7\xf6\x07\x5c\xe6\xf3\
|
||||
\x92\x6c\x36\x71\xcb\x9e\x33\x6d\xfa\xba\x5a\xc4\xd9\x1e\xce\x18\
|
||||
\x89\x44\xe4\xf1\x7e\x81\x35\xe4\xf3\xd7\x02\xc2\x04\x27\x10\x08\
|
||||
\x84\x4e\x3e\x73\xf7\x7f\x7e\x0b\x3d\x89\x44\x62\xbb\x89\x91\x5e\
|
||||
\x00\x7a\x2f\x2a\x2e\x73\x3a\x7b\xc5\x3f\x78\xef\x56\x5f\x6c\xcf\
|
||||
\x96\x65\xd8\xf6\xfd\x67\xeb\xd3\x3e\xe6\x2c\x95\x92\x92\x6c\xaf\
|
||||
\xab\x6f\xba\x0b\x96\x81\xa9\xa9\x2a\x7d\x21\x7b\xcf\x76\x1b\x7f\
|
||||
\xf1\xc6\xe3\xe7\x5c\xcf\xb2\xd3\xaf\xed\xc0\x8e\x3f\x49\x82\xe7\
|
||||
\x62\xa8\xdf\x37\x64\x81\xa7\xab\x33\xde\x06\xde\x06\x43\xcc\xbb\
|
||||
\xbe\x91\x3b\x96\xe3\x84\xb2\x33\x37\xd9\x43\x06\x0d\xa8\xdd\xba\
|
||||
\xe7\x0c\x79\xc3\xca\x79\xa3\xc9\xc8\x88\x91\x33\x89\x8e\x4b\x5e\
|
||||
\x05\xf7\xeb\x28\x5a\x01\xce\x14\x1d\xf2\x8a\xc5\x33\x07\xab\xab\
|
||||
\xd2\x93\x79\x05\xc2\x78\x5e\xc3\xc0\x78\x9d\x51\x7f\x3d\xed\xa0\
|
||||
\xa7\xa1\xd1\x93\xf4\x74\x34\xb1\xf8\x84\x8f\xe5\x5c\x2b\xb2\xb1\
|
||||
\x32\x3f\x86\x7e\xdf\x3b\xb0\x82\xa2\x52\x6b\xfb\xd1\x96\x22\xfb\
|
||||
\x71\x37\xef\xec\x60\xc3\x15\x4e\xee\x89\x4d\xab\x2a\xd3\xd3\xc2\
|
||||
\xa3\xde\xf3\xb5\x59\x5a\x98\x60\x17\xae\x3d\xea\xd4\xd6\x54\x21\
|
||||
\xcc\xfd\x63\x12\x8f\x7f\xce\xae\x9a\x60\x3f\xe2\x48\x8f\x04\x48\
|
||||
\x48\x88\x35\x8c\xb2\x1e\x3c\xee\xef\x43\x17\x43\x60\x7f\xc5\xc4\
|
||||
\xc4\xc8\x10\xbd\x87\x74\x1c\xf2\xbb\xce\xae\xad\xab\xaf\xb6\xb6\
|
||||
\x1c\xa4\xd4\x15\xc4\xc0\xb1\x7c\x48\x5f\x3c\x7f\xca\x3e\x72\x4f\
|
||||
\x6f\xa6\xbe\xae\x66\x18\xc4\x22\x83\x0b\xd7\x1f\x31\x1c\xc7\x58\
|
||||
\x61\xe9\x19\xb9\x24\x63\xc3\x7e\xfe\x39\x9f\x0a\xa7\x52\x28\x52\
|
||||
\x1c\xe6\x7b\x8f\x5e\x29\xdd\xb2\xd6\xcb\xee\xbb\x81\xed\x7b\xd4\
|
||||
\x87\x26\x5b\x00\x91\xfd\x6b\x42\x4a\x46\x2b\xf8\x4f\xcd\xe6\x66\
|
||||
\xe6\x54\x3b\x1b\x8b\x57\x87\xfd\xae\xab\x8d\xb7\xb7\xde\x08\xcc\
|
||||
\xb9\x31\x5b\xa8\x2f\x42\x04\x93\x14\x82\x42\x5f\x1f\x49\xfb\x98\
|
||||
\x3b\x8d\x4c\x22\xb5\xee\xdc\xb8\x98\xf6\xd3\xbe\x88\x13\x92\xbf\
|
||||
\x56\x9a\x1e\x3d\x73\x2b\x8d\xb7\x0d\xc5\x47\xac\x97\xc4\x27\xe0\
|
||||
\xc1\x93\xb0\x4b\x78\x44\x43\xb6\x8f\xee\x00\x7a\x87\xd8\x1f\x07\
|
||||
\x37\x77\xb8\xcb\x04\xdb\x15\x23\x87\x0f\x3a\xd9\x2b\x01\x8f\x9e\
|
||||
\xbe\x3a\x83\x33\x47\x0e\xce\xc3\xdd\x61\xae\xa0\x87\x0d\x7c\x16\
|
||||
\x75\xa2\x57\x02\x8a\x4b\xcb\x2d\xe2\xde\xa7\x2d\x41\xef\x52\x92\
|
||||
\x12\xb5\x38\xf3\x5f\x41\x1c\x01\x27\xcf\xdd\x49\xc0\x1b\x04\xa3\
|
||||
\xae\x9b\xd3\xe8\xe5\x8f\x43\x22\xfd\x7a\x2d\x20\x3c\xea\xdd\x16\
|
||||
\xde\x06\x71\x71\xb1\x46\xde\xef\x11\x96\x66\xa7\x7e\x44\x40\xc8\
|
||||
\xcb\xd8\x07\x1f\x33\x3f\xb9\x56\x54\xd5\x88\x71\x6e\xbd\x0a\x3d\
|
||||
\x6f\xd5\x92\x99\xfa\xe4\xd0\x88\xb8\xbf\xf1\x41\x70\x33\x5b\x7a\
|
||||
\xaa\xe1\xeb\x37\x49\x67\x82\x43\xa3\x97\x78\x7a\x38\x61\x4e\xe3\
|
||||
\xac\xb9\xed\x8d\x8d\x2d\x7a\x27\xcf\xde\x49\xe0\xb3\x22\x8a\xb4\
|
||||
\x54\xc5\xf7\x98\xa9\x28\x2b\xa6\xf3\x7e\xef\x39\x72\x89\xa9\xa3\
|
||||
\xad\x2e\x71\x00\xbc\x6b\x65\x55\x6d\x33\x18\x84\xb4\x9a\x32\xbd\
|
||||
\x73\xe5\xd2\x99\x44\x2a\x55\x0a\x6b\x6d\x6f\x97\xe1\x13\xd0\xd0\
|
||||
\xd8\xa4\x2a\xc8\x14\x07\xc7\x88\x16\xcc\x72\x71\xc6\xdf\xc1\xc1\
|
||||
\x35\xb9\x39\xdb\x49\x18\x1b\xea\x62\xe5\x15\xd5\x0d\xc7\xfe\x73\
|
||||
\x5b\x02\xb9\xed\x93\xe7\xef\x72\xad\x8e\x2a\x2d\x55\xc6\x27\xa0\
|
||||
\xa3\xa3\x53\x4c\x50\x00\x4a\x17\xba\xb6\xaf\x19\x30\xd9\x67\xf4\
|
||||
\x7e\xe4\xf4\xcd\xba\x31\x36\x43\xa4\x11\x73\x8e\xb0\xeb\x01\xf5\
|
||||
\x90\x88\x68\x7c\xcb\x34\x30\xec\xfe\xe3\x97\x59\x66\x03\x0d\xee\
|
||||
\x74\xbb\xc9\x9f\x4b\xbe\x0e\x45\x30\xa5\x6b\x7f\x57\xc3\xd2\xf5\
|
||||
\x39\x29\xc7\xe6\x65\xd4\x2e\x58\xe6\x29\x21\x2e\x26\x6b\x3e\xd0\
|
||||
\x90\x33\x1e\x00\x41\xb6\xfb\xc4\x31\xeb\xd1\x7b\x62\x6a\xe6\x5e\
|
||||
\x2a\x45\x1a\xbb\x7c\x2b\x30\xbd\xae\xbe\xa1\x13\x32\xab\xb3\x1c\
|
||||
\x30\x08\x7b\xf9\x19\x17\xe0\x77\xfe\xee\x3b\x04\x6e\x11\xf2\x42\
|
||||
\x50\x1a\xb5\x21\x3f\x84\xa2\x1b\x7a\x87\xf0\x7a\x83\x37\xa2\x01\
|
||||
\xac\xe9\x0f\xf7\x26\x90\x83\x3c\xb5\xd5\xcf\x41\x40\xcf\x30\x32\
|
||||
\xd0\x09\x2a\xfd\x5a\x69\xd6\xd8\xd8\xac\xc4\x81\xa7\x28\xcf\x82\
|
||||
\xcc\x24\x1f\x60\xaa\xfa\x3f\x67\xd1\xac\xc2\xc1\x84\xfd\xb4\x5e\
|
||||
\x78\xcf\x71\x77\xc4\x99\x65\xe5\x16\x4c\x1b\x31\xcc\x8c\xcb\xbc\
|
||||
\xbc\xb2\x06\x1b\x64\xda\xff\x0e\xfe\x2d\x29\x21\x51\xff\x30\x28\
|
||||
\xe2\x9a\x96\x9a\x32\xb1\xbf\x7e\x5f\x2c\x3c\x22\x21\x9a\xb3\x45\
|
||||
\x24\xf0\x96\xb0\x12\x8d\x7f\x33\xc9\x98\xf8\x94\x63\xde\x9e\x6e\
|
||||
\xdc\xef\xac\x1c\x46\xae\xf5\x70\x33\xee\x1d\xb9\xf7\xf8\x65\xf5\
|
||||
\xce\x0d\x8b\x10\x3f\xce\x77\xf0\xcb\x18\x9b\x1e\xc5\x83\x9c\xdc\
|
||||
\x42\x75\xde\x6f\x70\x2b\xc5\xb5\xb5\x0d\x5a\xda\x1a\xaa\x71\x57\
|
||||
\x6e\x05\x66\x8f\xb2\xb6\xe0\x32\xaf\xad\x6b\xc0\x10\xc4\x21\xff\
|
||||
\x8c\x9f\xa9\x6f\x68\x1a\x06\xfb\xbd\xa6\xa9\xa9\x45\xad\xb0\xf8\
|
||||
\x8b\x41\xbf\xbe\xdf\xe4\x83\xf3\xcc\x07\xc4\xbf\xb2\x47\x02\xe8\
|
||||
\x8a\xb4\x6a\x14\xd0\xbe\x21\x91\xc1\x94\x4b\x37\x1f\x27\x12\xe1\
|
||||
\x64\xb7\xad\x5b\xc8\x37\x36\x33\x87\xa1\x3b\x5f\xce\xe5\x73\x8f\
|
||||
\x04\x8c\xb2\x1a\xbc\xf1\x55\x74\xc2\x39\x3b\x9b\x21\x5d\x7e\x8b\
|
||||
\x8c\x2d\x59\x30\x95\xc0\x62\xb5\xb2\xf7\x1f\xbf\x4c\xd8\xb4\xda\
|
||||
\xab\xeb\xc2\x36\x63\xda\x9a\xaa\x6f\x7a\x1c\x93\x2d\x87\x98\x9c\
|
||||
\xdf\xb4\xeb\x94\x9f\xa4\xb8\xb8\xb8\x95\xe5\x40\x4e\x5b\x58\x64\
|
||||
\x7c\xea\xcb\xc8\x78\x53\x49\x09\x71\x2e\xf8\xba\x1b\x10\x9a\xe6\
|
||||
\x33\xc7\xdd\xa1\x57\x41\x7f\x2f\x98\x34\x30\xdd\xb6\x69\xf7\xa9\
|
||||
\x8d\x04\x36\x81\x34\xc5\x65\xec\x11\x40\x19\x0c\xd8\x92\x68\x7c\
|
||||
\x0c\xe4\x16\x03\xc0\x2b\x37\xf5\x1a\x55\xa4\x7e\xcc\x5d\xa4\xad\
|
||||
\xa1\x26\xe9\x3d\xdb\x1d\xdb\xb8\xeb\xe4\x75\x45\x05\x5a\xdd\xea\
|
||||
\xa5\xb3\x38\x7d\x37\xef\x3f\x7b\xb7\x7a\x99\xe7\x5c\x91\x41\xff\
|
||||
\x47\x48\xa1\x8f\x9c\xfc\xbc\x2e\x14\xb7\x6f\xdb\x72\xec\xdc\xb5\
|
||||
\x00\x39\x48\xfc\x31\x46\x61\x49\x45\x51\xf1\x17\x55\x25\x45\x5a\
|
||||
\xd6\x4f\x09\xb0\x1e\x66\xe6\x76\xe6\xd2\xfd\x13\x0e\x76\x23\x34\
|
||||
\x5a\x98\x4c\x19\x27\xfb\x11\xf5\x00\x9e\x1f\x46\xc6\x24\x4c\x80\
|
||||
\xa4\x5b\x8b\x2f\xa2\x89\xc2\x45\xc2\xe8\x53\x41\xf1\xe8\x98\xb8\
|
||||
\x94\x15\x59\xb9\x0c\x67\x61\x9e\x17\x05\x2c\x2f\x4f\xb7\x09\x3d\
|
||||
\xc9\x80\x7e\x49\xcc\xff\x1e\xa1\xb4\xe1\x59\x58\xec\xbe\xf6\xf6\
|
||||
\x0e\x89\x6e\x01\x4e\x49\xe1\x83\xa9\xb1\xbe\x3f\x84\x85\x27\x6a\
|
||||
\x2a\xf4\x14\xd8\x0b\x42\x76\x5e\xc1\xf8\xd0\xf0\xb8\xdd\xda\x5a\
|
||||
\xaa\xb1\x90\xb3\x3c\xfb\xbf\x2c\x00\x45\x81\x3b\x0f\x9f\xdf\x4a\
|
||||
\xfd\x90\xe3\x21\xd8\x87\x20\xd9\x94\x49\x63\x17\x82\xcd\xb0\xf0\
|
||||
\xb6\xf8\x84\x0f\x0b\x01\xfb\xbd\x15\x5c\x24\x44\xf8\xca\x2d\x6b\
|
||||
\xbd\xd5\x20\x2d\x6c\xfb\x9f\x2d\x20\xe6\x6d\xca\x9f\x08\x1f\x76\
|
||||
\x4f\x0a\xb4\xc2\xbc\x20\x5b\x04\xaf\xd6\xc1\xdb\x8e\x83\x56\x11\
|
||||
\xc5\x08\x45\x74\x82\xa3\x47\x5a\x1c\xfc\xed\x0b\x40\x36\x7d\xfc\
|
||||
\xec\xed\xe4\xaf\xe5\x55\xc6\x82\x83\x20\xcf\xda\x64\x67\x33\x74\
|
||||
\x9f\x30\x06\x28\x05\x3e\x70\xf2\x5a\x2e\xc4\x03\xba\xb0\x7e\xb8\
|
||||
\xd5\xc3\x7f\xbb\x09\xb5\x30\x59\xf2\xfb\x8f\x5d\x61\xa0\x67\x37\
|
||||
\xef\x6c\x61\x72\x41\x94\xf2\x78\x59\x63\xd3\xaa\x05\xda\x00\x4a\
|
||||
\x8a\x9b\x5b\x98\x7d\xba\x8f\x20\xb0\x7b\xab\x5c\x45\x65\xad\x41\
|
||||
\x69\x59\xb9\x65\x6d\x5d\xa3\xa1\x18\x99\xc4\x6c\xef\xe8\x60\x2a\
|
||||
\xd1\x69\x19\xba\xda\x1a\x91\x5c\x47\x8d\xec\x1d\xd5\xb0\x85\x29\
|
||||
\x8f\x08\x52\xee\x9d\xff\x26\x08\x79\x9f\x49\xe3\x47\xad\x06\xf8\
|
||||
\x75\x55\xb0\x4f\x5d\x8d\x9e\xf4\x23\xca\x02\x3c\xe8\x17\x1b\x9f\
|
||||
\x72\x36\x3a\x2e\xc5\x1e\xe5\xa8\x70\x7f\x50\xb9\x11\xa3\xc9\xcb\
|
||||
\x00\x1a\x56\x40\xd0\x02\x83\x0d\x42\xe8\x17\x8b\x7e\x9b\xca\x66\
|
||||
\xb6\xb0\xb2\x2d\xcc\x0c\x4f\x93\x43\x5e\xc6\x1c\x44\x05\x41\x61\
|
||||
\x4c\x11\x1a\x83\x5f\xc9\x8f\x28\x40\xa3\xc9\x32\x84\xb5\x0f\x35\
|
||||
\x37\xbe\x22\x6a\x0e\x04\x6d\xcd\xdb\xfe\xcf\x62\x21\xf4\x69\xca\
|
||||
\xca\x50\xb0\x89\x8e\x36\x9c\xc0\x02\xf0\x11\x4c\xba\x03\x7b\x9f\
|
||||
\x94\x91\x99\x99\xcb\xc0\xc0\xbb\x19\x59\x0f\x1b\x84\x2a\x31\x70\
|
||||
\x19\x31\x0c\xf2\x37\x42\xf4\x9b\x64\x03\x94\xb0\x90\x01\xa8\xce\
|
||||
\x16\x25\x00\xee\x85\xf8\x8f\x1e\x37\xca\xa3\x05\xdb\x1c\xc6\x58\
|
||||
\x6d\x03\xc5\x4a\x85\x14\x53\xdc\x01\x18\xfb\xb7\xb6\xb6\x12\x27\
|
||||
\x3a\x8e\xc2\x16\xcd\x9b\xc2\xed\x2b\x2e\xfd\x5a\x7d\xf1\xfa\x63\
|
||||
\x12\x84\xdf\x4c\x4d\x75\xa5\xf7\x03\x8d\xf5\x13\x60\x21\x57\x5a\
|
||||
\x5b\x59\x44\x5e\x1e\xb2\xb2\x14\xe4\x05\xa5\xc8\x4c\x66\xab\x9c\
|
||||
\x28\xa5\x1a\x9b\x9a\x95\xe0\x68\xb5\x50\x89\xf6\x7b\xca\xa7\xa4\
|
||||
\xe7\xcc\x78\x13\x9f\xea\x2b\xe8\x6e\xd1\x7f\x51\x78\xdb\xaa\xaa\
|
||||
\x6b\x4d\x4f\x5d\xbc\x9f\x04\x32\xc9\x0b\x3c\x5d\x51\xb9\x83\xdb\
|
||||
\xd7\xda\xda\x86\x9d\xbd\xe2\xff\xa9\xe4\x4b\xb9\xee\x8c\xc9\x8e\
|
||||
\xb3\x21\x2b\xe0\x14\xd7\xb2\x73\x0b\xd6\x80\x1e\xc4\xc6\x26\x26\
|
||||
\x77\x2c\x93\xc9\x62\x07\x3e\x7b\xdd\x02\x9b\x53\x4b\x36\x33\xd1\
|
||||
\xbf\x9f\x94\x9a\xe5\x29\x4a\xb9\xa0\xe7\xd1\x47\x66\x7b\x38\x4d\
|
||||
\x13\xd5\x8f\x5c\x2e\x72\xbd\x02\xe5\xe5\xd5\x82\x25\x2d\xff\x27\
|
||||
\x61\x31\xef\x92\x3e\x5a\x83\x4b\x85\x14\x71\x24\x1f\x0f\xb0\xeb\
|
||||
\xd6\x23\xa7\x6f\x10\x15\x68\x72\x6d\x7b\xb6\xf8\x4a\xe1\x31\x06\
|
||||
\xcc\x48\x02\x92\x80\x7d\x80\x17\x61\x43\x0c\x51\x7c\xc2\x9e\x85\
|
||||
\xc5\x64\x15\x7d\x2e\xab\xea\x43\x93\x25\x2e\x9e\x3f\xd5\x96\xec\
|
||||
\xe1\xee\x38\xa7\xae\xae\x51\x03\xc1\x04\x61\x0a\xa6\x67\xe4\x4e\
|
||||
\xdd\x7d\xf8\x62\x29\xda\x15\x3d\x5d\xcd\x70\x3c\x2b\x81\xe8\xbc\
|
||||
\x37\x21\x39\x63\x3e\xef\x58\x0d\x35\xe5\x84\x85\x73\xdd\xed\x91\
|
||||
\x67\xe2\x75\xcf\xe0\x24\x60\xf3\xeb\x64\xd6\xf8\xce\xc6\x94\xe9\
|
||||
\x7d\x04\x61\x39\x1b\x92\xb8\x0f\x06\x7a\x7d\x8b\xe7\xcf\x9c\xe4\
|
||||
\xca\xdb\xf7\x34\x34\xe6\x04\x91\x4d\xac\x01\x07\xa3\x04\xe9\x54\
|
||||
\x2c\x89\x48\x68\xd7\xd1\xd6\x78\x0d\xf1\xe8\x20\x9e\xc4\x93\x51\
|
||||
\xbe\x85\x8a\xad\xd5\x35\xf5\x3a\x37\xee\x3d\x7d\x58\xf2\xa5\xc2\
|
||||
\x5c\x08\xf6\x57\x15\xac\xa9\x72\x9d\x24\x81\xd0\x39\x6a\xc4\xe0\
|
||||
\x23\xe3\xc7\x8e\xd8\x2c\x18\x71\x51\xd5\x12\x32\xd3\x2a\x29\x49\
|
||||
\x71\x99\xcd\x6b\xbc\x31\x2a\x45\x4a\x58\x6d\xbc\x02\xf8\xeb\x6f\
|
||||
\x5b\xe7\xd3\xad\x4c\xe4\xea\x64\xbb\x18\xfd\x5a\x5a\x58\x34\xb8\
|
||||
\xab\x9b\xe0\xee\x38\x47\x44\xbf\xdb\x12\x9f\x98\xbe\x59\x49\x51\
|
||||
\xa1\x91\x4a\x95\x7c\x41\xe6\xa9\x8c\x31\xf0\x92\x10\xda\xb5\xdc\
|
||||
\xfc\x22\x7b\xb0\xbf\x09\x5f\xca\x2a\xcd\xea\x1a\x1a\xd5\x11\xce\
|
||||
\x41\xee\x52\xb1\x8f\x5c\x9e\x96\x86\xea\x5b\x93\x01\xfd\x02\xe8\
|
||||
\x0a\xb4\x9c\xef\xdd\x8d\x07\x4f\xc2\xa2\x60\xeb\x65\x56\x2c\xfe\
|
||||
\x43\xa8\xf2\xef\x12\x33\xea\xc0\x5d\xe6\x3a\xd8\x59\xf9\xa1\xd4\
|
||||
\x5b\xa0\xc8\xa6\x88\xee\x04\x89\x48\x92\x6d\x61\xb1\x50\xa5\x15\
|
||||
\x9b\x3c\x69\x0c\xe6\x39\xdd\x89\xb3\x6f\xc9\x69\xd9\x84\xc4\xd4\
|
||||
\x2c\xaa\x50\x2c\x84\x76\x12\x01\xb1\x9f\x01\x63\xb0\xab\x6a\x60\
|
||||
\x62\x23\xcd\x4c\x0c\x30\x75\x55\x25\xa1\x63\x5a\x98\x2d\x79\xa8\
|
||||
\xbc\xeb\x60\x37\x7c\x3b\x6f\xfb\x97\xaf\x95\x56\xfe\x81\x61\x51\
|
||||
\x10\x43\xc4\xa6\xb9\x3a\x60\x00\x5f\xba\xcd\x85\xac\xa4\x05\xa0\
|
||||
\xca\x30\xf2\xef\x0a\xf1\xa0\x84\x29\x28\xde\x01\xf7\x86\x24\xba\
|
||||
\xb2\x2b\x4e\xfc\x67\x21\x4c\x6e\x09\x13\x4e\x7e\xd6\xbd\x80\x17\
|
||||
\x37\x54\x94\x15\x09\x1e\xdf\x92\x7e\x3e\x8a\x4f\xfc\x50\x51\x51\
|
||||
\x55\xa3\x04\xa0\x72\xd1\x6f\x5b\x00\x95\x22\x5d\x0e\x2e\x91\x54\
|
||||
\x59\x55\x23\x7a\x10\x9b\x68\x0e\xc9\x74\xc9\xe7\xe2\x72\x6b\x22\
|
||||
\x81\x44\x09\x7f\x1d\x7f\x1c\x2e\xa7\xfc\xe8\x91\x43\x21\x58\x99\
|
||||
\x09\x9d\x82\x3c\xd2\x93\x90\x48\x39\x0d\x35\xa5\x44\x94\x84\xfe\
|
||||
\xb6\x05\xa0\x32\x2b\x78\xa5\xcc\x37\xef\xd2\x8c\xc6\xd8\x58\x62\
|
||||
\x52\x52\xdd\x63\xe2\xf0\xa1\xc6\x90\x09\x1b\xab\x17\x14\x95\xac\
|
||||
\xac\xa9\x6b\xc0\xa6\xbb\x39\x40\x6e\x2f\x0f\x59\xef\x0b\x80\x16\
|
||||
\xf5\x9c\xc8\x2c\x48\xb7\x1e\x3c\xfb\x04\xee\x55\x17\xee\xc2\xf4\
|
||||
\x5e\xa7\x7c\x3f\x4a\x8b\xe6\x4d\xb6\x3c\xe4\x77\x3d\xef\xf2\xad\
|
||||
\xc7\x34\xf0\x26\x62\xb0\x20\x21\x5e\x0c\xc3\x74\xb4\xd5\x31\xc9\
|
||||
\xb2\xca\xfa\x9b\xf7\x83\xeb\xcb\x2b\x6b\x38\xb0\x66\xde\x4c\x97\
|
||||
\x6e\x63\x23\x5e\xbf\x67\x64\xe5\x16\xf4\x9b\xe6\x6a\xef\xd5\x87\
|
||||
\x26\x97\xff\xdb\x17\x00\x36\xde\x00\x09\x8d\x32\xa4\xfc\xce\x90\
|
||||
\xa5\x2d\xcf\xce\x2b\x74\xd4\xd3\xd5\xca\x07\x08\x41\x55\x52\xec\
|
||||
\x53\x0d\xb0\x41\x16\x14\x56\x42\xa5\x65\x9a\x1c\xb5\xc8\xd5\xc9\
|
||||
\x6e\xfd\xad\x07\x21\x21\x14\x8a\x94\xf8\x80\xfe\x3a\xfc\x99\xfe\
|
||||
\x87\xdc\xca\xe7\xe1\x6f\x74\x00\x07\x9d\x40\xff\x53\xfe\xa9\xa4\
|
||||
\xbb\xa7\x64\x64\xa0\x13\x8c\x7e\x2c\x56\x1b\x35\x22\xfa\xfd\xc5\
|
||||
\x9c\xbc\xc2\xc9\x48\x71\x0d\xf0\x4e\x54\xaa\x74\xbe\x32\x5d\x21\
|
||||
\x04\xa2\xf7\xca\x97\x91\x6f\xaf\x01\xe2\x14\xf7\x98\xec\x20\x58\
|
||||
\x06\xaa\x84\x85\x29\x9a\x0f\xec\x7f\xdb\x65\x82\xed\xca\x1e\xe5\
|
||||
\xc4\xbf\x8a\x62\xe3\x53\xd7\x31\x0a\x4b\xf6\xd3\x15\xe4\x89\xbe\
|
||||
\x3e\xd3\xb9\x55\xb6\xb6\xb6\x76\xdd\xab\xb7\x83\x7c\x37\xec\x3c\
|
||||
\xe9\xdb\x85\xa1\xd0\x82\xb9\xf3\x22\x63\x12\xf2\x42\x5e\xc6\xea\
|
||||
\x41\x1c\x38\x0e\x8b\x5c\xd5\xe3\xa4\xfe\x57\xd1\x40\x63\xbd\x1b\
|
||||
\x99\xd9\x0c\x97\xe2\xd2\x0a\xd3\x8c\x6c\x86\x9c\xe9\x00\x3d\x3c\
|
||||
\x97\xc0\x7c\xe6\xba\xe3\x48\x14\xc3\xef\xc9\xe7\x92\xaf\x99\x37\
|
||||
\xee\x05\xcb\x4b\x4b\x4b\x36\x2c\xf5\x9a\x36\xb2\xaf\x96\x5a\x6c\
|
||||
\xaf\xaa\x12\xbf\x8a\x64\xa8\x94\x32\xef\x39\x6e\x36\xa8\x26\xfd\
|
||||
\x28\xf8\xd5\x19\x00\x81\x86\x60\x52\xb2\x4c\x16\x4b\x16\xb0\x53\
|
||||
\x23\x20\x4c\x4e\x8d\x1a\xd5\xaf\xc5\xc4\xc4\x9a\xca\x2b\xaa\x07\
|
||||
\xfc\x31\xc5\x71\xa6\x7e\x3f\xad\xf0\xef\xf1\xfd\x2f\x9a\x21\xe5\
|
||||
\x2e\x6b\x8c\x93\x5e\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\
|
||||
\x82\
|
||||
"
|
||||
|
||||
qt_resource_name = b"\
|
||||
\x00\x06\
|
||||
\x07\x03\x7d\xc3\
|
||||
\x00\x69\
|
||||
\x00\x6d\x00\x61\x00\x67\x00\x65\x00\x73\
|
||||
\x00\x03\
|
||||
\x00\x00\x70\x37\
|
||||
\x00\x69\
|
||||
\x00\x6d\x00\x67\
|
||||
\x00\x07\
|
||||
\x05\xd4\x57\xa7\
|
||||
\x00\x6f\
|
||||
\x00\x67\x00\x61\x00\x2e\x00\x70\x00\x6e\x00\x67\
|
||||
"
|
||||
|
||||
qt_resource_struct = b"\
|
||||
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\
|
||||
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x02\
|
||||
\x00\x00\x00\x12\x00\x02\x00\x00\x00\x01\x00\x00\x00\x03\
|
||||
\x00\x00\x00\x1e\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
|
||||
"
|
||||
|
||||
def qInitResources():
|
||||
QtCore.qRegisterResourceData(0x01, qt_resource_struct, qt_resource_name, qt_resource_data)
|
||||
|
||||
def qCleanupResources():
|
||||
QtCore.qUnregisterResourceData(0x01, qt_resource_struct, qt_resource_name, qt_resource_data)
|
||||
|
||||
qInitResources()
|
|
@ -0,0 +1,240 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>OGAAboutDialog</class>
|
||||
<widget class="QDialog" name="OGAAboutDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>466</width>
|
||||
<height>402</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Verdana</family>
|
||||
<pointsize>9</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>About OGAgent</string>
|
||||
</property>
|
||||
<property name="locale">
|
||||
<locale language="English" country="UnitedStates"/>
|
||||
</property>
|
||||
<property name="modal">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="LogoLabel">
|
||||
<property name="text">
|
||||
<string><html><head/><body><p><img src=":/images/img/oga.png"/>OpenGnsys Agent Tools</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>5</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="TitleLabel">
|
||||
<property name="text">
|
||||
<string><html><head/><body><p><span style=" font-family:'Sans Serif'; font-size:9pt; font-weight:600;">OpenGnsys Agent</span></p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="VersionLabel">
|
||||
<property name="text">
|
||||
<string>Version 1.0.0</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>5</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="aboutTab">
|
||||
<attribute name="title">
|
||||
<string>&About</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTextBrowser" name="aboutBrowser">
|
||||
<property name="html">
|
||||
<string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Verdana'; font-size:9pt; font-weight:400; font-style:normal;">
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif';"><br /></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif'; font-weight:600;">(c) 2014, Virtual Cable S.L.U.</span></p>
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-style:italic;"><br /></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://www.udsenterprise.com"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt; text-decoration: underline; color:#0000ff;">http://www.opengnsys.es</span></a></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://www.openuds.org"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt; text-decoration: underline; color:#0000ff;">http://www.udsenterprise.com</span></a></p>
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif';"><br /></p></body></html></string>
|
||||
</property>
|
||||
<property name="openExternalLinks">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="authorsTab">
|
||||
<attribute name="title">
|
||||
<string>A&uthors</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTextBrowser" name="authorsBrowser">
|
||||
<property name="html">
|
||||
<string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Verdana'; font-size:9pt; font-weight:400; font-style:normal;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans Serif';">Adolfo Gómez García &lt;agomez@virtualcable.es&gt;</span></p></body></html></string>
|
||||
</property>
|
||||
<property name="openExternalLinks">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="licenseTab">
|
||||
<attribute name="title">
|
||||
<string>&License Agreement</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTextBrowser" name="licenseBrowser">
|
||||
<property name="html">
|
||||
<string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Verdana'; font-size:9pt; font-weight:400; font-style:normal;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">Copyright (c) 2014 Virtual Cable S.L.</span></p>
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:8pt;"><br /></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">All rights reserved.</span></p>
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:8pt;"><br /></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">Redistribution and use in source and binary forms, with or without modification,</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">are permitted provided that the following conditions are met:</span></p>
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:8pt;"><br /></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;"> * Redistributions of source code must retain the above copyright notice,</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;"> this list of conditions and the following disclaimer.</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;"> * Redistributions in binary form must reproduce the above copyright notice,</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;"> this list of conditions and the following disclaimer in the documentation</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;"> and/or other materials provided with the distribution.</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;"> * Neither the name of Virtual Cable S.L. nor the names of its contributors</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;"> may be used to endorse or promote products derived from this software</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;"> without specific prior written permission.</span></p>
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:8pt;"><br /></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS &quot;AS IS&quot;</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</span></p>
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:8pt;"><br /></p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Close</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="OGAgent.qrc"/>
|
||||
</resources>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>clicked(QAbstractButton*)</signal>
|
||||
<receiver>OGAAboutDialog</receiver>
|
||||
<slot>closeDialog()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>432</x>
|
||||
<y>381</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>282</x>
|
||||
<y>362</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
<slots>
|
||||
<slot>closeDialog()</slot>
|
||||
</slots>
|
||||
</ui>
|
|
@ -0,0 +1,163 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Form implementation generated from reading ui file 'about-dialog.ui'
|
||||
#
|
||||
# Created by: PyQt4 UI code generator 4.11.4
|
||||
#
|
||||
# WARNING! All changes made in this file will be lost!
|
||||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
|
||||
try:
|
||||
_fromUtf8 = QtCore.QString.fromUtf8
|
||||
except AttributeError:
|
||||
def _fromUtf8(s):
|
||||
return s
|
||||
|
||||
try:
|
||||
_encoding = QtGui.QApplication.UnicodeUTF8
|
||||
def _translate(context, text, disambig):
|
||||
return QtGui.QApplication.translate(context, text, disambig, _encoding)
|
||||
except AttributeError:
|
||||
def _translate(context, text, disambig):
|
||||
return QtGui.QApplication.translate(context, text, disambig)
|
||||
|
||||
class Ui_OGAAboutDialog(object):
|
||||
def setupUi(self, OGAAboutDialog):
|
||||
OGAAboutDialog.setObjectName(_fromUtf8("OGAAboutDialog"))
|
||||
OGAAboutDialog.resize(466, 402)
|
||||
font = QtGui.QFont()
|
||||
font.setFamily(_fromUtf8("Verdana"))
|
||||
font.setPointSize(9)
|
||||
OGAAboutDialog.setFont(font)
|
||||
OGAAboutDialog.setLocale(QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.UnitedStates))
|
||||
OGAAboutDialog.setModal(True)
|
||||
self.vboxlayout = QtGui.QVBoxLayout(OGAAboutDialog)
|
||||
self.vboxlayout.setMargin(9)
|
||||
self.vboxlayout.setSpacing(9)
|
||||
self.vboxlayout.setObjectName(_fromUtf8("vboxlayout"))
|
||||
self.LogoLabel = QtGui.QLabel(OGAAboutDialog)
|
||||
self.LogoLabel.setObjectName(_fromUtf8("LogoLabel"))
|
||||
self.vboxlayout.addWidget(self.LogoLabel)
|
||||
spacerItem = QtGui.QSpacerItem(20, 5, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Fixed)
|
||||
self.vboxlayout.addItem(spacerItem)
|
||||
self.TitleLabel = QtGui.QLabel(OGAAboutDialog)
|
||||
self.TitleLabel.setObjectName(_fromUtf8("TitleLabel"))
|
||||
self.vboxlayout.addWidget(self.TitleLabel)
|
||||
self.VersionLabel = QtGui.QLabel(OGAAboutDialog)
|
||||
self.VersionLabel.setObjectName(_fromUtf8("VersionLabel"))
|
||||
self.vboxlayout.addWidget(self.VersionLabel)
|
||||
spacerItem1 = QtGui.QSpacerItem(20, 5, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Fixed)
|
||||
self.vboxlayout.addItem(spacerItem1)
|
||||
self.tabWidget = QtGui.QTabWidget(OGAAboutDialog)
|
||||
self.tabWidget.setObjectName(_fromUtf8("tabWidget"))
|
||||
self.aboutTab = QtGui.QWidget()
|
||||
self.aboutTab.setObjectName(_fromUtf8("aboutTab"))
|
||||
self.vboxlayout1 = QtGui.QVBoxLayout(self.aboutTab)
|
||||
self.vboxlayout1.setMargin(9)
|
||||
self.vboxlayout1.setSpacing(6)
|
||||
self.vboxlayout1.setObjectName(_fromUtf8("vboxlayout1"))
|
||||
self.aboutBrowser = QtGui.QTextBrowser(self.aboutTab)
|
||||
self.aboutBrowser.setOpenExternalLinks(True)
|
||||
self.aboutBrowser.setObjectName(_fromUtf8("aboutBrowser"))
|
||||
self.vboxlayout1.addWidget(self.aboutBrowser)
|
||||
self.tabWidget.addTab(self.aboutTab, _fromUtf8(""))
|
||||
self.authorsTab = QtGui.QWidget()
|
||||
self.authorsTab.setObjectName(_fromUtf8("authorsTab"))
|
||||
self.vboxlayout2 = QtGui.QVBoxLayout(self.authorsTab)
|
||||
self.vboxlayout2.setMargin(9)
|
||||
self.vboxlayout2.setSpacing(6)
|
||||
self.vboxlayout2.setObjectName(_fromUtf8("vboxlayout2"))
|
||||
self.authorsBrowser = QtGui.QTextBrowser(self.authorsTab)
|
||||
self.authorsBrowser.setOpenExternalLinks(True)
|
||||
self.authorsBrowser.setObjectName(_fromUtf8("authorsBrowser"))
|
||||
self.vboxlayout2.addWidget(self.authorsBrowser)
|
||||
self.tabWidget.addTab(self.authorsTab, _fromUtf8(""))
|
||||
self.licenseTab = QtGui.QWidget()
|
||||
self.licenseTab.setObjectName(_fromUtf8("licenseTab"))
|
||||
self.vboxlayout3 = QtGui.QVBoxLayout(self.licenseTab)
|
||||
self.vboxlayout3.setMargin(9)
|
||||
self.vboxlayout3.setSpacing(6)
|
||||
self.vboxlayout3.setObjectName(_fromUtf8("vboxlayout3"))
|
||||
self.licenseBrowser = QtGui.QTextBrowser(self.licenseTab)
|
||||
self.licenseBrowser.setObjectName(_fromUtf8("licenseBrowser"))
|
||||
self.vboxlayout3.addWidget(self.licenseBrowser)
|
||||
self.tabWidget.addTab(self.licenseTab, _fromUtf8(""))
|
||||
self.vboxlayout.addWidget(self.tabWidget)
|
||||
self.buttonBox = QtGui.QDialogButtonBox(OGAAboutDialog)
|
||||
self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
|
||||
self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Close)
|
||||
self.buttonBox.setObjectName(_fromUtf8("buttonBox"))
|
||||
self.vboxlayout.addWidget(self.buttonBox)
|
||||
|
||||
self.retranslateUi(OGAAboutDialog)
|
||||
self.tabWidget.setCurrentIndex(0)
|
||||
QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("clicked(QAbstractButton*)")), OGAAboutDialog.closeDialog)
|
||||
QtCore.QMetaObject.connectSlotsByName(OGAAboutDialog)
|
||||
|
||||
def retranslateUi(self, OGAAboutDialog):
|
||||
OGAAboutDialog.setWindowTitle(_translate("OGAAboutDialog", "About OGAgent", None))
|
||||
self.LogoLabel.setText(_translate("OGAAboutDialog", "<html><head/><body><p><img src=\":/images/img/oga.png\"/>OpenGnsys Agent Tools</p></body></html>", None))
|
||||
self.TitleLabel.setText(_translate("OGAAboutDialog", "<html><head/><body><p><span style=\" font-family:\'Sans Serif\'; font-size:9pt; font-weight:600;\">OpenGnsys Agent</span></p></body></html>", None))
|
||||
self.VersionLabel.setText(_translate("OGAAboutDialog", "Version 1.0.0", None))
|
||||
self.aboutBrowser.setHtml(_translate("OGAAboutDialog", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
|
||||
"<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
|
||||
"p, li { white-space: pre-wrap; }\n"
|
||||
"</style></head><body style=\" font-family:\'Verdana\'; font-size:9pt; font-weight:400; font-style:normal;\">\n"
|
||||
"<p style=\"-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:\'Sans Serif\';\"><br /></p>\n"
|
||||
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'Sans Serif\'; font-weight:600;\">(c) 2014, Virtual Cable S.L.U.</span></p>\n"
|
||||
"<p style=\"-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:\'Sans Serif\'; font-style:italic;\"><br /></p>\n"
|
||||
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><a href=\"http://www.udsenterprise.com\"><span style=\" font-family:\'MS Shell Dlg 2\'; font-size:8pt; text-decoration: underline; color:#0000ff;\">http://www.opengnsys.es</span></a></p>\n"
|
||||
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><a href=\"http://www.openuds.org\"><span style=\" font-family:\'MS Shell Dlg 2\'; font-size:8pt; text-decoration: underline; color:#0000ff;\">http://www.udsenterprise.com</span></a></p>\n"
|
||||
"<p style=\"-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:\'Sans Serif\';\"><br /></p></body></html>", None))
|
||||
self.tabWidget.setTabText(self.tabWidget.indexOf(self.aboutTab), _translate("OGAAboutDialog", "&About", None))
|
||||
self.authorsBrowser.setHtml(_translate("OGAAboutDialog", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
|
||||
"<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
|
||||
"p, li { white-space: pre-wrap; }\n"
|
||||
"</style></head><body style=\" font-family:\'Verdana\'; font-size:9pt; font-weight:400; font-style:normal;\">\n"
|
||||
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'Sans Serif\';\">Adolfo Gómez García <agomez@virtualcable.es></span></p></body></html>", None))
|
||||
self.tabWidget.setTabText(self.tabWidget.indexOf(self.authorsTab), _translate("OGAAboutDialog", "A&uthors", None))
|
||||
self.licenseBrowser.setHtml(_translate("OGAAboutDialog", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
|
||||
"<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
|
||||
"p, li { white-space: pre-wrap; }\n"
|
||||
"</style></head><body style=\" font-family:\'Verdana\'; font-size:9pt; font-weight:400; font-style:normal;\">\n"
|
||||
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'MS Shell Dlg 2\'; font-size:8pt;\">Copyright (c) 2014 Virtual Cable S.L.</span></p>\n"
|
||||
"<p style=\"-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:\'MS Shell Dlg 2\'; font-size:8pt;\"><br /></p>\n"
|
||||
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'MS Shell Dlg 2\'; font-size:8pt;\">All rights reserved.</span></p>\n"
|
||||
"<p style=\"-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:\'MS Shell Dlg 2\'; font-size:8pt;\"><br /></p>\n"
|
||||
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'MS Shell Dlg 2\'; font-size:8pt;\">Redistribution and use in source and binary forms, with or without modification,</span></p>\n"
|
||||
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'MS Shell Dlg 2\'; font-size:8pt;\">are permitted provided that the following conditions are met:</span></p>\n"
|
||||
"<p style=\"-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:\'MS Shell Dlg 2\'; font-size:8pt;\"><br /></p>\n"
|
||||
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'MS Shell Dlg 2\'; font-size:8pt;\"> * Redistributions of source code must retain the above copyright notice,</span></p>\n"
|
||||
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'MS Shell Dlg 2\'; font-size:8pt;\"> this list of conditions and the following disclaimer.</span></p>\n"
|
||||
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'MS Shell Dlg 2\'; font-size:8pt;\"> * Redistributions in binary form must reproduce the above copyright notice,</span></p>\n"
|
||||
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'MS Shell Dlg 2\'; font-size:8pt;\"> this list of conditions and the following disclaimer in the documentation</span></p>\n"
|
||||
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'MS Shell Dlg 2\'; font-size:8pt;\"> and/or other materials provided with the distribution.</span></p>\n"
|
||||
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'MS Shell Dlg 2\'; font-size:8pt;\"> * Neither the name of Virtual Cable S.L. nor the names of its contributors</span></p>\n"
|
||||
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'MS Shell Dlg 2\'; font-size:8pt;\"> may be used to endorse or promote products derived from this software</span></p>\n"
|
||||
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'MS Shell Dlg 2\'; font-size:8pt;\"> without specific prior written permission.</span></p>\n"
|
||||
"<p style=\"-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:\'MS Shell Dlg 2\'; font-size:8pt;\"><br /></p>\n"
|
||||
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'MS Shell Dlg 2\'; font-size:8pt;\">THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"</span></p>\n"
|
||||
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'MS Shell Dlg 2\'; font-size:8pt;\">AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE</span></p>\n"
|
||||
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'MS Shell Dlg 2\'; font-size:8pt;\">IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE</span></p>\n"
|
||||
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'MS Shell Dlg 2\'; font-size:8pt;\">DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE</span></p>\n"
|
||||
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'MS Shell Dlg 2\'; font-size:8pt;\">FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL</span></p>\n"
|
||||
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'MS Shell Dlg 2\'; font-size:8pt;\">DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR</span></p>\n"
|
||||
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'MS Shell Dlg 2\'; font-size:8pt;\">SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER</span></p>\n"
|
||||
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'MS Shell Dlg 2\'; font-size:8pt;\">CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,</span></p>\n"
|
||||
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'MS Shell Dlg 2\'; font-size:8pt;\">OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE</span></p>\n"
|
||||
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'MS Shell Dlg 2\'; font-size:8pt;\">OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</span></p>\n"
|
||||
"<p style=\"-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:\'MS Shell Dlg 2\'; font-size:8pt;\"><br /></p></body></html>", None))
|
||||
self.tabWidget.setTabText(self.tabWidget.indexOf(self.licenseTab), _translate("OGAAboutDialog", "&License Agreement", None))
|
||||
|
||||
import OGAgent_rc
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
app = QtGui.QApplication(sys.argv)
|
||||
OGAAboutDialog = QtGui.QDialog()
|
||||
ui = Ui_OGAAboutDialog()
|
||||
ui.setupUi(OGAAboutDialog)
|
||||
OGAAboutDialog.show()
|
||||
sys.exit(app.exec_())
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
[opengnsys]
|
||||
# Listen address & port of REST
|
||||
address=0.0.0.0
|
||||
port=8000
|
||||
|
||||
# This is a comma separated list of paths where to look for modules to load
|
||||
path=test_modules/server
|
||||
|
||||
# Remote OpenGnsys Service
|
||||
remote=https://192.168.2.10/opengnsys/rest
|
||||
|
||||
# Log Level, if ommited, will be set to INFO
|
||||
log=DEBUG
|
||||
|
||||
# Module specific
|
||||
# The sections must match the module name
|
||||
# This section will be passes on activation to module
|
||||
[Sample1]
|
||||
value1=Mariete
|
||||
value2=Yo
|
||||
remote=https://172.27.0.1:9999/rest
|
|
@ -0,0 +1,11 @@
|
|||
[opengnsys]
|
||||
# Log Level, if ommited, will be set to INFO
|
||||
log=DEBUG
|
||||
|
||||
# Module specific
|
||||
# The sections must match the module name
|
||||
# This section will be passes on activation to module
|
||||
[Sample1]
|
||||
value1=Mariete
|
||||
value2=Yo
|
||||
remote=https://172.27.0.1:9999/rest
|
Binary file not shown.
After Width: | Height: | Size: 9.4 KiB |
Binary file not shown.
After Width: | Height: | Size: 43 KiB |
Binary file not shown.
After Width: | Height: | Size: 9.4 KiB |
Binary file not shown.
After Width: | Height: | Size: 3.8 KiB |
|
@ -0,0 +1,27 @@
|
|||
Copyright (c) 2012-2015 Virtual Cable S.L.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1,89 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>OGAMessageDialog</class>
|
||||
<widget class="QDialog" name="OGAMessageDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>339</width>
|
||||
<height>188</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Verdana</family>
|
||||
<pointsize>10</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>UDS Actor</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="verticalLayoutWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>10</y>
|
||||
<width>321</width>
|
||||
<height>171</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QTextBrowser" name="message"/>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>15</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>clicked(QAbstractButton*)</signal>
|
||||
<receiver>OGAMessageDialog</receiver>
|
||||
<slot>closeDialog()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>203</x>
|
||||
<y>161</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>337</x>
|
||||
<y>125</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
<slots>
|
||||
<slot>closeDialog()</slot>
|
||||
</slots>
|
||||
</ui>
|
|
@ -0,0 +1,69 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Form implementation generated from reading ui file 'message-dialog.ui'
|
||||
#
|
||||
# Created by: PyQt4 UI code generator 4.11.4
|
||||
#
|
||||
# WARNING! All changes made in this file will be lost!
|
||||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
|
||||
try:
|
||||
_fromUtf8 = QtCore.QString.fromUtf8
|
||||
except AttributeError:
|
||||
def _fromUtf8(s):
|
||||
return s
|
||||
|
||||
try:
|
||||
_encoding = QtGui.QApplication.UnicodeUTF8
|
||||
def _translate(context, text, disambig):
|
||||
return QtGui.QApplication.translate(context, text, disambig, _encoding)
|
||||
except AttributeError:
|
||||
def _translate(context, text, disambig):
|
||||
return QtGui.QApplication.translate(context, text, disambig)
|
||||
|
||||
class Ui_OGAMessageDialog(object):
|
||||
def setupUi(self, OGAMessageDialog):
|
||||
OGAMessageDialog.setObjectName(_fromUtf8("OGAMessageDialog"))
|
||||
OGAMessageDialog.resize(339, 188)
|
||||
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(OGAMessageDialog.sizePolicy().hasHeightForWidth())
|
||||
OGAMessageDialog.setSizePolicy(sizePolicy)
|
||||
font = QtGui.QFont()
|
||||
font.setFamily(_fromUtf8("Verdana"))
|
||||
font.setPointSize(10)
|
||||
OGAMessageDialog.setFont(font)
|
||||
self.verticalLayoutWidget = QtGui.QWidget(OGAMessageDialog)
|
||||
self.verticalLayoutWidget.setGeometry(QtCore.QRect(10, 10, 321, 171))
|
||||
self.verticalLayoutWidget.setObjectName(_fromUtf8("verticalLayoutWidget"))
|
||||
self.verticalLayout = QtGui.QVBoxLayout(self.verticalLayoutWidget)
|
||||
self.verticalLayout.setObjectName(_fromUtf8("verticalLayout"))
|
||||
self.message = QtGui.QTextBrowser(self.verticalLayoutWidget)
|
||||
self.message.setObjectName(_fromUtf8("message"))
|
||||
self.verticalLayout.addWidget(self.message)
|
||||
spacerItem = QtGui.QSpacerItem(20, 15, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Fixed)
|
||||
self.verticalLayout.addItem(spacerItem)
|
||||
self.buttonBox = QtGui.QDialogButtonBox(self.verticalLayoutWidget)
|
||||
self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Ok)
|
||||
self.buttonBox.setObjectName(_fromUtf8("buttonBox"))
|
||||
self.verticalLayout.addWidget(self.buttonBox)
|
||||
|
||||
self.retranslateUi(OGAMessageDialog)
|
||||
QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("clicked(QAbstractButton*)")), OGAMessageDialog.closeDialog)
|
||||
QtCore.QMetaObject.connectSlotsByName(OGAMessageDialog)
|
||||
|
||||
def retranslateUi(self, OGAMessageDialog):
|
||||
OGAMessageDialog.setWindowTitle(_translate("OGAMessageDialog", "UDS Actor", None))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
app = QtGui.QApplication(sys.argv)
|
||||
OGAMessageDialog = QtGui.QDialog()
|
||||
ui = Ui_OGAMessageDialog()
|
||||
ui.setupUi(OGAMessageDialog)
|
||||
OGAMessageDialog.show()
|
||||
sys.exit(app.exec_())
|
||||
|
|
@ -0,0 +1,160 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 201 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
'''
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
|
||||
# pylint: disable-msg=E1101,W0703
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import requests
|
||||
import logging
|
||||
import json
|
||||
import warnings
|
||||
|
||||
from .log import logger
|
||||
|
||||
from .utils import exceptionToMessage
|
||||
|
||||
VERIFY_CERT = False
|
||||
|
||||
|
||||
class RESTError(Exception):
|
||||
ERRCODE = 0
|
||||
|
||||
|
||||
class ConnectionError(RESTError):
|
||||
ERRCODE = -1
|
||||
|
||||
|
||||
# Disable warnings log messages
|
||||
try:
|
||||
import urllib3 # @UnusedImport
|
||||
except Exception:
|
||||
from requests.packages import urllib3 # @Reimport
|
||||
|
||||
try:
|
||||
urllib3.disable_warnings() # @UndefinedVariable
|
||||
warnings.simplefilter("ignore")
|
||||
except Exception:
|
||||
pass # In fact, isn't too important, but wil log warns to logging file
|
||||
|
||||
class REST(object):
|
||||
'''
|
||||
Simple interface to remote REST apis.
|
||||
The constructor expects the "base url" as parameter, that is, the url that will be common on all REST requests
|
||||
Remember that this is a helper for "easy of use". You can provide your owns using requests lib for example.
|
||||
Examples:
|
||||
v = REST('https://example.com/rest/v1/') (Can omit trailing / if desired)
|
||||
v.sendMessage('hello?param1=1¶m2=2')
|
||||
This will generate a GET message to https://example.com/rest/v1/hello?param1=1¶m2=2, and return the deserialized JSON result or an exception
|
||||
v.sendMessage('hello?param1=1¶m2=2', {'name': 'mario' })
|
||||
This will generate a POST message to https://example.com/rest/v1/hello?param1=1¶m2=2, with json encoded body {'name': 'mario' }, and also returns
|
||||
the deserialized JSON result or raises an exception in case of error
|
||||
'''
|
||||
def __init__(self, url):
|
||||
'''
|
||||
Initializes the REST helper
|
||||
url is the full url of the REST API Base, as for example "https://example.com/rest/v1".
|
||||
@param url The url of the REST API Base. The trailing '/' can be included or omitted, as desired.
|
||||
'''
|
||||
self.endpoint = url
|
||||
|
||||
if self.endpoint[-1] != '/':
|
||||
self.endpoint += '/'
|
||||
|
||||
# Some OSs ships very old python requests lib implementations, workaround them...
|
||||
try:
|
||||
self.newerRequestLib = requests.__version__.split('.')[0] >= '1'
|
||||
except Exception:
|
||||
self.newerRequestLib = False # I no version, guess this must be an old requests
|
||||
|
||||
# Disable logging requests messages except for errors, ...
|
||||
logging.getLogger("requests").setLevel(logging.CRITICAL)
|
||||
# Tries to disable all warnings
|
||||
try:
|
||||
warnings.simplefilter("ignore") # Disables all warnings
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def _getUrl(self, method):
|
||||
'''
|
||||
Internal method
|
||||
Composes the URL based on "method"
|
||||
@param method: Method to append to base url for composition
|
||||
'''
|
||||
url = self.endpoint + method
|
||||
|
||||
return url
|
||||
|
||||
def _request(self, url, data=None):
|
||||
'''
|
||||
Launches the request
|
||||
@param url: The url to obtain
|
||||
@param data: if None, the request will be sent as a GET request. If != None, the request will be sent as a POST, with data serialized as JSON in the body.
|
||||
'''
|
||||
try:
|
||||
if data is None:
|
||||
logger.debug('Requesting using GET (no data provided) {}'.format(url))
|
||||
# Old requests version does not support verify, but they do not checks ssl certificate by default
|
||||
if self.newerRequestLib:
|
||||
r = requests.get(url, verify=VERIFY_CERT)
|
||||
else:
|
||||
r = requests.get(url)
|
||||
else: # POST
|
||||
logger.debug('Requesting using POST {}, data: {}'.format(url, data))
|
||||
if self.newerRequestLib:
|
||||
r = requests.post(url, data=data, headers={'content-type': 'application/json'}, verify=VERIFY_CERT)
|
||||
else:
|
||||
r = requests.post(url, data=data, headers={'content-type': 'application/json'})
|
||||
|
||||
r = json.loads(r.content) # Using instead of r.json() to make compatible with oooold rquests lib versions
|
||||
except requests.exceptions.RequestException as e:
|
||||
raise ConnectionError(e)
|
||||
except Exception as e:
|
||||
raise ConnectionError(exceptionToMessage(e))
|
||||
|
||||
return r
|
||||
|
||||
def sendMessage(self, msg, data=None, processData=True):
|
||||
'''
|
||||
Sends a message to remote REST server
|
||||
@param data: if None or omitted, message will be a GET, else it will send a POST
|
||||
@param processData: if True, data will be serialized to json before sending, else, data will be sent as "raw"
|
||||
'''
|
||||
logger.debug('Invoking post message {} with data {}'.format(msg, data))
|
||||
|
||||
if processData and data is not None:
|
||||
data = json.dumps(data)
|
||||
|
||||
url = self._getUrl(msg)
|
||||
logger.debug('Requesting {}'.format(url))
|
||||
|
||||
return self._request(url, data)
|
|
@ -0,0 +1,57 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2014 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
'''
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# On centos, old six release does not includes byte2int, nor six.PY2
|
||||
import six
|
||||
|
||||
import modules
|
||||
from RESTApi import REST, RESTError
|
||||
|
||||
VERSION = '1.0.0'
|
||||
|
||||
__title__ = 'OpenGnSys Agent'
|
||||
__version__ = VERSION
|
||||
__build__ = 0x010750
|
||||
__author__ = 'Adolfo Gómez'
|
||||
__license__ = "BSD 3-clause"
|
||||
__copyright__ = "Copyright VirtualCable S.L.U."
|
||||
|
||||
|
||||
if not hasattr(six, 'byte2int'):
|
||||
if six.PY3:
|
||||
import operator
|
||||
six.byte2int = operator.itemgetter(0)
|
||||
else:
|
||||
def _byte2int(bs):
|
||||
return ord(bs[0])
|
||||
six.byte2int = _byte2int
|
|
@ -0,0 +1,101 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2014 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
'''
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
|
||||
from tempfile import gettempdir
|
||||
from os.path import exists, join
|
||||
|
||||
CERTFILE = 'OGAgent.pem'
|
||||
|
||||
|
||||
def createSelfSignedCert(force=False):
|
||||
|
||||
certFile = join(gettempdir(), CERTFILE)
|
||||
|
||||
if exists(certFile) and not force:
|
||||
return certFile
|
||||
|
||||
certData = '''-----BEGIN PRIVATE KEY-----
|
||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCb50K3mIznNklz
|
||||
yVAD7xSQOSJQ6+NPXj7U9/4zLZ+TvmbQ7RqUUsxbfxHbeRnoYTWV2nKk4+tHqmvz
|
||||
ujLSS/loFhTSMqtrLn7rowSYJoQhKOUkAiQlWkqCfItWgL5pJopDpNHFul9Rn3ds
|
||||
PMWQTiGeUNR4Y3RnBhr1Q1BsqAzf4m6zFUmgLPPmVLdF4uJ3Tuz8TSy2gWLs5aSr
|
||||
5do4WamwUfYjRSVMJECmwjUM4rQ8SQgg0sHBeBuDUGNBvBQFac1G7qUcMReeu8Zr
|
||||
DUtMsXma/l4rA8NB5CRmTrQbTBF4l+jb2BDFebDqDUK1Oqs9X35yOQfDOAFYHiix
|
||||
PX0IsXOZAgMBAAECggEBAJi3000RrIUZUp6Ph0gzPMuCjDEEwWiQA7CPNX1gpb8O
|
||||
dp0WhkDhUroWIaICYPSXtOwUTtVjRqivMoxPy1Thg3EIoGC/rdeSdlXRHMEGicwJ
|
||||
yVyalFnatr5Xzg5wkxVh4XMd0zeDt7e3JD7s0QLo5lm1CEzd77qz6lhzFic5/1KX
|
||||
bzdULtTlq60dazg2hEbcS4OmM1UMCtRVDAsOIUIZPL0M9j1C1d1iEdYnh2xshKeG
|
||||
/GOfo95xsgdMlGjtv3hUT5ryKVoEsu+36rGb4VfhPfUvvoVbRx5QZpW+QvxaYh5E
|
||||
Fi0JEROozFwG31Y++8El7J3yQko8cFBa1lYYUwwpNAECgYEAykT+GiM2YxJ4uVF1
|
||||
OoKiE9BD53i0IG5j87lGPnWqzEwYBwnqjEKDTou+uzMGz3MDV56UEFNho7wUWh28
|
||||
LpEkjJB9QgbsugjxIBr4JoL/rYk036e/6+U8I95lvYWrzb+rBMIkRDYI7kbQD/mQ
|
||||
piYUpuCkTymNAu2RisK6bBzJslkCgYEAxVE23OQvkCeOV8hJNPZGpJ1mDS+TiOow
|
||||
oOScMZmZpail181eYbAfMsCr7ri812lSj98NvA2GNVLpddil6LtS1cQ5p36lFBtV
|
||||
xQUMZiFz4qVbEak+izL+vPaev/mXXsOcibAIQ+qI/0txFpNhJjpaaSy6vRCBYFmc
|
||||
8pgSoBnBI0ECgYAUKCn2atnpp5aWSTLYgNosBU4vDA1PShD14dnJMaqyr0aZtPhF
|
||||
v/8b3btFJoGgPMLxgWEZ+2U4ju6sSFhPf7FXvLJu2QfQRkHZRDbEh7t5DLpTK4Fp
|
||||
va9vl6Ml7uM/HsGpOLuqfIQJUs87OFCc7iCSvMJDDU37I7ekT2GKkpfbCQKBgBrE
|
||||
0NeY0WcSJrp7/oqD2sOcYurpCG/rrZs2SIZmGzUhMxaa0vIXzbO59dlWELB8pmnE
|
||||
Tf20K//x9qA5OxDe0PcVPukdQlH+/1zSOYNliG44FqnHtyd1TJ/gKVtMBiAiE4uO
|
||||
aSClod5Yosf4SJbCFd/s5Iyfv52NqsAyp1w3Aj/BAoGAVCnEiGUfyHlIR+UH4zZW
|
||||
GXJMeqdZLfcEIszMxLePkml4gUQhoq9oIs/Kw+L1DDxUwzkXN4BNTlFbOSu9gzK1
|
||||
dhuIUGfS6RPL88U+ivC3A0y2jT43oUMqe3hiRt360UQ1GXzp2dMnR9odSRB1wHoO
|
||||
IOjEBZ8341/c9ZHc5PCGAG8=
|
||||
-----END PRIVATE KEY-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIID7zCCAtegAwIBAgIJAIrEIthCfxUCMA0GCSqGSIb3DQEBCwUAMIGNMQswCQYD
|
||||
VQQGEwJFUzEPMA0GA1UECAwGTWFkcmlkMREwDwYDVQQHDAhBbGNvcmNvbjEMMAoG
|
||||
A1UECgwDVURTMQ4wDAYDVQQLDAVBY3RvcjESMBAGA1UEAwwJVURTIEFjdG9yMSgw
|
||||
JgYJKoZIhvcNAQkBFhlzdXBwb3J0QHVkc2VudGVycHJpc2UuY29tMB4XDTE0MTAy
|
||||
NjIzNDEyNFoXDTI0MTAyMzIzNDEyNFowgY0xCzAJBgNVBAYTAkVTMQ8wDQYDVQQI
|
||||
DAZNYWRyaWQxETAPBgNVBAcMCEFsY29yY29uMQwwCgYDVQQKDANVRFMxDjAMBgNV
|
||||
BAsMBUFjdG9yMRIwEAYDVQQDDAlVRFMgQWN0b3IxKDAmBgkqhkiG9w0BCQEWGXN1
|
||||
cHBvcnRAdWRzZW50ZXJwcmlzZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
|
||||
ggEKAoIBAQCb50K3mIznNklzyVAD7xSQOSJQ6+NPXj7U9/4zLZ+TvmbQ7RqUUsxb
|
||||
fxHbeRnoYTWV2nKk4+tHqmvzujLSS/loFhTSMqtrLn7rowSYJoQhKOUkAiQlWkqC
|
||||
fItWgL5pJopDpNHFul9Rn3dsPMWQTiGeUNR4Y3RnBhr1Q1BsqAzf4m6zFUmgLPPm
|
||||
VLdF4uJ3Tuz8TSy2gWLs5aSr5do4WamwUfYjRSVMJECmwjUM4rQ8SQgg0sHBeBuD
|
||||
UGNBvBQFac1G7qUcMReeu8ZrDUtMsXma/l4rA8NB5CRmTrQbTBF4l+jb2BDFebDq
|
||||
DUK1Oqs9X35yOQfDOAFYHiixPX0IsXOZAgMBAAGjUDBOMB0GA1UdDgQWBBRShS90
|
||||
5lJTNvYPIEqP3GxWwG5iiDAfBgNVHSMEGDAWgBRShS905lJTNvYPIEqP3GxWwG5i
|
||||
iDAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAU0Sp4gXhQmRVzq+7+
|
||||
vRFUkQuPj4Ga/d9r5Wrbg3hck3+5pwe9/7APoq0P/M0DBhQpiJKjrD6ydUevC+Y/
|
||||
43ZOJPhMlNw0o6TdQxOkX6FDwQanLLs7sfvJvqtVzYn3nuRFKT3dvl7Zg44QMw2M
|
||||
ay42q59fAcpB4LaDx/i7gOYSS5eca3lYW7j7YSr/+ozXK2KlgUkuCUHN95lOq+dF
|
||||
trmV9mjzM4CNPZqKSE7kpHRywgrXGPCO000NvEGSYf82AtgRSFKiU8NWLQSEPdcB
|
||||
k//2dsQZw2cRZ8DrC2B6Tb3M+3+CA6wVyqfqZh1SZva3LfGvq/C+u+ItguzPqNpI
|
||||
xtvM
|
||||
-----END CERTIFICATE-----'''
|
||||
with open(certFile, "wt") as f:
|
||||
f.write(certData)
|
||||
|
||||
return certFile
|
|
@ -0,0 +1,59 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2014 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
'''
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
# pylint: disable=unused-wildcard-import, wildcard-import
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from ConfigParser import SafeConfigParser
|
||||
from .log import logger
|
||||
|
||||
config = None
|
||||
|
||||
def readConfig(client=False):
|
||||
'''
|
||||
Reads configuration file
|
||||
If client is False, will read ogagent.cfg as configuration
|
||||
If client is True, will read ogclient.cfg as configuration
|
||||
|
||||
This is this way so we can protect ogagent.cfg against reading for non admin users on all platforms.
|
||||
'''
|
||||
cfg = SafeConfigParser()
|
||||
if client is True:
|
||||
fname = 'ogclient.cfg'
|
||||
else:
|
||||
fname = 'ogagent.cfg'
|
||||
|
||||
if len(cfg.read('cfg/{}'.format(fname))) == 0:
|
||||
# No configuration found
|
||||
return None
|
||||
|
||||
return cfg
|
||||
|
|
@ -0,0 +1,150 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2015 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
'''
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
# pylint: disable=unused-wildcard-import,wildcard-import
|
||||
from __future__ import unicode_literals, print_function
|
||||
|
||||
# Pydev can't parse "six.moves.xxxx" because it is loaded lazy
|
||||
import six
|
||||
from six.moves.socketserver import ThreadingMixIn # @UnresolvedImport
|
||||
from six.moves.BaseHTTPServer import BaseHTTPRequestHandler # @UnresolvedImport
|
||||
from six.moves.BaseHTTPServer import HTTPServer # @UnresolvedImport
|
||||
from six.moves.urllib.parse import unquote # @UnresolvedImport
|
||||
|
||||
import json
|
||||
import threading
|
||||
import ssl
|
||||
|
||||
from .utils import exceptionToMessage
|
||||
from .certs import createSelfSignedCert
|
||||
from .log import logger
|
||||
|
||||
class HTTPServerHandler(BaseHTTPRequestHandler):
|
||||
service = None
|
||||
protocol_version = 'HTTP/1.0'
|
||||
server_version = 'OpenGnsys Agent Server'
|
||||
sys_version = ''
|
||||
|
||||
def sendJsonError(self, code, message):
|
||||
self.send_response(code)
|
||||
self.send_header('Content-type', 'application/json')
|
||||
self.end_headers()
|
||||
self.wfile.write(json.dumps({'error': message}))
|
||||
return
|
||||
|
||||
def sendJsonResponse(self, data):
|
||||
self.send_response(200)
|
||||
data = json.dumps(data)
|
||||
self.send_header('Content-type', 'application/json')
|
||||
self.send_header('Content-Length', len(data))
|
||||
self.end_headers()
|
||||
# Send the html message
|
||||
self.wfile.write(data)
|
||||
|
||||
|
||||
# parseURL
|
||||
def parseUrl(self):
|
||||
# Very simple path & params splitter
|
||||
path = self.path.split('?')[0][1:].split('/')
|
||||
|
||||
try:
|
||||
params = dict((v[0], unquote(v[1])) for v in (v.split('=') for v in self.path.split('?')[1].split('&')))
|
||||
except Exception:
|
||||
params = {}
|
||||
|
||||
for v in self.service.modules:
|
||||
if v.name == path[0]: # Case Sensitive!!!!
|
||||
return (v, path[1:], params)
|
||||
|
||||
return (None, path, params)
|
||||
|
||||
def notifyMessage(self, module, path, getParams, postParams):
|
||||
'''
|
||||
Locates witch module will process the message based on path (first folder on url path)
|
||||
'''
|
||||
try:
|
||||
data = module.processServerMessage(path, getParams, postParams)
|
||||
self.sendJsonResponse(data)
|
||||
except Exception as e:
|
||||
logger.exception()
|
||||
self.sendJsonError(500, exceptionToMessage(e))
|
||||
|
||||
def do_GET(self):
|
||||
module, path, params = self.parseUrl()
|
||||
|
||||
self.notifyMessage(module, path, params, None)
|
||||
|
||||
def do_POST(self):
|
||||
module, path, getParams = self.parseUrl()
|
||||
|
||||
# Tries to get json content
|
||||
try:
|
||||
length = int(self.headers.getheader('content-length'))
|
||||
content = self.rfile.read(length)
|
||||
logger.debug('length: {}, content >>{}<<'.format(length, content))
|
||||
postParams = json.loads(content)
|
||||
except Exception as e:
|
||||
self.sendJsonError(500, exceptionToMessage(e))
|
||||
|
||||
self.notifyMessage(module, path, getParams, postParams)
|
||||
|
||||
|
||||
def log_error(self, fmt, *args):
|
||||
logger.error('HTTP ' + fmt % args)
|
||||
|
||||
def log_message(self, fmt, *args):
|
||||
logger.info('HTTP ' + fmt % args)
|
||||
|
||||
|
||||
class HTTPThreadingServer(ThreadingMixIn, HTTPServer):
|
||||
pass
|
||||
|
||||
class HTTPServerThread(threading.Thread):
|
||||
def __init__(self, address, service):
|
||||
super(self.__class__, self).__init__()
|
||||
|
||||
HTTPServerHandler.service = service # Keep tracking of service so we can intercact with it
|
||||
|
||||
self.certFile = createSelfSignedCert()
|
||||
self.server = HTTPThreadingServer(address, HTTPServerHandler)
|
||||
self.server.socket = ssl.wrap_socket(self.server.socket, certfile=self.certFile, server_side=True)
|
||||
|
||||
logger.debug('Initialized HTTPS Server thread on {}'.format(address))
|
||||
|
||||
def getServerUrl(self):
|
||||
return 'https://{}:{}/'.format(self.server.server_address[0], self.server.server_address[1])
|
||||
|
||||
def stop(self):
|
||||
self.server.shutdown()
|
||||
|
||||
def run(self):
|
||||
self.server.serve_forever()
|
||||
|
||||
|
|
@ -0,0 +1,416 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2014 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
'''
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import socket
|
||||
import threading
|
||||
import six
|
||||
import traceback
|
||||
import json
|
||||
|
||||
from opengnsys.utils import toUnicode
|
||||
from opengnsys.log import logger
|
||||
|
||||
# The IPC Server will wait for connections from clients
|
||||
# Clients will open socket, and wait for data from server
|
||||
# The messages sent (from server) will be the following (subject to future changes):
|
||||
# Message_id Data Action
|
||||
# ------------ -------- --------------------------
|
||||
# MSG_LOGOFF None Logout user from session
|
||||
# MSG_MESSAGE message,level Display a message with level (INFO, WARN, ERROR, FATAL) # TODO: Include level, right now only has message
|
||||
# MSG_SCRIPT python script Execute an specific python script INSIDE CLIENT environment (this messages is not sent right now)
|
||||
# The messages received (sent from client) will be the following:
|
||||
# Message_id Data Action
|
||||
# ------------ -------- --------------------------
|
||||
# REQ_LOGOUT Logout user from session
|
||||
# REQ_INFORMATION None Request information from ipc server (maybe configuration parameters in a near future)
|
||||
# REQ_LOGIN python script Execute an specific python script INSIDE CLIENT environment (this messages is not sent right now)
|
||||
#
|
||||
# All messages are in the form:
|
||||
# BYTE
|
||||
# 0 1-2 3 4 ...
|
||||
# MSG_ID DATA_LENGTH (little endian) Data (can be 0 length)
|
||||
# With a previos "MAGIC" header in fron of each message
|
||||
|
||||
# Client messages
|
||||
MSG_LOGOFF = 0xA1 # Request log off from an user
|
||||
MSG_MESSAGE = 0xB2
|
||||
MSG_SCRIPT = 0xC3
|
||||
|
||||
# Request messages
|
||||
REQ_MESSAGE = 0xD4
|
||||
REQ_LOGIN = 0xE5
|
||||
REQ_LOGOUT = 0xF6
|
||||
|
||||
# Reverse msgs dict for debugging
|
||||
REV_DICT = {
|
||||
MSG_LOGOFF: 'MSG_LOGOFF',
|
||||
MSG_MESSAGE: 'MSG_MESSAGE',
|
||||
MSG_SCRIPT: 'MSG_SCRIPT',
|
||||
REQ_LOGIN: 'REQ_LOGIN',
|
||||
REQ_LOGOUT: 'REQ_LOGOUT',
|
||||
REQ_MESSAGE: 'REQ_MESSAGE'
|
||||
}
|
||||
|
||||
MAGIC = b'\x4F\x47\x41\x00' # OGA in hexa with a padded 0 to the right
|
||||
|
||||
|
||||
# States for client processor
|
||||
ST_SECOND_BYTE = 0x01
|
||||
ST_RECEIVING = 0x02
|
||||
ST_PROCESS_MESSAGE = 0x02
|
||||
|
||||
|
||||
class ClientProcessor(threading.Thread):
|
||||
def __init__(self, parent, clientSocket):
|
||||
super(self.__class__, self).__init__()
|
||||
self.parent = parent
|
||||
self.clientSocket = clientSocket
|
||||
self.running = False
|
||||
self.messages = six.moves.queue.Queue(32) # @UndefinedVariable
|
||||
|
||||
def stop(self):
|
||||
logger.debug('Stoping client processor')
|
||||
self.running = False
|
||||
|
||||
def processRequest(self, msg, data):
|
||||
logger.debug('Got Client message {}={}'.format(msg, REV_DICT.get(msg)))
|
||||
if self.parent.clientMessageProcessor is not None:
|
||||
self.parent.clientMessageProcessor(msg, data)
|
||||
|
||||
def run(self):
|
||||
self.running = True
|
||||
self.clientSocket.setblocking(0)
|
||||
|
||||
state = None
|
||||
recv_msg = None
|
||||
recv_data = None
|
||||
while self.running:
|
||||
try:
|
||||
counter = 1024
|
||||
while counter > 0: # So we process at least the incoming queue every XX bytes readed
|
||||
counter -= 1
|
||||
b = self.clientSocket.recv(1)
|
||||
if b == b'':
|
||||
# Client disconnected
|
||||
self.running = False
|
||||
break
|
||||
buf = six.byte2int(b) # Empty buffer, this is set as non-blocking
|
||||
if state is None:
|
||||
if buf in (REQ_MESSAGE, REQ_LOGIN, REQ_LOGOUT):
|
||||
logger.debug('State set to {}'.format(buf))
|
||||
state = buf
|
||||
recv_msg = buf
|
||||
continue # Get next byte
|
||||
else:
|
||||
logger.debug('Got unexpected data {}'.format(buf))
|
||||
elif state in (REQ_MESSAGE, REQ_LOGIN, REQ_LOGOUT):
|
||||
logger.debug('First length byte is {}'.format(buf))
|
||||
msg_len = buf
|
||||
state = ST_SECOND_BYTE
|
||||
continue
|
||||
elif state == ST_SECOND_BYTE:
|
||||
msg_len += buf << 8
|
||||
logger.debug('Second length byte is {}, len is {}'.format(buf, msg_len))
|
||||
if msg_len == 0:
|
||||
self.processRequest(recv_msg, None)
|
||||
state = None
|
||||
break
|
||||
state = ST_RECEIVING
|
||||
recv_data = b''
|
||||
continue
|
||||
elif state == ST_RECEIVING:
|
||||
recv_data += six.int2byte(buf)
|
||||
msg_len -= 1
|
||||
if msg_len == 0:
|
||||
self.processRequest(recv_msg, recv_data)
|
||||
recv_data = None
|
||||
state = None
|
||||
break
|
||||
else:
|
||||
logger.debug('Got invalid message from request: {}, state: {}'.format(buf, state))
|
||||
except socket.error as e:
|
||||
# If no data is present, no problem at all, pass to check messages
|
||||
pass
|
||||
except Exception as e:
|
||||
tb = traceback.format_exc()
|
||||
logger.error('Error: {}, trace: {}'.format(e, tb))
|
||||
|
||||
if self.running is False:
|
||||
break
|
||||
|
||||
try:
|
||||
msg = self.messages.get(block=True, timeout=1)
|
||||
except six.moves.queue.Empty: # No message got in time @UndefinedVariable
|
||||
continue
|
||||
|
||||
logger.debug('Got message {}={}'.format(msg, REV_DICT.get(msg[0])))
|
||||
|
||||
try:
|
||||
m = msg[1] if msg[1] is not None else b''
|
||||
l = len(m)
|
||||
data = MAGIC + six.int2byte(msg[0]) + six.int2byte(l & 0xFF) + six.int2byte(l >> 8) + m
|
||||
try:
|
||||
self.clientSocket.sendall(data)
|
||||
except socket.error as e:
|
||||
# Send data error
|
||||
logger.debug('Socket connection is no more available: {}'.format(e.args))
|
||||
self.running = False
|
||||
except Exception as e:
|
||||
logger.error('Invalid message in queue: {}'.format(e))
|
||||
|
||||
logger.debug('Client processor stopped')
|
||||
try:
|
||||
self.clientSocket.close()
|
||||
except Exception:
|
||||
pass # If can't close, nothing happens, just end thread
|
||||
|
||||
|
||||
class ServerIPC(threading.Thread):
|
||||
|
||||
def __init__(self, listenPort, clientMessageProcessor=None):
|
||||
super(self.__class__, self).__init__()
|
||||
self.port = listenPort
|
||||
self.running = False
|
||||
self.serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.serverSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
self.threads = []
|
||||
self.clientMessageProcessor = clientMessageProcessor
|
||||
|
||||
def stop(self):
|
||||
logger.debug('Stopping Server IPC')
|
||||
self.running = False
|
||||
for t in self.threads:
|
||||
t.stop()
|
||||
socket.socket(socket.AF_INET, socket.SOCK_STREAM).connect(('localhost', self.port))
|
||||
self.serverSocket.close()
|
||||
|
||||
for t in self.threads:
|
||||
t.join()
|
||||
|
||||
def sendMessage(self, msgId, msgData):
|
||||
'''
|
||||
Notify message to all listening threads
|
||||
'''
|
||||
logger.debug('Sending message {}({}),{} to all clients'.format(msgId, REV_DICT.get(msgId), msgData))
|
||||
|
||||
# Convert to bytes so length is correctly calculated
|
||||
if isinstance(msgData, six.text_type):
|
||||
msgData = msgData.encode('utf8')
|
||||
|
||||
for t in self.threads:
|
||||
if t.isAlive():
|
||||
logger.debug('Sending to {}'.format(t))
|
||||
t.messages.put((msgId, msgData))
|
||||
|
||||
def sendLoggofMessage(self):
|
||||
self.sendMessage(MSG_LOGOFF, '')
|
||||
|
||||
def sendMessageMessage(self, message):
|
||||
self.sendMessage(MSG_MESSAGE, message)
|
||||
|
||||
def sendScriptMessage(self, script):
|
||||
self.sendMessage(MSG_SCRIPT, script)
|
||||
|
||||
def cleanupFinishedThreads(self):
|
||||
'''
|
||||
Cleans up current threads list
|
||||
'''
|
||||
aliveThreads = []
|
||||
for t in self.threads:
|
||||
if t.isAlive():
|
||||
logger.debug('Thread {} is alive'.format(t))
|
||||
aliveThreads.append(t)
|
||||
self.threads[:] = aliveThreads
|
||||
|
||||
def run(self):
|
||||
self.running = True
|
||||
|
||||
self.serverSocket.bind(('localhost', self.port))
|
||||
self.serverSocket.setblocking(1)
|
||||
self.serverSocket.listen(4)
|
||||
|
||||
while True:
|
||||
try:
|
||||
(clientSocket, address) = self.serverSocket.accept()
|
||||
# Stop processing if thread is mean to stop
|
||||
if self.running is False:
|
||||
break
|
||||
logger.debug('Got connection from {}'.format(address))
|
||||
|
||||
self.cleanupFinishedThreads() # House keeping
|
||||
|
||||
logger.debug('Starting new thread, current: {}'.format(self.threads))
|
||||
t = ClientProcessor(self, clientSocket)
|
||||
self.threads.append(t)
|
||||
t.start()
|
||||
except Exception as e:
|
||||
logger.error('Got an exception on Server ipc thread: {}'.format(e))
|
||||
|
||||
|
||||
class ClientIPC(threading.Thread):
|
||||
def __init__(self, listenPort):
|
||||
super(ClientIPC, self).__init__()
|
||||
self.port = listenPort
|
||||
self.running = False
|
||||
self.clientSocket = None
|
||||
self.messages = six.moves.queue.Queue(32) # @UndefinedVariable
|
||||
|
||||
self.connect()
|
||||
|
||||
def stop(self):
|
||||
self.running = False
|
||||
|
||||
def getMessage(self):
|
||||
while self.running:
|
||||
try:
|
||||
return self.messages.get(timeout=1)
|
||||
except six.moves.queue.Empty: # @UndefinedVariable
|
||||
continue
|
||||
|
||||
return None
|
||||
|
||||
def sendRequestMessage(self, msg, data=None):
|
||||
logger.debug('Sending request for msg: {}({}), {}'.format(msg, REV_DICT.get(msg), data))
|
||||
if data is None:
|
||||
data = b''
|
||||
|
||||
if isinstance(data, six.text_type): # Convert to bytes if necessary
|
||||
data = data.encode('utf-8')
|
||||
|
||||
l = len(data)
|
||||
msg = six.int2byte(msg) + six.int2byte(l & 0xFF) + six.int2byte(l >> 8) + data
|
||||
self.clientSocket.sendall(msg)
|
||||
|
||||
def sendLogin(self, username):
|
||||
self.sendRequestMessage(REQ_LOGIN, username)
|
||||
|
||||
def sendLogout(self, username):
|
||||
self.sendRequestMessage(REQ_LOGOUT, username)
|
||||
|
||||
def sendMessage(self, module, message, data=None):
|
||||
'''
|
||||
Sends a message "message" with data (data will be encoded as json, so ensure that it is serializable)
|
||||
@param module: Module that will receive this message
|
||||
@param message: Message to send. This message is "customized", and understand by modules
|
||||
@param data: Data to be send as message companion
|
||||
'''
|
||||
msg = '\0'.join((module, message, json.dumps(data)))
|
||||
self.sendRequestMessage(REQ_MESSAGE, msg)
|
||||
|
||||
def messageReceived(self):
|
||||
'''
|
||||
Override this method to automatically get notified on new message
|
||||
received. Message is at self.messages queue
|
||||
'''
|
||||
pass
|
||||
|
||||
def receiveBytes(self, number):
|
||||
msg = b''
|
||||
while self.running and len(msg) < number:
|
||||
try:
|
||||
buf = self.clientSocket.recv(number - len(msg))
|
||||
if buf == b'':
|
||||
logger.debug('Buf {}, msg {}({})'.format(buf, msg, REV_DICT.get(msg)))
|
||||
self.running = False
|
||||
break
|
||||
msg += buf
|
||||
except socket.timeout:
|
||||
pass
|
||||
|
||||
if self.running is False:
|
||||
logger.debug('Not running, returning None')
|
||||
return None
|
||||
return msg
|
||||
|
||||
def connect(self):
|
||||
self.clientSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.clientSocket.connect(('localhost', self.port))
|
||||
self.clientSocket.settimeout(2) # Static, custom socket timeout of 2 seconds for local connection (no network)
|
||||
|
||||
def run(self):
|
||||
self.running = True
|
||||
|
||||
while self.running:
|
||||
try:
|
||||
msg = b''
|
||||
# We look for magic message header
|
||||
while self.running: # Wait for MAGIC
|
||||
try:
|
||||
buf = self.clientSocket.recv(len(MAGIC) - len(msg))
|
||||
if buf == b'':
|
||||
self.running = False
|
||||
break
|
||||
msg += buf
|
||||
if len(msg) != len(MAGIC):
|
||||
continue # Do not have message
|
||||
if msg != MAGIC: # Skip first byte an continue searchong
|
||||
msg = msg[1:]
|
||||
continue
|
||||
break
|
||||
except socket.timeout: # Timeout is here so we can get stop thread
|
||||
continue
|
||||
|
||||
if self.running is False:
|
||||
break
|
||||
|
||||
# Now we get message basic data (msg + datalen)
|
||||
msg = bytearray(self.receiveBytes(3))
|
||||
|
||||
# We have the magic header, here comes the message itself
|
||||
if msg is None:
|
||||
continue
|
||||
|
||||
msgId = msg[0]
|
||||
dataLen = msg[1] + (msg[2] << 8)
|
||||
if msgId not in (MSG_LOGOFF, MSG_MESSAGE, MSG_SCRIPT):
|
||||
raise Exception('Invalid message id: {}'.format(msgId))
|
||||
|
||||
data = self.receiveBytes(dataLen)
|
||||
if data is None:
|
||||
continue
|
||||
|
||||
self.messages.put((msgId, data))
|
||||
self.messageReceived()
|
||||
|
||||
except socket.error as e:
|
||||
logger.error('Communication with server got an error: {}'.format(toUnicode(e.strerror)))
|
||||
self.running = False
|
||||
return
|
||||
except Exception as e:
|
||||
tb = traceback.format_exc()
|
||||
logger.error('Error: {}, trace: {}'.format(e, tb))
|
||||
|
||||
try:
|
||||
self.clientSocket.close()
|
||||
except Exception:
|
||||
pass # If can't close, nothing happens, just end thread
|
||||
|
|
@ -0,0 +1,147 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2014 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
'''
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from opengnsys.service import CommonService
|
||||
from opengnsys.service import IPC_PORT
|
||||
from opengnsys import ipc
|
||||
|
||||
from opengnsys.log import logger
|
||||
|
||||
from opengnsys.linux.daemon import Daemon
|
||||
|
||||
import sys
|
||||
import signal
|
||||
import json
|
||||
|
||||
try:
|
||||
from prctl import set_proctitle # @UnresolvedImport
|
||||
except Exception: # Platform may not include prctl, so in case it's not available, we let the "name" as is
|
||||
def set_proctitle(_):
|
||||
pass
|
||||
|
||||
|
||||
class OGAgentSvc(Daemon, CommonService):
|
||||
def __init__(self, args=None):
|
||||
Daemon.__init__(self, '/var/run/opengnsys-agent.pid')
|
||||
CommonService.__init__(self)
|
||||
|
||||
def run(self):
|
||||
logger.debug('** Running Daemon **')
|
||||
set_proctitle('OGAgent')
|
||||
|
||||
self.initialize()
|
||||
|
||||
# Call modules initialization
|
||||
# They are called in sequence, no threading is done at this point, so ensure modules onActivate always returns
|
||||
|
||||
|
||||
# *********************
|
||||
# * Main Service loop *
|
||||
# *********************
|
||||
# Counter used to check ip changes only once every 10 seconds, for
|
||||
# example
|
||||
try:
|
||||
while self.isAlive:
|
||||
# In milliseconds, will break
|
||||
self.doWait(1000)
|
||||
except (KeyboardInterrupt, SystemExit) as e:
|
||||
logger.error('Requested exit of main loop')
|
||||
except Exception as e:
|
||||
logger.exception()
|
||||
logger.error('Caught exception on main loop: {}'.format(e))
|
||||
|
||||
self.terminate()
|
||||
|
||||
self.notifyStop()
|
||||
|
||||
def signal_handler(self, signal, frame):
|
||||
self.isAlive = False
|
||||
sys.stderr.write("signal handler: {}".format(signal))
|
||||
|
||||
|
||||
def usage():
|
||||
sys.stderr.write("usage: {} start|stop|restart|fg|login 'username'|logout 'username'|message 'module' 'message' 'json'\n".format(sys.argv[0]))
|
||||
sys.exit(2)
|
||||
|
||||
if __name__ == '__main__':
|
||||
logger.setLevel('INFO')
|
||||
|
||||
if len(sys.argv) == 5 and sys.argv[1] == 'message':
|
||||
logger.debug('Running client opengnsys')
|
||||
client = None
|
||||
try:
|
||||
client = ipc.ClientIPC(IPC_PORT)
|
||||
client.sendMessage(sys.argv[2], sys.argv[3], json.loads(sys.argv[4]))
|
||||
sys.exit(0)
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
|
||||
|
||||
if len(sys.argv) == 3 and sys.argv[1] in ('login', 'logout'):
|
||||
logger.debug('Running client opengnsys')
|
||||
client = None
|
||||
try:
|
||||
client = ipc.ClientIPC(IPC_PORT)
|
||||
if 'login' == sys.argv[1]:
|
||||
client.sendLogin(sys.argv[2])
|
||||
sys.exit(0)
|
||||
elif 'logout' == sys.argv[1]:
|
||||
client.sendLogout(sys.argv[2])
|
||||
sys.exit(0)
|
||||
else:
|
||||
usage()
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
elif len(sys.argv) != 2:
|
||||
usage()
|
||||
|
||||
logger.debug('Executing actor')
|
||||
daemon = OGAgentSvc()
|
||||
|
||||
signal.signal(signal.SIGTERM, daemon.signal_handler)
|
||||
signal.signal(signal.SIGINT, daemon.signal_handler)
|
||||
|
||||
if len(sys.argv) == 2:
|
||||
if 'start' == sys.argv[1]:
|
||||
daemon.start()
|
||||
elif 'stop' == sys.argv[1]:
|
||||
daemon.stop()
|
||||
elif 'restart' == sys.argv[1]:
|
||||
daemon.restart()
|
||||
elif 'fg' == sys.argv[1]:
|
||||
daemon.run()
|
||||
else:
|
||||
usage()
|
||||
sys.exit(0)
|
||||
else:
|
||||
usage()
|
|
@ -0,0 +1,32 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2014 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
'''
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
from __future__ import unicode_literals
|
|
@ -0,0 +1,182 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2014 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
'''
|
||||
@author: : http://www.jejik.com/authors/sander_marechal/
|
||||
@see: : http://www.jejik.com/articles/2007/02/a_simple_unix_linux_daemon_in_python/
|
||||
'''
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import sys
|
||||
import os
|
||||
import time
|
||||
import atexit
|
||||
from opengnsys.log import logger
|
||||
|
||||
from signal import SIGTERM
|
||||
|
||||
|
||||
class Daemon:
|
||||
"""
|
||||
A generic daemon class.
|
||||
|
||||
Usage: subclass the Daemon class and override the run() method
|
||||
"""
|
||||
def __init__(self, pidfile, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):
|
||||
self.stdin = stdin
|
||||
self.stdout = stdout
|
||||
self.stderr = stderr
|
||||
self.pidfile = pidfile
|
||||
|
||||
def daemonize(self):
|
||||
"""
|
||||
do the UNIX double-fork magic, see Stevens' "Advanced
|
||||
Programming in the UNIX Environment" for details (ISBN 0201563177)
|
||||
http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16
|
||||
"""
|
||||
try:
|
||||
pid = os.fork()
|
||||
if pid > 0:
|
||||
# exit first parent
|
||||
sys.exit(0)
|
||||
except OSError as e:
|
||||
logger.error("fork #1 error: {}".format(e))
|
||||
sys.stderr.write("fork #1 failed: {}\n".format(e))
|
||||
sys.exit(1)
|
||||
|
||||
# decouple from parent environment
|
||||
os.chdir("/")
|
||||
os.setsid()
|
||||
os.umask(0)
|
||||
|
||||
# do second fork
|
||||
try:
|
||||
pid = os.fork()
|
||||
if pid > 0:
|
||||
# exit from second parent
|
||||
sys.exit(0)
|
||||
except OSError as e:
|
||||
logger.error("fork #2 error: {}".format(e))
|
||||
sys.stderr.write("fork #2 failed: {}\n".format(e))
|
||||
sys.exit(1)
|
||||
|
||||
# redirect standard file descriptors
|
||||
sys.stdout.flush()
|
||||
sys.stderr.flush()
|
||||
si = open(self.stdin, 'r')
|
||||
so = open(self.stdout, 'a+')
|
||||
se = open(self.stderr, 'a+', 0)
|
||||
os.dup2(si.fileno(), sys.stdin.fileno())
|
||||
os.dup2(so.fileno(), sys.stdout.fileno())
|
||||
os.dup2(se.fileno(), sys.stderr.fileno())
|
||||
|
||||
# write pidfile
|
||||
atexit.register(self.delpid)
|
||||
pid = str(os.getpid())
|
||||
with open(self.pidfile, 'w+') as f:
|
||||
f.write("{}\n".format(pid))
|
||||
|
||||
def delpid(self):
|
||||
try:
|
||||
os.remove(self.pidfile)
|
||||
except Exception:
|
||||
# Not found/not permissions or whatever...
|
||||
pass
|
||||
|
||||
def start(self):
|
||||
"""
|
||||
Start the daemon
|
||||
"""
|
||||
logger.debug('Starting daemon')
|
||||
# Check for a pidfile to see if the daemon already runs
|
||||
try:
|
||||
pf = open(self.pidfile, 'r')
|
||||
pid = int(pf.read().strip())
|
||||
pf.close()
|
||||
except IOError:
|
||||
pid = None
|
||||
|
||||
if pid:
|
||||
message = "pidfile {} already exist. Daemon already running?\n".format(pid)
|
||||
logger.error(message)
|
||||
sys.stderr.write(message)
|
||||
sys.exit(1)
|
||||
|
||||
# Start the daemon
|
||||
self.daemonize()
|
||||
try:
|
||||
self.run()
|
||||
except Exception as e:
|
||||
logger.error('Exception running process: {}'.format(e))
|
||||
|
||||
if os.path.exists(self.pidfile):
|
||||
os.remove(self.pidfile)
|
||||
|
||||
def stop(self):
|
||||
"""
|
||||
Stop the daemon
|
||||
"""
|
||||
# Get the pid from the pidfile
|
||||
try:
|
||||
pf = open(self.pidfile, 'r')
|
||||
pid = int(pf.read().strip())
|
||||
pf.close()
|
||||
except IOError:
|
||||
pid = None
|
||||
|
||||
if pid is None:
|
||||
message = "pidfile {} does not exist. Daemon not running?\n".format(self.pidfile)
|
||||
logger.info(message)
|
||||
# sys.stderr.write(message)
|
||||
return # not an error in a restart
|
||||
|
||||
# Try killing the daemon process
|
||||
try:
|
||||
while True:
|
||||
os.kill(pid, SIGTERM)
|
||||
time.sleep(1)
|
||||
except OSError as err:
|
||||
if err.errno == 3: # No such process
|
||||
if os.path.exists(self.pidfile):
|
||||
os.remove(self.pidfile)
|
||||
else:
|
||||
sys.stderr.write(err)
|
||||
sys.exit(1)
|
||||
|
||||
def restart(self):
|
||||
"""
|
||||
Restart the daemon
|
||||
"""
|
||||
self.stop()
|
||||
self.start()
|
||||
|
||||
# Overridables
|
||||
def run(self):
|
||||
"""
|
||||
You should override this method when you subclass Daemon. It will be called after the process has been
|
||||
daemonized by start() or restart().
|
||||
"""
|
|
@ -0,0 +1,80 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2014 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
'''
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import logging
|
||||
import os
|
||||
import tempfile
|
||||
import six
|
||||
|
||||
# Valid logging levels, from UDS Broker (uds.core.utils.log)
|
||||
OTHER, DEBUG, INFO, WARN, ERROR, FATAL = (10000 * (x + 1) for x in six.moves.xrange(6)) # @UndefinedVariable
|
||||
|
||||
|
||||
class LocalLogger(object):
|
||||
def __init__(self):
|
||||
# tempdir is different for "user application" and "service"
|
||||
# service wil get c:\windows\temp, while user will get c:\users\XXX\temp
|
||||
# Try to open logger at /var/log path
|
||||
# If it fails (access denied normally), will try to open one at user's home folder, and if
|
||||
# agaim it fails, open it at the tmpPath
|
||||
|
||||
for logDir in ('/var/log', os.path.expanduser('~'), tempfile.gettempdir()):
|
||||
try:
|
||||
fname = os.path.join(logDir, 'opengnsys.log')
|
||||
logging.basicConfig(
|
||||
filename=fname,
|
||||
filemode='a',
|
||||
format='%(levelname)s %(asctime)s %(message)s',
|
||||
level=logging.DEBUG
|
||||
)
|
||||
self.logger = logging.getLogger('opengnsys')
|
||||
os.chmod(fname, 0o0600)
|
||||
return
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Logger can't be set
|
||||
self.logger = None
|
||||
|
||||
def log(self, level, message):
|
||||
# Debug messages are logged to a file
|
||||
# our loglevels are 10000 (other), 20000 (debug), ....
|
||||
# logging levels are 10 (debug), 20 (info)
|
||||
# OTHER = logging.NOTSET
|
||||
self.logger.log(int(level / 1000) - 10, message)
|
||||
|
||||
def isWindows(self):
|
||||
return False
|
||||
|
||||
def isLinux(self):
|
||||
return True
|
|
@ -0,0 +1,271 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2014 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
'''
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import socket
|
||||
import platform
|
||||
import fcntl
|
||||
import os
|
||||
import ctypes # @UnusedImport
|
||||
import ctypes.util
|
||||
import subprocess
|
||||
import struct
|
||||
import array
|
||||
import six
|
||||
from opengnsys import utils
|
||||
from .renamer import rename
|
||||
|
||||
|
||||
def _getMacAddr(ifname):
|
||||
'''
|
||||
Returns the mac address of an interface
|
||||
Mac is returned as unicode utf-8 encoded
|
||||
'''
|
||||
if isinstance(ifname, list):
|
||||
return dict([(name, _getMacAddr(name)) for name in ifname])
|
||||
if isinstance(ifname, six.text_type):
|
||||
ifname = ifname.encode('utf-8') # If unicode, convert to bytes (or str in python 2.7)
|
||||
try:
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
info = bytearray(fcntl.ioctl(s.fileno(), 0x8927, struct.pack(str('256s'), ifname[:15])))
|
||||
return six.text_type(''.join(['%02x:' % char for char in info[18:24]])[:-1])
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
def _getIpAddr(ifname):
|
||||
'''
|
||||
Returns the ip address of an interface
|
||||
Ip is returned as unicode utf-8 encoded
|
||||
'''
|
||||
if isinstance(ifname, list):
|
||||
return dict([(name, _getIpAddr(name)) for name in ifname])
|
||||
if isinstance(ifname, six.text_type):
|
||||
ifname = ifname.encode('utf-8') # If unicode, convert to bytes (or str in python 2.7)
|
||||
try:
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
return six.text_type(socket.inet_ntoa(fcntl.ioctl(
|
||||
s.fileno(),
|
||||
0x8915, # SIOCGIFADDR
|
||||
struct.pack(str('256s'), ifname[:15])
|
||||
)[20:24]))
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
def _getInterfaces():
|
||||
'''
|
||||
Returns a list of interfaces names coded in utf-8
|
||||
'''
|
||||
max_possible = 128 # arbitrary. raise if needed.
|
||||
space = max_possible * 16
|
||||
if platform.architecture()[0] == '32bit':
|
||||
offset, length = 32, 32
|
||||
elif platform.architecture()[0] == '64bit':
|
||||
offset, length = 16, 40
|
||||
else:
|
||||
raise OSError('Unknown arquitecture {0}'.format(platform.architecture()[0]))
|
||||
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
names = array.array(str('B'), b'\0' * space)
|
||||
outbytes = struct.unpack(str('iL'), fcntl.ioctl(
|
||||
s.fileno(),
|
||||
0x8912, # SIOCGIFCONF
|
||||
struct.pack(str('iL'), space, names.buffer_info()[0])
|
||||
))[0]
|
||||
namestr = names.tostring()
|
||||
# return namestr, outbytes
|
||||
return [namestr[i:i + offset].split(b'\0', 1)[0].decode('utf-8') for i in range(0, outbytes, length)]
|
||||
|
||||
|
||||
def _getIpAndMac(ifname):
|
||||
ip, mac = _getIpAddr(ifname), _getMacAddr(ifname)
|
||||
return (ip, mac)
|
||||
|
||||
|
||||
def getComputerName():
|
||||
'''
|
||||
Returns computer name, with no domain
|
||||
'''
|
||||
return socket.gethostname().split('.')[0]
|
||||
|
||||
|
||||
def getNetworkInfo():
|
||||
'''
|
||||
Obtains a list of network interfaces
|
||||
@return: A "generator" of elements, that are dict-as-object, with this elements:
|
||||
name: Name of the interface
|
||||
mac: mac of the interface
|
||||
ip: ip of the interface
|
||||
'''
|
||||
for ifname in _getInterfaces():
|
||||
ip, mac = _getIpAndMac(ifname)
|
||||
if mac != '00:00:00:00:00:00': # Skips local interfaces
|
||||
yield utils.Bunch(name=ifname, mac=mac, ip=ip)
|
||||
|
||||
|
||||
def getDomainName():
|
||||
return ''
|
||||
|
||||
|
||||
def getLinuxVersion():
|
||||
lv = platform.linux_distribution()
|
||||
return lv[0] + ', ' + lv[1]
|
||||
|
||||
|
||||
def reboot(flags=0):
|
||||
'''
|
||||
Simple reboot using os command
|
||||
'''
|
||||
# Workaround for dummy thread
|
||||
if six.PY3 is False:
|
||||
import threading
|
||||
threading._DummyThread._Thread__stop = lambda x: 42
|
||||
|
||||
# Check for OpenGnsys Client or GNU/Linux distribution.
|
||||
if os.path.exists('/scripts/oginit'):
|
||||
subprocess.call('source /opt/opengnsys/etc/preinit/loadenviron.sh; /opt/opengnsys/scripts/reboot', shell=True)
|
||||
else:
|
||||
subprocess.call(['/sbin/reboot'])
|
||||
|
||||
def poweroff(flags=0):
|
||||
'''
|
||||
Simple poweroff using os command
|
||||
'''
|
||||
# Workaround for dummy thread
|
||||
if six.PY3 is False:
|
||||
import threading
|
||||
threading._DummyThread._Thread__stop = lambda x: 42
|
||||
|
||||
# Check for OpenGnsys Client or GNU/Linux distribution.
|
||||
if os.path.exists('/scripts/oginit'):
|
||||
subprocess.call('source /opt/opengnsys/etc/preinit/loadenviron.sh; /opt/opengnsys/scripts/poweroff', shell=True)
|
||||
else:
|
||||
subprocess.call(['/sbin/poweroff'])
|
||||
|
||||
|
||||
|
||||
def logoff():
|
||||
'''
|
||||
Kills all curent user processes, which must send a logogof
|
||||
caveat: If the user has other sessions, will also disconnect from them
|
||||
'''
|
||||
# Workaround for dummy thread
|
||||
if six.PY3 is False:
|
||||
import threading
|
||||
threading._DummyThread._Thread__stop = lambda x: 42
|
||||
|
||||
subprocess.call(['/usr/bin/pkill', '-u', os.environ['USER']])
|
||||
|
||||
|
||||
def renameComputer(newName):
|
||||
rename(newName)
|
||||
|
||||
|
||||
def joinDomain(domain, ou, account, password, executeInOneStep=False):
|
||||
pass
|
||||
|
||||
|
||||
def changeUserPassword(user, oldPassword, newPassword):
|
||||
'''
|
||||
Simple password change for user using command line
|
||||
'''
|
||||
os.system('echo "{1}\n{1}" | /usr/bin/passwd {0} 2> /dev/null'.format(user, newPassword))
|
||||
|
||||
|
||||
class XScreenSaverInfo(ctypes.Structure):
|
||||
_fields_ = [('window', ctypes.c_long),
|
||||
('state', ctypes.c_int),
|
||||
('kind', ctypes.c_int),
|
||||
('til_or_since', ctypes.c_ulong),
|
||||
('idle', ctypes.c_ulong),
|
||||
('eventMask', ctypes.c_ulong)]
|
||||
|
||||
# Initialize xlib & xss
|
||||
try:
|
||||
xlibPath = ctypes.util.find_library('X11')
|
||||
xssPath = ctypes.util.find_library('Xss')
|
||||
xlib = ctypes.cdll.LoadLibrary(xlibPath)
|
||||
xss = ctypes.cdll.LoadLibrary(xssPath)
|
||||
|
||||
# Fix result type to XScreenSaverInfo Structure
|
||||
xss.XScreenSaverQueryExtension.restype = ctypes.c_int
|
||||
xss.XScreenSaverAllocInfo.restype = ctypes.POINTER(XScreenSaverInfo) # Result in a XScreenSaverInfo structure
|
||||
except Exception: # Libraries not accesible, not found or whatever..
|
||||
xlib = xss = None
|
||||
|
||||
|
||||
def initIdleDuration(atLeastSeconds):
|
||||
'''
|
||||
On linux we set the screensaver to at least required seconds, or we never will get "idle"
|
||||
'''
|
||||
# Workaround for dummy thread
|
||||
if six.PY3 is False:
|
||||
import threading
|
||||
threading._DummyThread._Thread__stop = lambda x: 42
|
||||
|
||||
subprocess.call(['/usr/bin/xset', 's', '{}'.format(atLeastSeconds + 30)])
|
||||
# And now reset it
|
||||
subprocess.call(['/usr/bin/xset', 's', 'reset'])
|
||||
|
||||
|
||||
def getIdleDuration():
|
||||
'''
|
||||
Returns idle duration, in seconds
|
||||
'''
|
||||
if xlib is None or xss is None:
|
||||
return 0 # Libraries not available
|
||||
|
||||
# production code might want to not hardcode the offset 16...
|
||||
display = xlib.XOpenDisplay(None)
|
||||
|
||||
event_base = ctypes.c_int()
|
||||
error_base = ctypes.c_int()
|
||||
|
||||
available = xss.XScreenSaverQueryExtension(display, ctypes.byref(event_base), ctypes.byref(error_base))
|
||||
if available != 1:
|
||||
return 0 # No screen saver is available, no way of getting idle
|
||||
|
||||
info = xss.XScreenSaverAllocInfo()
|
||||
xss.XScreenSaverQueryInfo(display, xlib.XDefaultRootWindow(display), info)
|
||||
|
||||
if info.contents.state != 0:
|
||||
return 3600 * 100 * 1000 # If screen saver is active, return a high enough value
|
||||
|
||||
return info.contents.idle / 1000.0
|
||||
|
||||
|
||||
def getCurrentUser():
|
||||
'''
|
||||
Returns current logged in user
|
||||
'''
|
||||
return os.environ['USER']
|
|
@ -0,0 +1,61 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2014 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
'''
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import platform
|
||||
import os
|
||||
import sys
|
||||
import pkgutil
|
||||
|
||||
from opengnsys.log import logger
|
||||
|
||||
renamers = {}
|
||||
|
||||
|
||||
# Renamers now are for IPv4 only addresses
|
||||
def rename(newName):
|
||||
distribution = platform.linux_distribution()[0].lower().strip()
|
||||
if distribution in renamers:
|
||||
return renamers[distribution](newName)
|
||||
|
||||
# Try Debian renamer, simplest one
|
||||
logger.info('Renamer for platform "{0}" not found, tryin debian renamer'.format(distribution))
|
||||
return renamers['debian'](newName)
|
||||
|
||||
|
||||
# Do load of packages
|
||||
def _init():
|
||||
pkgpath = os.path.dirname(sys.modules[__name__].__file__)
|
||||
for _, name, _ in pkgutil.iter_modules([pkgpath]):
|
||||
__import__(__name__ + '.' + name, globals(), locals())
|
||||
|
||||
_init()
|
|
@ -0,0 +1,68 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2014 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
'''
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from opengnsys.linux.renamer import renamers
|
||||
from opengnsys.log import logger
|
||||
|
||||
import os
|
||||
|
||||
|
||||
def rename(newName):
|
||||
'''
|
||||
Debian renamer
|
||||
Expects new host name on newName
|
||||
Host does not needs to be rebooted after renaming
|
||||
'''
|
||||
logger.debug('using Debian renamer')
|
||||
|
||||
with open('/etc/hostname', 'w') as hostname:
|
||||
hostname.write(newName)
|
||||
|
||||
# Force system new name
|
||||
os.system('/bin/hostname %s' % newName)
|
||||
|
||||
# add name to "hosts"
|
||||
with open('/etc/hosts', 'r') as hosts:
|
||||
lines = hosts.readlines()
|
||||
with open('/etc/hosts', 'w') as hosts:
|
||||
hosts.write("127.0.1.1\t%s\n" % newName)
|
||||
for l in lines:
|
||||
if l[:9] == '127.0.1.1': # Skips existing 127.0.1.1. if it already exists
|
||||
continue
|
||||
hosts.write(l)
|
||||
|
||||
return True
|
||||
|
||||
# All names in lower case
|
||||
renamers['debian'] = rename
|
||||
renamers['ubuntu'] = rename
|
|
@ -0,0 +1,66 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2014 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
'''
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from opengnsys.linux.renamer import renamers
|
||||
from opengnsys.log import logger
|
||||
|
||||
import os
|
||||
|
||||
|
||||
def rename(newName):
|
||||
'''
|
||||
RH, Centos, Fedora Renamer
|
||||
Expects new host name on newName
|
||||
Host does not needs to be rebooted after renaming
|
||||
'''
|
||||
logger.debug('using SUSE renamer')
|
||||
|
||||
with open('/etc/hostname', 'w') as hostname:
|
||||
hostname.write(newName)
|
||||
|
||||
# Force system new name
|
||||
os.system('/bin/hostname %s' % newName)
|
||||
|
||||
# add name to "hosts"
|
||||
with open('/etc/hosts', 'r') as hosts:
|
||||
lines = hosts.readlines()
|
||||
with open('/etc/hosts', 'w') as hosts:
|
||||
hosts.write("127.0.1.1\t{}\n".format(newName))
|
||||
for l in lines:
|
||||
if l[:9] != '127.0.1.1': # Skips existing 127.0.1.1. if it already exists
|
||||
hosts.write(l)
|
||||
|
||||
return True
|
||||
|
||||
# All names in lower case
|
||||
renamers['opensuse'] = rename
|
||||
renamers['suse'] = rename
|
|
@ -0,0 +1,74 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2014 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
'''
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from opengnsys.linux.renamer import renamers
|
||||
from opengnsys.log import logger
|
||||
|
||||
import os
|
||||
|
||||
|
||||
def rename(newName):
|
||||
'''
|
||||
RH, Centos, Fedora Renamer
|
||||
Expects new host name on newName
|
||||
Host does not needs to be rebooted after renaming
|
||||
'''
|
||||
logger.debug('using RH renamer')
|
||||
|
||||
with open('/etc/hostname', 'w') as hostname:
|
||||
hostname.write(newName)
|
||||
|
||||
# Force system new name
|
||||
os.system('/bin/hostname %s' % newName)
|
||||
|
||||
# add name to "hosts"
|
||||
with open('/etc/hosts', 'r') as hosts:
|
||||
lines = hosts.readlines()
|
||||
with open('/etc/hosts', 'w') as hosts:
|
||||
hosts.write("127.0.1.1\t{}\n".format(newName))
|
||||
for l in lines:
|
||||
if l[:9] != '127.0.1.1': # Skips existing 127.0.1.1. if it already exists
|
||||
hosts.write(l)
|
||||
|
||||
with open('/etc/sysconfig/network', 'r') as net:
|
||||
lines = net.readlines()
|
||||
with open('/etc/sysconfig/network', 'w') as net:
|
||||
net.write('HOSTNAME={}\n'.format(newName))
|
||||
for l in lines:
|
||||
if l[:8] != 'HOSTNAME':
|
||||
net.write(l)
|
||||
|
||||
return True
|
||||
|
||||
# All names in lower case
|
||||
renamers['centos linux'] = rename
|
||||
renamers['fedora'] = rename
|
|
@ -0,0 +1,111 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2014 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
'''
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
# pylint: disable=unused-wildcard-import,wildcard-import
|
||||
|
||||
# This is a simple module loader, so we can add "external opengnsys" modules as addons
|
||||
# Modules under "opengsnsys/modules" are always autoloaded
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import pkgutil
|
||||
import os.path
|
||||
|
||||
from opengnsys.workers import ServerWorker
|
||||
from opengnsys.workers import ClientWorker
|
||||
from .log import logger
|
||||
|
||||
|
||||
def loadModules(controller, client=False):
|
||||
'''
|
||||
Load own provided modules plus the modules that are in the configuration path.
|
||||
The loading order is not defined (they are loaded as found, because modules MUST be "standalone" modules
|
||||
@param service: The service that:
|
||||
* Holds the configuration
|
||||
* Will be used to initialize modules.
|
||||
'''
|
||||
|
||||
ogModules = []
|
||||
|
||||
if client is False:
|
||||
from opengnsys.modules.server import OpenGnSys # @UnusedImport
|
||||
from .modules import server # @UnusedImport, just used to ensure opengnsys modules are initialized
|
||||
modPath = 'opengnsys.modules.server'
|
||||
modType = ServerWorker
|
||||
else:
|
||||
from opengnsys.modules.client import OpenGnSys # @UnusedImport @Reimport
|
||||
from .modules import client # @UnusedImport, just used to ensure opengnsys modules are initialized
|
||||
modPath = 'opengnsys.modules.client'
|
||||
modType = ClientWorker
|
||||
|
||||
def addCls(cls):
|
||||
logger.debug('Found module class {}'.format(cls))
|
||||
try:
|
||||
if cls.name is None:
|
||||
# Error, cls has no name
|
||||
# Log the issue and
|
||||
logger.error('Class {} has no name attribute'.format(cls))
|
||||
return
|
||||
ogModules.append(cls(controller))
|
||||
except Exception as e:
|
||||
logger.error('Error loading module {}'.format(e))
|
||||
|
||||
def recursiveAdd(p):
|
||||
subcls = p.__subclasses__()
|
||||
|
||||
if len(subcls) == 0:
|
||||
addCls(p)
|
||||
else:
|
||||
for c in subcls:
|
||||
recursiveAdd(c)
|
||||
|
||||
def doLoad(paths):
|
||||
for (module_loader, name, ispkg) in pkgutil.iter_modules(paths, modPath + '.'):
|
||||
if ispkg:
|
||||
logger.debug('Found module package {}'.format(name))
|
||||
module_loader.find_module(name).load_module(name)
|
||||
|
||||
|
||||
if controller.config.has_option('opengnsys', 'path') is True:
|
||||
paths = tuple(os.path.abspath(v) for v in controller.config.get('opengnsys', 'path').split(','))
|
||||
else:
|
||||
paths = ()
|
||||
|
||||
# paths += (os.path.dirname(sys.modules[modPath].__file__),)
|
||||
|
||||
logger.debug('Loading modules from {}'.format(paths))
|
||||
|
||||
# Load modules
|
||||
doLoad(paths)
|
||||
|
||||
# Add to list of available modules
|
||||
recursiveAdd(modType)
|
||||
|
||||
return ogModules
|
|
@ -0,0 +1,103 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2014 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
'''
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import traceback
|
||||
import sys
|
||||
import six
|
||||
|
||||
if sys.platform == 'win32':
|
||||
from opengnsys.windows.log import LocalLogger # @UnusedImport
|
||||
else:
|
||||
from opengnsys.linux.log import LocalLogger # @Reimport
|
||||
|
||||
# Valid logging levels, from UDS Broker (uds.core.utils.log)
|
||||
OTHER, DEBUG, INFO, WARN, ERROR, FATAL = (10000 * (x + 1) for x in six.moves.xrange(6)) # @UndefinedVariable
|
||||
|
||||
_levelName = {
|
||||
'OTHER': OTHER,
|
||||
'DEBUG': DEBUG,
|
||||
'INFO': INFO,
|
||||
'WARN': WARN,
|
||||
'ERROR': ERROR,
|
||||
'FATAL': FATAL
|
||||
}
|
||||
|
||||
class Logger(object):
|
||||
def __init__(self):
|
||||
self.logLevel = INFO
|
||||
self.logger = LocalLogger()
|
||||
|
||||
def setLevel(self, level):
|
||||
'''
|
||||
Sets log level filter (minimum level required for a log message to be processed)
|
||||
:param level: Any message with a level below this will be filtered out
|
||||
'''
|
||||
if isinstance(level, six.string_types):
|
||||
level = _levelName.get(level, INFO)
|
||||
|
||||
self.logLevel = level # Ensures level is an integer or fails
|
||||
|
||||
def log(self, level, message):
|
||||
if level < self.logLevel: # Skip not wanted messages
|
||||
return
|
||||
|
||||
self.logger.log(level, message)
|
||||
|
||||
def debug(self, message):
|
||||
self.log(DEBUG, message)
|
||||
|
||||
def warn(self, message):
|
||||
self.log(WARN, message)
|
||||
|
||||
def info(self, message):
|
||||
self.log(INFO, message)
|
||||
|
||||
def error(self, message):
|
||||
self.log(ERROR, message)
|
||||
|
||||
def fatal(self, message):
|
||||
self.log(FATAL, message)
|
||||
|
||||
def exception(self):
|
||||
try:
|
||||
tb = traceback.format_exc()
|
||||
except Exception:
|
||||
tb = '(could not get traceback!)'
|
||||
|
||||
self.log(DEBUG, tb)
|
||||
|
||||
def flush(self):
|
||||
pass
|
||||
|
||||
|
||||
logger = Logger()
|
|
@ -0,0 +1,55 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2014 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
'''
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from opengnsys.workers import ClientWorker
|
||||
|
||||
from opengnsys import operations
|
||||
from opengnsys.log import logger
|
||||
|
||||
class OpenGnSysWorker(ClientWorker):
|
||||
name = 'opengnsys'
|
||||
|
||||
def onActivation(self):
|
||||
logger.debug('Activate invoked')
|
||||
|
||||
def onDeactivation(self):
|
||||
logger.debug('Deactivate invoked')
|
||||
|
||||
# Processes message "doit" (sample)
|
||||
def process_doit(self, jsonParams):
|
||||
logger.debug('Processed message doit with params {}'.format(jsonParams))
|
||||
self.sendServerMessage('doit', {'data':1})
|
||||
|
||||
def process_logoff(self, jsonParams):
|
||||
logger.debug('Processed logoff message with params {}'.format(jsonParams))
|
||||
operations.logoff()
|
||||
|
|
@ -0,0 +1,198 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2014 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
'''
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from opengnsys.workers import ServerWorker
|
||||
|
||||
from opengnsys import REST, RESTError
|
||||
from opengnsys import operations
|
||||
from opengnsys.log import logger
|
||||
from opengnsys.scriptThread import ScriptExecutorThread
|
||||
|
||||
import subprocess
|
||||
import threading
|
||||
import thread
|
||||
import os
|
||||
import platform
|
||||
import time
|
||||
|
||||
# Error handler decorator.
|
||||
def catchBackgroundError(fnc):
|
||||
def wrapper(*args, **kwargs):
|
||||
this = args[0]
|
||||
try:
|
||||
fnc(*args, **kwargs)
|
||||
except Exception as e:
|
||||
this.REST.sendMessage('error?id={}'.format(kwargs.get('requestId', 'error')), {'error': '{}'.format(e)})
|
||||
return wrapper
|
||||
|
||||
class OpenGnSysWorker(ServerWorker):
|
||||
name = 'opengnsys'
|
||||
interface = None # Binded interface for OpenGnsys
|
||||
loggedin = False #
|
||||
locked = {}
|
||||
|
||||
def onActivation(self):
|
||||
self.cmd = None
|
||||
# Ensure cfg has required configuration variables or an exception will be thrown
|
||||
|
||||
self.REST = REST(self.service.config.get('opengnsys', 'remote'))
|
||||
|
||||
# Get network interfaces
|
||||
self.interface = list(operations.getNetworkInfo())[0] # Get first network interface
|
||||
|
||||
# Send an initialize message
|
||||
#self.REST.sendMessage('initialize/{}/{}'.format(self.interface.mac, self.interface.ip))
|
||||
|
||||
# Send an POST message
|
||||
self.REST.sendMessage('ogagent/started', {'mac': self.interface.mac, 'ip': self.interface.ip})
|
||||
|
||||
def onDeactivation(self):
|
||||
#self.REST.sendMessage('deinitialize/{}/{}'.format(self.interface.mac, self.interface.ip))
|
||||
logger.debug('onDeactivation')
|
||||
self.REST.sendMessage('ogagent/stopped', {'mac': self.interface.mac, 'ip': self.interface.ip})
|
||||
|
||||
# Processes message "doit" (sample)
|
||||
#def process_doit(self, path, getParams, postParams):
|
||||
# # Send a sample message to client
|
||||
# logger.debug('Processing doit')
|
||||
# self.sendClientMessage('doit', {'param1': 'test', 'param2': 'test2'})
|
||||
# return 'Processed message for {}, {}, {}'.format(path, getParams, postParams)
|
||||
|
||||
def process_script(self, path, getParams, postParams):
|
||||
'''
|
||||
Processes an script execution (script is encoded in base64)
|
||||
'''
|
||||
logger.debug('Processing script request')
|
||||
script = postParams.get('script')
|
||||
if postParams.get('client', 'false') == 'false':
|
||||
thr = ScriptExecutorThread(script=script.decode('base64'))
|
||||
thr.start()
|
||||
else:
|
||||
self.sendScriptMessage(script)
|
||||
|
||||
return 'ok'
|
||||
|
||||
def processClientMessage(self, message, data):
|
||||
logger.debug('Got OpenGnsys message from client: {}, data {}'.format(message, data))
|
||||
|
||||
def process_client_doit(self, params):
|
||||
self.REST.sendMessage('doit_done', params)
|
||||
|
||||
def onLogin(self, user):
|
||||
logger.debug('Received login for {}'.format(user))
|
||||
self.loggedin = True
|
||||
self.REST.sendMessage('ogagent/loggedin', {'ip': self.interface.ip, "user": user})
|
||||
|
||||
def onLogout(self, user):
|
||||
logger.debug('Received logout for {}'.format(user))
|
||||
self.loggedin = False
|
||||
self.REST.sendMessage('ogagent/loggedout', {'ip': self.interface.ip, "user": user})
|
||||
|
||||
def process_ogclient(self, path, getParams, postParams):
|
||||
'''
|
||||
This method can be overriden to provide your own message proccessor, or better you can
|
||||
implement a method that is called exactly as "process_" + path[0] (module name has been removed from path array) and this default processMessage will invoke it
|
||||
* Example:
|
||||
Imagine this invocation url (no matter if GET or POST): http://example.com:9999/Sample/mazinger/Z
|
||||
The HTTP Server will remove "Sample" from path, parse arguments and invoke this method as this:
|
||||
module.processMessage(["mazinger","Z"], getParams, postParams)
|
||||
|
||||
This method will process "mazinger", and look for a "self" method that is called "process_mazinger", and invoke it this way:
|
||||
return self.process_mazinger(["Z"], getParams, postParams)
|
||||
|
||||
In the case path is empty (that is, the path is composed only by the module name, like in "http://example.com/Sample", the "process" method
|
||||
will be invoked directly
|
||||
|
||||
The methods must return data that can be serialized to json (i.e. Ojects are not serializable to json, basic type are)
|
||||
'''
|
||||
if len(path) == 0:
|
||||
return "ok"
|
||||
try:
|
||||
operation = getattr(self, 'ogclient_' + path[0])
|
||||
except Exception:
|
||||
raise Exception('Message processor for "{}" not found'.format(path[0]))
|
||||
|
||||
return operation(path[1:], getParams, postParams)
|
||||
|
||||
###### EN PRUEBAS ######
|
||||
def process_status(self, path, getParams, postParams):
|
||||
'''
|
||||
Returns client status.
|
||||
'''
|
||||
res = { 'status': '', 'loggedin': self.loggedin }
|
||||
if platform.system() == 'Linux': # GNU/Linux
|
||||
# Check if it's OpenGnsys Client.
|
||||
if os.path.exists('/scripts/oginit'):
|
||||
# Check if OpenGnsys Client is busy.
|
||||
if self.locked:
|
||||
res['status'] = 'BSY'
|
||||
else:
|
||||
res['status'] = 'OPG'
|
||||
else:
|
||||
# Check if there is an active session.
|
||||
res['status'] = 'LNX'
|
||||
elif platform.system() == 'Windows': # Windows
|
||||
# Check if there is an active session.
|
||||
res['status'] = 'WIN'
|
||||
elif platform.system() == 'Darwin': # Mac OS X ??
|
||||
res['status'] = 'OSX'
|
||||
return res
|
||||
|
||||
def process_reboot(self, path, getParams, postParams):
|
||||
'''
|
||||
Launches a system reboot operation.
|
||||
'''
|
||||
logger.debug('Received reboot operation')
|
||||
def rebt():
|
||||
operations.reboot()
|
||||
threading.Thread(target=rebt).start()
|
||||
return {'op': 'launched'}
|
||||
|
||||
def process_poweroff(self, path, getParams, postParams):
|
||||
'''
|
||||
Launches a system power off operation.
|
||||
'''
|
||||
logger.debug('Received poweroff operation')
|
||||
def pwoff():
|
||||
time.sleep(2)
|
||||
operations.poweroff()
|
||||
threading.Thread(target=pwoff).start()
|
||||
return {'op': 'launched'}
|
||||
|
||||
def process_logoff(self, path, getParams, postParams):
|
||||
'''
|
||||
Closes user session.
|
||||
'''
|
||||
logger.debug('Received logoff operation')
|
||||
self.sendClientMessage('logoff', {})
|
||||
return 'Logoff operation was sended to client'
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2014 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
'''
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
# pylint: disable=unused-wildcard-import,wildcard-import
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import sys
|
||||
if sys.platform == 'win32':
|
||||
from .windows.operations import * # @UnusedWildImport
|
||||
else:
|
||||
from .linux.operations import * # @UnusedWildImport
|
|
@ -0,0 +1,51 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 201 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
'''
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
|
||||
# pylint: disable-msg=E1101,W0703
|
||||
|
||||
from opengnsys.log import logger
|
||||
|
||||
import threading
|
||||
import six
|
||||
|
||||
|
||||
class ScriptExecutorThread(threading.Thread):
|
||||
def __init__(self, script):
|
||||
super(ScriptExecutorThread, self).__init__()
|
||||
self.script = script
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
logger.debug('Executing script: {}'.format(self.script))
|
||||
six.exec_(self.script, globals(), None)
|
||||
except Exception as e:
|
||||
logger.error('Error executing script: {}'.format(e))
|
|
@ -0,0 +1,243 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2014 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
'''
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from .log import logger
|
||||
from .config import readConfig
|
||||
from .utils import exceptionToMessage
|
||||
|
||||
from . import ipc
|
||||
from . import httpserver
|
||||
from .loader import loadModules
|
||||
|
||||
import socket
|
||||
import time
|
||||
import json
|
||||
import six
|
||||
|
||||
IPC_PORT = 10398
|
||||
|
||||
|
||||
class CommonService(object):
|
||||
isAlive = True
|
||||
ipc = None
|
||||
httpServer = None
|
||||
modules = None
|
||||
|
||||
def __init__(self):
|
||||
logger.info('----------------------------------------')
|
||||
logger.info('Initializing OpenGnsys Agent')
|
||||
|
||||
# Read configuration file before proceding & ensures minimal config is there
|
||||
|
||||
self.config = readConfig()
|
||||
|
||||
# Get opengnsys section as dict
|
||||
cfg = dict(self.config.items('opengnsys'))
|
||||
|
||||
# Set up log level
|
||||
logger.setLevel(cfg.get('log', 'INFO'))
|
||||
|
||||
|
||||
logger.debug('Loaded configuration from opengnsys.cfg:')
|
||||
for section in self.config.sections():
|
||||
logger.debug('Section {} = {}'.format(section, self.config.items(section)))
|
||||
|
||||
|
||||
if logger.logger.isWindows():
|
||||
# Logs will also go to windows event log for services
|
||||
logger.logger.serviceLogger = True
|
||||
|
||||
self.address = (cfg.get('address', '0.0.0.0'), int(cfg.get('port', '10997')))
|
||||
self.ipcport = int(cfg.get('ipc_port', IPC_PORT))
|
||||
|
||||
self.timeout = int(cfg.get('timeout', '20'))
|
||||
|
||||
logger.debug('Socket timeout: {}'.format(self.timeout))
|
||||
socket.setdefaulttimeout(self.timeout)
|
||||
|
||||
# Now load modules
|
||||
self.modules = loadModules(self)
|
||||
logger.debug('Modules: {}'.format(list(v.name for v in self.modules)))
|
||||
|
||||
def stop(self):
|
||||
'''
|
||||
Requests service termination
|
||||
'''
|
||||
self.isAlive = False
|
||||
|
||||
# ********************************
|
||||
# * Internal messages processors *
|
||||
# ********************************
|
||||
def notifyLogin(self, username):
|
||||
for v in self.modules:
|
||||
try:
|
||||
logger.debug('Notifying login of user {} to module {}'.format(username, v.name))
|
||||
v.onLogin(username)
|
||||
except Exception as e:
|
||||
logger.error('Got exception {} processing login message on {}'.format(e, v.name))
|
||||
|
||||
def notifyLogout(self, username):
|
||||
for v in self.modules:
|
||||
try:
|
||||
logger.debug('Notifying logout of user {} to module {}'.format(username, v.name))
|
||||
v.onLogout(username)
|
||||
except Exception as e:
|
||||
logger.error('Got exception {} processing logout message on {}'.format(e, v.name))
|
||||
|
||||
def notifyMessage(self, data):
|
||||
module, message, data = data.split('\0')
|
||||
for v in self.modules:
|
||||
if v.name == module: # Case Sensitive!!!!
|
||||
try:
|
||||
logger.debug('Notifying message {} to module {} with json data {}'.format(message, v.name, data))
|
||||
v.processClientMessage(message, json.loads(data))
|
||||
return
|
||||
except Exception as e:
|
||||
logger.error('Got exception {} processing generic message on {}'.format(e, v.name))
|
||||
|
||||
logger.error('Module {} not found, messsage {} not sent'.format(module, message))
|
||||
|
||||
|
||||
def clientMessageProcessor(self, msg, data):
|
||||
'''
|
||||
Callback, invoked from IPC, on its own thread (not the main thread).
|
||||
This thread will "block" communication with agent untill finished, but this should be no problem
|
||||
'''
|
||||
logger.debug('Got message {}'.format(msg))
|
||||
|
||||
if msg == ipc.REQ_LOGIN:
|
||||
self.notifyLogin(data)
|
||||
elif msg == ipc.REQ_LOGOUT:
|
||||
self.notifyLogout(data)
|
||||
elif msg == ipc.REQ_MESSAGE:
|
||||
self.notifyMessage(data)
|
||||
|
||||
def initialize(self):
|
||||
# ******************************************
|
||||
# * Initialize listeners, modules, etc...
|
||||
# ******************************************
|
||||
|
||||
if six.PY3 is False:
|
||||
import threading
|
||||
threading._DummyThread._Thread__stop = lambda x: 42
|
||||
|
||||
logger.debug('Starting IPC listener at {}'.format(IPC_PORT))
|
||||
self.ipc = ipc.ServerIPC(self.ipcport, clientMessageProcessor=self.clientMessageProcessor)
|
||||
self.ipc.start()
|
||||
|
||||
# And http threaded server
|
||||
self.httpServer = httpserver.HTTPServerThread(self.address, self)
|
||||
self.httpServer.start()
|
||||
|
||||
# And lastly invoke modules activation
|
||||
validMods = []
|
||||
for mod in self.modules:
|
||||
try:
|
||||
logger.debug('Activating module {}'.format(mod.name))
|
||||
mod.activate()
|
||||
validMods.append(mod)
|
||||
except Exception as e:
|
||||
logger.exception()
|
||||
logger.error("Activation of {} failed: {}".format(mod.name, exceptionToMessage(e)))
|
||||
|
||||
self.modules[:] = validMods # copy instead of assignment
|
||||
|
||||
logger.debug('Modules after activation: {}'.format(list(v.name for v in self.modules)))
|
||||
|
||||
def terminate(self):
|
||||
# First invoke deactivate on modules
|
||||
for mod in reversed(self.modules):
|
||||
try:
|
||||
logger.debug('Deactivating module {}'.format(mod.name))
|
||||
mod.deactivate()
|
||||
except Exception as e:
|
||||
logger.exception()
|
||||
logger.error("Deactivation of {} failed: {}".format(mod.name, exceptionToMessage(e)))
|
||||
|
||||
# Remove IPC threads
|
||||
if self.ipc is not None:
|
||||
try:
|
||||
self.ipc.stop()
|
||||
except Exception:
|
||||
logger.error('Couln\'t stop ipc server')
|
||||
|
||||
if self.httpServer is not None:
|
||||
try:
|
||||
self.httpServer.stop()
|
||||
except Exception:
|
||||
logger.error('Couln\'t stop RESTApi server')
|
||||
|
||||
self.notifyStop()
|
||||
|
||||
# ****************************************
|
||||
# Methods that CAN BE overridden by agents
|
||||
# ****************************************
|
||||
def doWait(self, miliseconds):
|
||||
'''
|
||||
Invoked to wait a bit
|
||||
CAN be OVERRIDDEN
|
||||
'''
|
||||
time.sleep(float(miliseconds) / 1000)
|
||||
|
||||
def notifyStop(self):
|
||||
'''
|
||||
Overridden to log stop
|
||||
'''
|
||||
logger.info('Service is being stopped')
|
||||
|
||||
# ***************************************************
|
||||
# * Helpers, convenient methods to facilitate comms *
|
||||
# ***************************************************
|
||||
def sendClientMessage(self, toModule, message, data):
|
||||
'''
|
||||
Sends a message to the clients using IPC
|
||||
The data is converted to json, so ensure that it is serializable.
|
||||
All IPC is asynchronous, so if you expect a response, this will be sent by client using another message
|
||||
|
||||
@param toModule: Module that will receive this message
|
||||
@param message: Message to send
|
||||
@param data: data to send
|
||||
'''
|
||||
self.ipc.sendMessageMessage('\0'.join((toModule, message, json.dumps(data))))
|
||||
|
||||
def sendScriptMessage(self, script):
|
||||
'''
|
||||
Sends an script to be executed by client
|
||||
'''
|
||||
self.ipc.sendScriptMessage(script)
|
||||
|
||||
def sendLogoffMessage(self):
|
||||
'''
|
||||
Sends a logoff message to client
|
||||
'''
|
||||
self.ipc.sendLoggofMessage()
|
|
@ -0,0 +1,72 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2014 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
'''
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import sys
|
||||
import six
|
||||
|
||||
if sys.platform == 'win32':
|
||||
_fromEncoding = 'windows-1250'
|
||||
else:
|
||||
_fromEncoding = 'utf-8'
|
||||
|
||||
|
||||
def toUnicode(msg):
|
||||
try:
|
||||
if not isinstance(msg, six.text_type):
|
||||
if isinstance(msg, six.binary_type):
|
||||
return msg.decode(_fromEncoding, 'ignore')
|
||||
return six.text_type(msg)
|
||||
else:
|
||||
return msg
|
||||
except Exception:
|
||||
try:
|
||||
return six.text_type(msg)
|
||||
except Exception:
|
||||
return ''
|
||||
|
||||
|
||||
def exceptionToMessage(e):
|
||||
msg = ''
|
||||
for arg in e.args:
|
||||
if isinstance(arg, Exception):
|
||||
msg = msg + exceptionToMessage(arg)
|
||||
else:
|
||||
msg = msg + toUnicode(arg) + '. '
|
||||
return msg
|
||||
|
||||
|
||||
class Bunch(dict):
|
||||
def __init__(self, **kw):
|
||||
dict.__init__(self, kw)
|
||||
self.__dict__ = self
|
||||
|
|
@ -0,0 +1,124 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2014 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
'''
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
# pylint: disable=unused-wildcard-import, wildcard-import
|
||||
|
||||
import win32serviceutil # @UnresolvedImport, pylint: disable=import-error
|
||||
import win32service # @UnresolvedImport, pylint: disable=import-error
|
||||
import win32security # @UnresolvedImport, pylint: disable=import-error
|
||||
import win32net # @UnresolvedImport, pylint: disable=import-error
|
||||
import win32event # @UnresolvedImport, pylint: disable=import-error
|
||||
import win32com.client # @UnresolvedImport, @UnusedImport, pylint: disable=import-error
|
||||
import pythoncom # @UnresolvedImport, pylint: disable=import-error
|
||||
import servicemanager # @UnresolvedImport, pylint: disable=import-error
|
||||
import os
|
||||
|
||||
from opengnsys import operations
|
||||
from opengnsys.service import CommonService
|
||||
|
||||
from opengnsys.log import logger
|
||||
|
||||
class OGAgentSvc(win32serviceutil.ServiceFramework, CommonService):
|
||||
'''
|
||||
This class represents a Windows Service for managing actor interactions
|
||||
with UDS Broker and Machine
|
||||
'''
|
||||
_svc_name_ = "OGAgent"
|
||||
_svc_display_name_ = "OpenGnSys Agent Service"
|
||||
_svc_description_ = "OpenGnSys Agent for machines"
|
||||
# 'System Event Notification' is the SENS service
|
||||
_svc_deps_ = ['EventLog']
|
||||
|
||||
def __init__(self, args):
|
||||
win32serviceutil.ServiceFramework.__init__(self, args)
|
||||
CommonService.__init__(self)
|
||||
self.hWaitStop = win32event.CreateEvent(None, 1, 0, None)
|
||||
self._user = None
|
||||
|
||||
def SvcStop(self):
|
||||
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
|
||||
self.isAlive = False
|
||||
win32event.SetEvent(self.hWaitStop)
|
||||
|
||||
SvcShutdown = SvcStop
|
||||
|
||||
def notifyStop(self):
|
||||
servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
|
||||
servicemanager.PYS_SERVICE_STOPPED,
|
||||
(self._svc_name_, ''))
|
||||
|
||||
def doWait(self, miliseconds):
|
||||
win32event.WaitForSingleObject(self.hWaitStop, miliseconds)
|
||||
|
||||
def SvcDoRun(self):
|
||||
'''
|
||||
Main service loop
|
||||
'''
|
||||
try:
|
||||
logger.debug('running SvcDoRun')
|
||||
servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
|
||||
servicemanager.PYS_SERVICE_STARTED,
|
||||
(self._svc_name_, ''))
|
||||
|
||||
# call the CoInitialize to allow the registration to run in an other
|
||||
# thread
|
||||
logger.debug('Initializing com...')
|
||||
pythoncom.CoInitialize()
|
||||
|
||||
# Initialize remaining service data
|
||||
self.initialize()
|
||||
except Exception: # Any init exception wil be caught, service must be then restarted
|
||||
logger.exception()
|
||||
logger.debug('Exiting service with failure status')
|
||||
os._exit(-1) # pylint: disable=protected-access
|
||||
|
||||
# *********************
|
||||
# * Main Service loop *
|
||||
# *********************
|
||||
try:
|
||||
while self.isAlive:
|
||||
# Pumps & processes any waiting messages
|
||||
pythoncom.PumpWaitingMessages()
|
||||
win32event.WaitForSingleObject(self.hWaitStop, 1000)
|
||||
except Exception as e:
|
||||
logger.error('Caught exception on main loop: {}'.format(e))
|
||||
|
||||
logger.debug('Exited main loop, deregistering SENS')
|
||||
|
||||
self.terminate() # Ends IPC servers
|
||||
|
||||
self.notifyStop()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
win32serviceutil.HandleCommandLine(OGAgentSvc)
|
|
@ -0,0 +1,39 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2014 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
'''
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
# Change to application directory.
|
||||
os.chdir(os.path.dirname(sys.argv[0]))
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2014 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
'''
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import servicemanager # @UnresolvedImport, pylint: disable=import-error
|
||||
import logging
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
# Valid logging levels, from UDS Broker (uds.core.utils.log)
|
||||
OTHER, DEBUG, INFO, WARN, ERROR, FATAL = (10000 * (x + 1) for x in xrange(6))
|
||||
|
||||
|
||||
class LocalLogger(object):
|
||||
def __init__(self):
|
||||
# tempdir is different for "user application" and "service"
|
||||
# service wil get c:\windows\temp, while user will get c:\users\XXX\temp
|
||||
logging.basicConfig(
|
||||
filename=os.path.join(tempfile.gettempdir(), 'opengnsys.log'),
|
||||
filemode='a',
|
||||
format='%(levelname)s %(asctime)s %(message)s',
|
||||
level=logging.DEBUG
|
||||
)
|
||||
self.logger = logging.getLogger('opengnsys')
|
||||
self.serviceLogger = False
|
||||
|
||||
def log(self, level, message):
|
||||
# Debug messages are logged to a file
|
||||
# our loglevels are 10000 (other), 20000 (debug), ....
|
||||
# logging levels are 10 (debug), 20 (info)
|
||||
# OTHER = logging.NOTSET
|
||||
self.logger.log(level / 1000 - 10, message)
|
||||
|
||||
if level < INFO or self.serviceLogger is False: # Only information and above will be on event log
|
||||
return
|
||||
|
||||
if level < WARN: # Info
|
||||
servicemanager.LogInfoMsg(message)
|
||||
elif level < ERROR: # WARN
|
||||
servicemanager.LogWarningMsg(message)
|
||||
else: # Error & Fatal
|
||||
servicemanager.LogErrorMsg(message)
|
||||
|
||||
def isWindows(self):
|
||||
return True
|
||||
|
||||
def isLinux(self):
|
||||
return False
|
|
@ -0,0 +1,231 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2014 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
'''
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import win32com.client # @UnresolvedImport, pylint: disable=import-error
|
||||
import win32net # @UnresolvedImport, pylint: disable=import-error
|
||||
import win32security # @UnresolvedImport, pylint: disable=import-error
|
||||
import win32api # @UnresolvedImport, pylint: disable=import-error
|
||||
import win32con # @UnresolvedImport, pylint: disable=import-error
|
||||
import ctypes
|
||||
from ctypes.wintypes import DWORD, LPCWSTR
|
||||
import os
|
||||
|
||||
from opengnsys import utils
|
||||
from opengnsys.log import logger
|
||||
|
||||
|
||||
def getErrorMessage(res=0):
|
||||
msg = win32api.FormatMessage(res)
|
||||
return msg.decode('windows-1250', 'ignore')
|
||||
|
||||
|
||||
def getComputerName():
|
||||
return win32api.GetComputerNameEx(win32con.ComputerNamePhysicalDnsHostname)
|
||||
|
||||
|
||||
def getNetworkInfo():
|
||||
'''
|
||||
Obtains a list of network interfaces
|
||||
@return: A "generator" of elements, that are dict-as-object, with this elements:
|
||||
name: Name of the interface
|
||||
mac: mac of the interface
|
||||
ip: ip of the interface
|
||||
'''
|
||||
obj = win32com.client.Dispatch("WbemScripting.SWbemLocator")
|
||||
wmobj = obj.ConnectServer("localhost", "root\cimv2")
|
||||
adapters = wmobj.ExecQuery("Select * from Win32_NetworkAdapterConfiguration where IpEnabled=True")
|
||||
try:
|
||||
for obj in adapters:
|
||||
for ip in obj.IPAddress:
|
||||
if ':' in ip: # Is IPV6, skip this
|
||||
continue
|
||||
if ip is None or ip == '' or ip.startswith('169.254') or ip.startswith('0.'): # If single link ip, or no ip
|
||||
continue
|
||||
# logger.debug('Net config found: {}=({}, {})'.format(obj.Caption, obj.MACAddress, ip))
|
||||
yield utils.Bunch(name=obj.Caption, mac=obj.MACAddress, ip=ip)
|
||||
except Exception:
|
||||
return
|
||||
|
||||
|
||||
def getDomainName():
|
||||
'''
|
||||
Will return the domain name if we belong a domain, else None
|
||||
(if part of a network group, will also return None)
|
||||
'''
|
||||
# Status:
|
||||
# 0 = Unknown
|
||||
# 1 = Unjoined
|
||||
# 2 = Workgroup
|
||||
# 3 = Domain
|
||||
domain, status = win32net.NetGetJoinInformation()
|
||||
if status != 3:
|
||||
domain = None
|
||||
|
||||
return domain
|
||||
|
||||
|
||||
def getWindowsVersion():
|
||||
return win32api.GetVersionEx()
|
||||
|
||||
EWX_LOGOFF = 0x00000000
|
||||
EWX_SHUTDOWN = 0x00000001
|
||||
EWX_REBOOT = 0x00000002
|
||||
EWX_FORCE = 0x00000004
|
||||
EWX_POWEROFF = 0x00000008
|
||||
EWX_FORCEIFHUNG = 0x00000010
|
||||
|
||||
|
||||
def reboot(flags=EWX_FORCEIFHUNG | EWX_REBOOT):
|
||||
hproc = win32api.GetCurrentProcess()
|
||||
htok = win32security.OpenProcessToken(hproc, win32security.TOKEN_ADJUST_PRIVILEGES | win32security.TOKEN_QUERY)
|
||||
privs = ((win32security.LookupPrivilegeValue(None, win32security.SE_SHUTDOWN_NAME), win32security.SE_PRIVILEGE_ENABLED),)
|
||||
win32security.AdjustTokenPrivileges(htok, 0, privs)
|
||||
win32api.ExitWindowsEx(flags, 0)
|
||||
|
||||
def poweroff(flags=0):
|
||||
'''
|
||||
Simple poweroff command.
|
||||
'''
|
||||
reboot(flags=EWX_FORCEIFHUNG | EWX_POWEROFF)
|
||||
|
||||
def logoff():
|
||||
win32api.ExitWindowsEx(EWX_LOGOFF)
|
||||
|
||||
|
||||
def renameComputer(newName):
|
||||
# Needs admin privileges to work
|
||||
if ctypes.windll.kernel32.SetComputerNameExW(DWORD(win32con.ComputerNamePhysicalDnsHostname), LPCWSTR(newName)) == 0: # @UndefinedVariable
|
||||
# win32api.FormatMessage -> returns error string
|
||||
# win32api.GetLastError -> returns error code
|
||||
# (just put this comment here to remember to log this when logger is available)
|
||||
error = getErrorMessage()
|
||||
computerName = win32api.GetComputerNameEx(win32con.ComputerNamePhysicalDnsHostname)
|
||||
raise Exception('Error renaming computer from {} to {}: {}'.format(computerName, newName, error))
|
||||
|
||||
NETSETUP_JOIN_DOMAIN = 0x00000001
|
||||
NETSETUP_ACCT_CREATE = 0x00000002
|
||||
NETSETUP_ACCT_DELETE = 0x00000004
|
||||
NETSETUP_WIN9X_UPGRADE = 0x00000010
|
||||
NETSETUP_DOMAIN_JOIN_IF_JOINED = 0x00000020
|
||||
NETSETUP_JOIN_UNSECURE = 0x00000040
|
||||
NETSETUP_MACHINE_PWD_PASSED = 0x00000080
|
||||
NETSETUP_JOIN_WITH_NEW_NAME = 0x00000400
|
||||
NETSETUP_DEFER_SPN_SET = 0x1000000
|
||||
|
||||
|
||||
def joinDomain(domain, ou, account, password, executeInOneStep=False):
|
||||
'''
|
||||
Joins machine to a windows domain
|
||||
:param domain: Domain to join to
|
||||
:param ou: Ou that will hold machine
|
||||
:param account: Account used to join domain
|
||||
:param password: Password of account used to join domain
|
||||
:param executeInOneStep: If true, means that this machine has been renamed and wants to add NETSETUP_JOIN_WITH_NEW_NAME to request so we can do rename/join in one step.
|
||||
'''
|
||||
# If account do not have domain, include it
|
||||
if '@' not in account and '\\' not in account:
|
||||
if '.' in domain:
|
||||
account = account + '@' + domain
|
||||
else:
|
||||
account = domain + '\\' + account
|
||||
|
||||
# Do log
|
||||
flags = NETSETUP_ACCT_CREATE | NETSETUP_DOMAIN_JOIN_IF_JOINED | NETSETUP_JOIN_DOMAIN
|
||||
|
||||
if executeInOneStep:
|
||||
flags |= NETSETUP_JOIN_WITH_NEW_NAME
|
||||
|
||||
flags = DWORD(flags)
|
||||
|
||||
domain = LPCWSTR(domain)
|
||||
|
||||
# Must be in format "ou=.., ..., dc=...,"
|
||||
ou = LPCWSTR(ou) if ou is not None and ou != '' else None
|
||||
account = LPCWSTR(account)
|
||||
password = LPCWSTR(password)
|
||||
|
||||
res = ctypes.windll.netapi32.NetJoinDomain(None, domain, ou, account, password, flags)
|
||||
# Machine found in another ou, use it and warn this on log
|
||||
if res == 2224:
|
||||
flags = DWORD(NETSETUP_DOMAIN_JOIN_IF_JOINED | NETSETUP_JOIN_DOMAIN)
|
||||
res = ctypes.windll.netapi32.NetJoinDomain(None, domain, None, account, password, flags)
|
||||
if res != 0:
|
||||
# Log the error
|
||||
error = getErrorMessage(res)
|
||||
if res == 1355:
|
||||
error = "DC Is not reachable"
|
||||
print res, error
|
||||
raise Exception('Error joining domain {}, with credentials {}/*****{}: {}, {}'.format(domain.value, account.value, ', under OU {}'.format(ou.value) if ou.value is not None else '', res, error))
|
||||
|
||||
|
||||
def changeUserPassword(user, oldPassword, newPassword):
|
||||
computerName = LPCWSTR(getComputerName())
|
||||
user = LPCWSTR(user)
|
||||
oldPassword = LPCWSTR(oldPassword)
|
||||
newPassword = LPCWSTR(newPassword)
|
||||
|
||||
res = ctypes.windll.netapi32.NetUserChangePassword(computerName, user, oldPassword, newPassword)
|
||||
|
||||
if res != 0:
|
||||
# Log the error, and raise exception to parent
|
||||
error = getErrorMessage()
|
||||
raise Exception('Error changing password for user {}: {}'.format(user.value, error))
|
||||
|
||||
|
||||
class LASTINPUTINFO(ctypes.Structure):
|
||||
_fields_ = [
|
||||
('cbSize', ctypes.c_uint),
|
||||
('dwTime', ctypes.c_uint),
|
||||
]
|
||||
|
||||
|
||||
def initIdleDuration(atLeastSeconds):
|
||||
'''
|
||||
In windows, there is no need to set screensaver
|
||||
'''
|
||||
pass
|
||||
|
||||
|
||||
def getIdleDuration():
|
||||
lastInputInfo = LASTINPUTINFO()
|
||||
lastInputInfo.cbSize = ctypes.sizeof(lastInputInfo)
|
||||
ctypes.windll.user32.GetLastInputInfo(ctypes.byref(lastInputInfo))
|
||||
millis = ctypes.windll.kernel32.GetTickCount() - lastInputInfo.dwTime # @UndefinedVariable
|
||||
return millis / 1000.0
|
||||
|
||||
|
||||
def getCurrentUser():
|
||||
'''
|
||||
Returns current logged in username
|
||||
'''
|
||||
return os.environ['USERNAME']
|
|
@ -0,0 +1,2 @@
|
|||
from .server_worker import ServerWorker
|
||||
from .client_worker import ClientWorker
|
|
@ -0,0 +1,114 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2014 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
'''
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
# pylint: disable=unused-wildcard-import,wildcard-import
|
||||
from __future__ import unicode_literals
|
||||
|
||||
class ClientWorker(object):
|
||||
'''
|
||||
A ServerWorker is a server module that "works" for service
|
||||
Most method are invoked inside their own thread, except onActivation & onDeactivation.
|
||||
This two methods are invoked inside main service thread, take that into account when creating them
|
||||
|
||||
* You must provide a module name (override name on your class), so we can identify the module by a "valid" name.
|
||||
A valid name is like a valid python variable (do not use spaces, etc...)
|
||||
* The name of the module is used as REST message destination id:
|
||||
https://sampleserver:8888/[name]/....
|
||||
Remember that module names and REST path are case sensitive!!!
|
||||
|
||||
'''
|
||||
name = None
|
||||
service = None
|
||||
|
||||
def __init__(self, service):
|
||||
self.service = service
|
||||
|
||||
def activate(self):
|
||||
'''
|
||||
Convenient method to wrap onActivation, so we can include easyly custom common logic for activation in a future
|
||||
'''
|
||||
self.onActivation()
|
||||
|
||||
def deactivate(self):
|
||||
'''
|
||||
Convenient method to wrap onActivation, so we can include easyly custom common logic for deactivation in a future
|
||||
'''
|
||||
self.onDeactivation()
|
||||
|
||||
def processMessage(self, message, params):
|
||||
'''
|
||||
This method can be overriden to provide your own message proccessor, or better you can
|
||||
implement a method that is called "process_" + message and this default processMessage will invoke it
|
||||
* Example:
|
||||
We got a message from OGAgent "Mazinger", with json params
|
||||
module.processMessage("mazinger", jsonParams)
|
||||
|
||||
This method will process "mazinguer", and look for a "self" method that is called "process_mazinger", and invoke it this way:
|
||||
return self.process_mazinger(jsonParams)
|
||||
|
||||
The methods must return data that can be serialized to json (i.e. Ojects are not serializable to json, basic type are)
|
||||
'''
|
||||
try:
|
||||
operation = getattr(self, 'process_' + message)
|
||||
except Exception:
|
||||
raise Exception('Message processor for "{}" not found'.format(message))
|
||||
|
||||
return operation(params)
|
||||
|
||||
def onActivation(self):
|
||||
'''
|
||||
Invoked by Service for activation.
|
||||
This MUST be overridden by modules!
|
||||
This method is invoked inside main thread, so if it "hangs", complete service will hang
|
||||
This should be no problem, but be advised about this
|
||||
'''
|
||||
pass
|
||||
|
||||
def onDeactivation(self):
|
||||
'''
|
||||
Invoked by Service before unloading service
|
||||
This MUST be overridden by modules!
|
||||
This method is invoked inside main thread, so if it "hangs", complete service will hang
|
||||
This should be no problem, but be advised about this
|
||||
'''
|
||||
pass
|
||||
|
||||
# *************************************
|
||||
# * Helper, convenient helper methods *
|
||||
# *************************************
|
||||
def sendServerMessage(self, message, data):
|
||||
'''
|
||||
Sends a message to connected ipc clients
|
||||
By convenience, it uses the "current" moduel name as destination module name also.
|
||||
If you need to send a message to a different module, you can use self.service.sendClientMessage(module, message, data) instead
|
||||
og this helmer
|
||||
'''
|
||||
self.service.ipc.sendMessage(self.name, message, data)
|
||||
|
|
@ -0,0 +1,183 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2014 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
'''
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
# pylint: disable=unused-wildcard-import,wildcard-import
|
||||
from __future__ import unicode_literals
|
||||
|
||||
class ServerWorker(object):
|
||||
'''
|
||||
A ServerWorker is a server module that "works" for service
|
||||
Most method are invoked inside their own thread, except onActivation & onDeactivation.
|
||||
This two methods are invoked inside main service thread, take that into account when creating them
|
||||
|
||||
* You must provide a module name (override name on your class), so we can identify the module by a "valid" name.
|
||||
A valid name is like a valid python variable (do not use spaces, etc...)
|
||||
* The name of the module is used as REST message destination id:
|
||||
https://sampleserver:8888/[name]/....
|
||||
Remember that module names and REST path are case sensitive!!!
|
||||
|
||||
'''
|
||||
name = None
|
||||
service = None
|
||||
locked = False
|
||||
|
||||
def __init__(self, service):
|
||||
self.service = service
|
||||
|
||||
def activate(self):
|
||||
'''
|
||||
Convenient method to wrap onActivation, so we can include easyly custom common logic for activation in a future
|
||||
'''
|
||||
self.onActivation()
|
||||
|
||||
def deactivate(self):
|
||||
'''
|
||||
Convenient method to wrap onActivation, so we can include easyly custom common logic for deactivation in a future
|
||||
'''
|
||||
self.onDeactivation()
|
||||
|
||||
def process(self, getParams, postParams):
|
||||
'''
|
||||
This method is invoked on a message received with an empty path (that means a message with only the module name, like in "http://example.com/Sample"
|
||||
Override it if you expect messages with that pattern
|
||||
|
||||
Overriden method must return data that can be serialized to json (i.e. Ojects are not serializable to json, basic type are)
|
||||
'''
|
||||
raise NotImplementedError('Generic message processor is not supported')
|
||||
|
||||
def processServerMessage(self, path, getParams, postParams):
|
||||
'''
|
||||
This method can be overriden to provide your own message proccessor, or better you can
|
||||
implement a method that is called exactly as "process_" + path[0] (module name has been removed from path array) and this default processMessage will invoke it
|
||||
* Example:
|
||||
Imagine this invocation url (no matter if GET or POST): http://example.com:9999/Sample/mazinger/Z
|
||||
The HTTP Server will remove "Sample" from path, parse arguments and invoke this method as this:
|
||||
module.processMessage(["mazinger","Z"], getParams, postParams)
|
||||
|
||||
This method will process "mazinguer", and look for a "self" method that is called "process_mazinger", and invoke it this way:
|
||||
return self.process_mazinger(["Z"], getParams, postParams)
|
||||
|
||||
In the case path is empty (that is, the path is composed only by the module name, like in "http://example.com/Sample", the "process" method
|
||||
will be invoked directly
|
||||
|
||||
The methods must return data that can be serialized to json (i.e. Ojects are not serializable to json, basic type are)
|
||||
'''
|
||||
if self.locked is True:
|
||||
raise Exception('system is busy')
|
||||
|
||||
if len(path) == 0:
|
||||
return self.process(getParams, postParams)
|
||||
try:
|
||||
operation = getattr(self, 'process_' + path[0])
|
||||
except Exception:
|
||||
raise Exception('Message processor for "{}" not found'.format(path[0]))
|
||||
|
||||
return operation(path[1:], getParams, postParams)
|
||||
|
||||
|
||||
def processClientMessage(self, message, data):
|
||||
'''
|
||||
Invoked by Service when a client message is received (A message from user space Agent)
|
||||
|
||||
This method can be overriden to provide your own message proccessor, or better you can
|
||||
implement a method that is called exactly "process_client_" + message (module name has been removed from path) and this default processMessage will invoke it
|
||||
* Example:
|
||||
We got a message from OGAgent "Mazinger", with json params
|
||||
module.processClientMessage("mazinger", jsonParams)
|
||||
|
||||
This method will process "mazinguer", and look for a "self" method that is called "process_client_mazinger", and invoke it this way:
|
||||
self.process_client_mazinger(jsonParams)
|
||||
|
||||
The methods returns nothing (client communications are done asynchronously)
|
||||
'''
|
||||
try:
|
||||
operation = getattr(self, 'process_client_' + message)
|
||||
except Exception:
|
||||
raise Exception('Message processor for "{}" not found'.format(message))
|
||||
|
||||
operation(data)
|
||||
|
||||
# raise NotImplementedError('Got a client message but no proccessor is implemented')
|
||||
|
||||
|
||||
def onActivation(self):
|
||||
'''
|
||||
Invoked by Service for activation.
|
||||
This MUST be overridden by modules!
|
||||
This method is invoked inside main thread, so if it "hangs", complete service will hang
|
||||
This should be no problem, but be advised about this
|
||||
'''
|
||||
pass
|
||||
|
||||
def onDeactivation(self):
|
||||
'''
|
||||
Invoked by Service before unloading service
|
||||
This MUST be overridden by modules!
|
||||
This method is invoked inside main thread, so if it "hangs", complete service will hang
|
||||
This should be no problem, but be advised about this
|
||||
'''
|
||||
pass
|
||||
|
||||
|
||||
def onLogin(self, user):
|
||||
'''
|
||||
Invoked by Service when an user login is detected
|
||||
This CAN be overridden by modules
|
||||
This method is invoked whenever the client (user space agent) notifies the server (Service) that a user has logged in.
|
||||
This method is run on its own thread
|
||||
'''
|
||||
pass
|
||||
|
||||
def onLogout(self, user):
|
||||
'''
|
||||
Invoked by Service when an user login is detected
|
||||
This CAN be overridden by modules
|
||||
This method is invoked whenever the client (user space agent) notifies the server (Service) that a user has logged in.
|
||||
This method is run on its own thread
|
||||
'''
|
||||
pass
|
||||
|
||||
# *************************************
|
||||
# * Helper, convenient helper methods *
|
||||
# *************************************
|
||||
def sendClientMessage(self, message, data):
|
||||
'''
|
||||
Sends a message to connected ipc clients
|
||||
By convenience, it uses the "current" moduel name as destination module name also.
|
||||
If you need to send a message to a different module, you can use self.service.sendClientMessage(module, message, data) instead
|
||||
og this helmer
|
||||
'''
|
||||
self.service.sendClientMessage(self.name, message, data)
|
||||
|
||||
def sendScriptMessage(self, script):
|
||||
self.service.sendScriptMessage(script)
|
||||
|
||||
def sendLogoffMessage(self):
|
||||
self.service.sendLogoffMessage()
|
|
@ -0,0 +1,170 @@
|
|||
'''
|
||||
Created on Jul 9, 2015
|
||||
|
||||
@author: dkmaster
|
||||
'''
|
||||
from __future__ import unicode_literals, print_function
|
||||
|
||||
# Pydev can't parse "six.moves.xxxx" because it is loaded lazy
|
||||
from six.moves.socketserver import ThreadingMixIn # @UnresolvedImport
|
||||
from six.moves.SimpleHTTPServer import SimpleHTTPRequestHandler # @UnresolvedImport
|
||||
from six.moves.BaseHTTPServer import HTTPServer # @UnresolvedImport
|
||||
from six.moves.urllib.parse import unquote # @UnresolvedImport
|
||||
|
||||
import json
|
||||
import threading
|
||||
import ssl
|
||||
|
||||
import os.path
|
||||
import tempfile
|
||||
|
||||
# For testing
|
||||
# --------------------
|
||||
CERTFILE = 'UDSActor.pem'
|
||||
|
||||
|
||||
def createSelfSignedCert(force=False):
|
||||
|
||||
certFile = os.path.join(tempfile.gettempdir(), CERTFILE)
|
||||
|
||||
if os.path.exists(certFile) and not force:
|
||||
return certFile
|
||||
|
||||
certData = '''-----BEGIN PRIVATE KEY-----
|
||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCb50K3mIznNklz
|
||||
yVAD7xSQOSJQ6+NPXj7U9/4zLZ+TvmbQ7RqUUsxbfxHbeRnoYTWV2nKk4+tHqmvz
|
||||
ujLSS/loFhTSMqtrLn7rowSYJoQhKOUkAiQlWkqCfItWgL5pJopDpNHFul9Rn3ds
|
||||
PMWQTiGeUNR4Y3RnBhr1Q1BsqAzf4m6zFUmgLPPmVLdF4uJ3Tuz8TSy2gWLs5aSr
|
||||
5do4WamwUfYjRSVMJECmwjUM4rQ8SQgg0sHBeBuDUGNBvBQFac1G7qUcMReeu8Zr
|
||||
DUtMsXma/l4rA8NB5CRmTrQbTBF4l+jb2BDFebDqDUK1Oqs9X35yOQfDOAFYHiix
|
||||
PX0IsXOZAgMBAAECggEBAJi3000RrIUZUp6Ph0gzPMuCjDEEwWiQA7CPNX1gpb8O
|
||||
dp0WhkDhUroWIaICYPSXtOwUTtVjRqivMoxPy1Thg3EIoGC/rdeSdlXRHMEGicwJ
|
||||
yVyalFnatr5Xzg5wkxVh4XMd0zeDt7e3JD7s0QLo5lm1CEzd77qz6lhzFic5/1KX
|
||||
bzdULtTlq60dazg2hEbcS4OmM1UMCtRVDAsOIUIZPL0M9j1C1d1iEdYnh2xshKeG
|
||||
/GOfo95xsgdMlGjtv3hUT5ryKVoEsu+36rGb4VfhPfUvvoVbRx5QZpW+QvxaYh5E
|
||||
Fi0JEROozFwG31Y++8El7J3yQko8cFBa1lYYUwwpNAECgYEAykT+GiM2YxJ4uVF1
|
||||
OoKiE9BD53i0IG5j87lGPnWqzEwYBwnqjEKDTou+uzMGz3MDV56UEFNho7wUWh28
|
||||
LpEkjJB9QgbsugjxIBr4JoL/rYk036e/6+U8I95lvYWrzb+rBMIkRDYI7kbQD/mQ
|
||||
piYUpuCkTymNAu2RisK6bBzJslkCgYEAxVE23OQvkCeOV8hJNPZGpJ1mDS+TiOow
|
||||
oOScMZmZpail181eYbAfMsCr7ri812lSj98NvA2GNVLpddil6LtS1cQ5p36lFBtV
|
||||
xQUMZiFz4qVbEak+izL+vPaev/mXXsOcibAIQ+qI/0txFpNhJjpaaSy6vRCBYFmc
|
||||
8pgSoBnBI0ECgYAUKCn2atnpp5aWSTLYgNosBU4vDA1PShD14dnJMaqyr0aZtPhF
|
||||
v/8b3btFJoGgPMLxgWEZ+2U4ju6sSFhPf7FXvLJu2QfQRkHZRDbEh7t5DLpTK4Fp
|
||||
va9vl6Ml7uM/HsGpOLuqfIQJUs87OFCc7iCSvMJDDU37I7ekT2GKkpfbCQKBgBrE
|
||||
0NeY0WcSJrp7/oqD2sOcYurpCG/rrZs2SIZmGzUhMxaa0vIXzbO59dlWELB8pmnE
|
||||
Tf20K//x9qA5OxDe0PcVPukdQlH+/1zSOYNliG44FqnHtyd1TJ/gKVtMBiAiE4uO
|
||||
aSClod5Yosf4SJbCFd/s5Iyfv52NqsAyp1w3Aj/BAoGAVCnEiGUfyHlIR+UH4zZW
|
||||
GXJMeqdZLfcEIszMxLePkml4gUQhoq9oIs/Kw+L1DDxUwzkXN4BNTlFbOSu9gzK1
|
||||
dhuIUGfS6RPL88U+ivC3A0y2jT43oUMqe3hiRt360UQ1GXzp2dMnR9odSRB1wHoO
|
||||
IOjEBZ8341/c9ZHc5PCGAG8=
|
||||
-----END PRIVATE KEY-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIID7zCCAtegAwIBAgIJAIrEIthCfxUCMA0GCSqGSIb3DQEBCwUAMIGNMQswCQYD
|
||||
VQQGEwJFUzEPMA0GA1UECAwGTWFkcmlkMREwDwYDVQQHDAhBbGNvcmNvbjEMMAoG
|
||||
A1UECgwDVURTMQ4wDAYDVQQLDAVBY3RvcjESMBAGA1UEAwwJVURTIEFjdG9yMSgw
|
||||
JgYJKoZIhvcNAQkBFhlzdXBwb3J0QHVkc2VudGVycHJpc2UuY29tMB4XDTE0MTAy
|
||||
NjIzNDEyNFoXDTI0MTAyMzIzNDEyNFowgY0xCzAJBgNVBAYTAkVTMQ8wDQYDVQQI
|
||||
DAZNYWRyaWQxETAPBgNVBAcMCEFsY29yY29uMQwwCgYDVQQKDANVRFMxDjAMBgNV
|
||||
BAsMBUFjdG9yMRIwEAYDVQQDDAlVRFMgQWN0b3IxKDAmBgkqhkiG9w0BCQEWGXN1
|
||||
cHBvcnRAdWRzZW50ZXJwcmlzZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
|
||||
ggEKAoIBAQCb50K3mIznNklzyVAD7xSQOSJQ6+NPXj7U9/4zLZ+TvmbQ7RqUUsxb
|
||||
fxHbeRnoYTWV2nKk4+tHqmvzujLSS/loFhTSMqtrLn7rowSYJoQhKOUkAiQlWkqC
|
||||
fItWgL5pJopDpNHFul9Rn3dsPMWQTiGeUNR4Y3RnBhr1Q1BsqAzf4m6zFUmgLPPm
|
||||
VLdF4uJ3Tuz8TSy2gWLs5aSr5do4WamwUfYjRSVMJECmwjUM4rQ8SQgg0sHBeBuD
|
||||
UGNBvBQFac1G7qUcMReeu8ZrDUtMsXma/l4rA8NB5CRmTrQbTBF4l+jb2BDFebDq
|
||||
DUK1Oqs9X35yOQfDOAFYHiixPX0IsXOZAgMBAAGjUDBOMB0GA1UdDgQWBBRShS90
|
||||
5lJTNvYPIEqP3GxWwG5iiDAfBgNVHSMEGDAWgBRShS905lJTNvYPIEqP3GxWwG5i
|
||||
iDAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAU0Sp4gXhQmRVzq+7+
|
||||
vRFUkQuPj4Ga/d9r5Wrbg3hck3+5pwe9/7APoq0P/M0DBhQpiJKjrD6ydUevC+Y/
|
||||
43ZOJPhMlNw0o6TdQxOkX6FDwQanLLs7sfvJvqtVzYn3nuRFKT3dvl7Zg44QMw2M
|
||||
ay42q59fAcpB4LaDx/i7gOYSS5eca3lYW7j7YSr/+ozXK2KlgUkuCUHN95lOq+dF
|
||||
trmV9mjzM4CNPZqKSE7kpHRywgrXGPCO000NvEGSYf82AtgRSFKiU8NWLQSEPdcB
|
||||
k//2dsQZw2cRZ8DrC2B6Tb3M+3+CA6wVyqfqZh1SZva3LfGvq/C+u+ItguzPqNpI
|
||||
xtvM
|
||||
-----END CERTIFICATE-----'''
|
||||
with open(certFile, "wt") as f:
|
||||
f.write(certData)
|
||||
|
||||
return certFile
|
||||
# --------------
|
||||
|
||||
|
||||
class HTTPServerHandler(SimpleHTTPRequestHandler):
|
||||
service = None
|
||||
protocol_version = 'HTTP/1.1'
|
||||
server_version = 'OpenGnsys Agent Server'
|
||||
sys_version = ''
|
||||
|
||||
def sendJsonError(self, code, message):
|
||||
self.send_response(code)
|
||||
self.send_header('Content-type', 'application/json')
|
||||
self.end_headers()
|
||||
self.wfile.write(json.dumps({'error': message}))
|
||||
return
|
||||
|
||||
def sendJsonResponse(self, data):
|
||||
self.send_response(200)
|
||||
data = json.dumps(data)
|
||||
self.send_header('Content-type', 'application/json')
|
||||
self.send_header('Content-Length', len(data))
|
||||
self.end_headers()
|
||||
# Send the html message
|
||||
self.wfile.write(data)
|
||||
|
||||
|
||||
# parseURL
|
||||
def parseUrl(self):
|
||||
# Very simple path & params splitter
|
||||
path = self.path.split('?')[0][1:].split('/')
|
||||
|
||||
try:
|
||||
params = dict((v[0], unquote(v[1])) for v in (v.split('=') for v in self.path.split('?')[1].split('&')))
|
||||
except Exception:
|
||||
params = {}
|
||||
|
||||
return (path, params)
|
||||
|
||||
|
||||
def do_GET(self):
|
||||
path, params = self.parseUrl()
|
||||
|
||||
self.sendJsonResponse({'path': path, 'params': params})
|
||||
|
||||
def do_POST(self):
|
||||
path, getParams = self.parseUrl()
|
||||
|
||||
# Now post parameters, that are in JSON format
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class HTTPThreadingServer(ThreadingMixIn, HTTPServer):
|
||||
pass
|
||||
|
||||
class HTTPServerThread(threading.Thread):
|
||||
def __init__(self, address, service):
|
||||
super(self.__class__, self).__init__()
|
||||
|
||||
HTTPServerHandler.service = service
|
||||
|
||||
self.certFile = createSelfSignedCert()
|
||||
self.server = HTTPThreadingServer(address, HTTPServerHandler)
|
||||
self.server.socket = ssl.wrap_socket(self.server.socket, certfile=self.certFile, server_side=True)
|
||||
|
||||
def getServerUrl(self):
|
||||
return 'https://{}:{}/{}'.format(self.server.server_address[0], self.server.server_address[1], HTTPServerHandler.uuid)
|
||||
|
||||
def stop(self):
|
||||
self.server.shutdown()
|
||||
|
||||
def run(self):
|
||||
self.server.serve_forever()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
thr = HTTPServerThread(('0.0.0.0', 8000), None)
|
||||
print('Server started: {}'.format(thr))
|
||||
thr.start()
|
||||
|
||||
|
|
@ -0,0 +1,132 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2014 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
'''
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
|
||||
VERSION = '1.0.0'
|
||||
|
||||
# ModuleFinder can't handle runtime changes to __path__, but win32com uses them
|
||||
try:
|
||||
# py2exe 0.6.4 introduced a replacement modulefinder.
|
||||
# This means we have to add package paths there, not to the built-in
|
||||
# one. If this new modulefinder gets integrated into Python, then
|
||||
# we might be able to revert this some day.
|
||||
# if this doesn't work, try import modulefinder
|
||||
try:
|
||||
import py2exe.mf as modulefinder
|
||||
except ImportError:
|
||||
import modulefinder
|
||||
import win32com, sys
|
||||
for p in win32com.__path__[1:]:
|
||||
modulefinder.AddPackagePath("win32com", p)
|
||||
for extra in ["win32com.shell"]: # ,"win32com.mapi"
|
||||
__import__(extra)
|
||||
m = sys.modules[extra]
|
||||
for p in m.__path__[1:]:
|
||||
modulefinder.AddPackagePath(extra, p)
|
||||
except ImportError:
|
||||
# no build path setup, no worries.
|
||||
pass
|
||||
|
||||
from distutils.core import setup
|
||||
import py2exe
|
||||
import sys
|
||||
import os
|
||||
|
||||
sys.argv.append('py2exe')
|
||||
|
||||
def get_requests_cert_file():
|
||||
"""Add Python requests .pem file for installers."""
|
||||
import requests
|
||||
f = os.path.join(os.path.dirname(requests.__file__), 'cacert.pem')
|
||||
return f
|
||||
|
||||
|
||||
class Target:
|
||||
|
||||
def __init__(self, **kw):
|
||||
self.__dict__.update(kw)
|
||||
# for the versioninfo resources
|
||||
self.version = VERSION
|
||||
self.name = 'OGAgentService'
|
||||
self.description = 'OpenGnsys Agent Service'
|
||||
self.author = 'Adolfo Gomez'
|
||||
self.url = 'http://www.opengnsys.es'
|
||||
self.company_name = "VirtualCable S.L.U."
|
||||
self.copyright = "(c) 2014 VirtualCable S.L.U."
|
||||
self.name = "OpenGnsys Agent"
|
||||
|
||||
# Now you need to pass arguments to setup
|
||||
# windows is a list of scripts that have their own UI and
|
||||
# thus don't need to run in a console.
|
||||
|
||||
|
||||
udsservice = Target(
|
||||
description='OpenGnsys Agent Service',
|
||||
modules=['opengnsys.windows.OGAgentService'],
|
||||
icon_resources=[(0, 'img\\oga.ico'), (1, 'img\\oga.ico')],
|
||||
cmdline_style='pywin32'
|
||||
)
|
||||
|
||||
# Some test_modules are hidden to py2exe by six, we ensure that they appear on "includes"
|
||||
HIDDEN_BY_SIX = ['SocketServer', 'SimpleHTTPServer', 'urllib']
|
||||
|
||||
setup(
|
||||
windows=[
|
||||
{
|
||||
'script': 'OGAgentUser.py',
|
||||
'icon_resources': [(0, 'img\\oga.ico'), (1, 'img\\oga.ico')]
|
||||
},
|
||||
],
|
||||
console=[
|
||||
{
|
||||
'script': 'OGAServiceHelper.py'
|
||||
}
|
||||
],
|
||||
service=[udsservice],
|
||||
data_files=[('', [get_requests_cert_file()]),('cfg', ['cfg/ogagent.cfg', 'cfg/ogclient.cfg'])],
|
||||
options={
|
||||
'py2exe': {
|
||||
'bundle_files': 3,
|
||||
'compressed': True,
|
||||
'optimize': 2,
|
||||
'includes': [ 'sip', 'PyQt4', 'win32com.shell', 'requests'] + HIDDEN_BY_SIX,
|
||||
'excludes': [ 'doctest', 'unittest' ],
|
||||
'dll_excludes': ['msvcp90.dll'],
|
||||
'dist_dir': '..\\bin',
|
||||
}
|
||||
},
|
||||
name='OpenGnsys Agent',
|
||||
version=VERSION,
|
||||
description='OpenGnsys Agent',
|
||||
author='Adolfo Gomez',
|
||||
author_email='agomez@virtualcable.es',
|
||||
zipfile='OGAgent.zip',
|
||||
)
|
|
@ -0,0 +1,38 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2014 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
'''
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from opengnsys.workers import ClientWorker
|
||||
|
||||
class Sample1(ClientWorker):
|
||||
name = 'Sample1'
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
# Module must be imported on package, so we can initialize and load it
|
||||
from sample1 import Sample1
|
|
@ -0,0 +1,40 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2014 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
'''
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from opengnsys.workers import ServerWorker
|
||||
|
||||
from .sample_pkg import test
|
||||
|
||||
class Sample1(ServerWorker):
|
||||
name='Sample1'
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2014 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
'''
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
|
||||
|
||||
def test():
|
||||
return 'Test'
|
|
@ -0,0 +1,210 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2015 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
'''
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
# pylint: disable=unused-wildcard-import,wildcard-import
|
||||
from __future__ import unicode_literals, print_function
|
||||
|
||||
# Pydev can't parse "six.moves.xxxx" because it is loaded lazy
|
||||
from six.moves.socketserver import ThreadingMixIn # @UnresolvedImport
|
||||
from six.moves.BaseHTTPServer import BaseHTTPRequestHandler # @UnresolvedImport
|
||||
from six.moves.BaseHTTPServer import HTTPServer # @UnresolvedImport
|
||||
from six.moves.urllib.parse import unquote # @UnresolvedImport
|
||||
|
||||
import json
|
||||
import threading
|
||||
import ssl
|
||||
|
||||
import logging
|
||||
from tempfile import gettempdir
|
||||
from os.path import exists, join
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
CERTFILE = 'OGTestServer.pem'
|
||||
|
||||
|
||||
def createSelfSignedCert(force=False):
|
||||
|
||||
certFile = join(gettempdir(), CERTFILE)
|
||||
|
||||
if exists(certFile) and not force:
|
||||
return certFile
|
||||
|
||||
certData = '''-----BEGIN PRIVATE KEY-----
|
||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCb50K3mIznNklz
|
||||
yVAD7xSQOSJQ6+NPXj7U9/4zLZ+TvmbQ7RqUUsxbfxHbeRnoYTWV2nKk4+tHqmvz
|
||||
ujLSS/loFhTSMqtrLn7rowSYJoQhKOUkAiQlWkqCfItWgL5pJopDpNHFul9Rn3ds
|
||||
PMWQTiGeUNR4Y3RnBhr1Q1BsqAzf4m6zFUmgLPPmVLdF4uJ3Tuz8TSy2gWLs5aSr
|
||||
5do4WamwUfYjRSVMJECmwjUM4rQ8SQgg0sHBeBuDUGNBvBQFac1G7qUcMReeu8Zr
|
||||
DUtMsXma/l4rA8NB5CRmTrQbTBF4l+jb2BDFebDqDUK1Oqs9X35yOQfDOAFYHiix
|
||||
PX0IsXOZAgMBAAECggEBAJi3000RrIUZUp6Ph0gzPMuCjDEEwWiQA7CPNX1gpb8O
|
||||
dp0WhkDhUroWIaICYPSXtOwUTtVjRqivMoxPy1Thg3EIoGC/rdeSdlXRHMEGicwJ
|
||||
yVyalFnatr5Xzg5wkxVh4XMd0zeDt7e3JD7s0QLo5lm1CEzd77qz6lhzFic5/1KX
|
||||
bzdULtTlq60dazg2hEbcS4OmM1UMCtRVDAsOIUIZPL0M9j1C1d1iEdYnh2xshKeG
|
||||
/GOfo95xsgdMlGjtv3hUT5ryKVoEsu+36rGb4VfhPfUvvoVbRx5QZpW+QvxaYh5E
|
||||
Fi0JEROozFwG31Y++8El7J3yQko8cFBa1lYYUwwpNAECgYEAykT+GiM2YxJ4uVF1
|
||||
OoKiE9BD53i0IG5j87lGPnWqzEwYBwnqjEKDTou+uzMGz3MDV56UEFNho7wUWh28
|
||||
LpEkjJB9QgbsugjxIBr4JoL/rYk036e/6+U8I95lvYWrzb+rBMIkRDYI7kbQD/mQ
|
||||
piYUpuCkTymNAu2RisK6bBzJslkCgYEAxVE23OQvkCeOV8hJNPZGpJ1mDS+TiOow
|
||||
oOScMZmZpail181eYbAfMsCr7ri812lSj98NvA2GNVLpddil6LtS1cQ5p36lFBtV
|
||||
xQUMZiFz4qVbEak+izL+vPaev/mXXsOcibAIQ+qI/0txFpNhJjpaaSy6vRCBYFmc
|
||||
8pgSoBnBI0ECgYAUKCn2atnpp5aWSTLYgNosBU4vDA1PShD14dnJMaqyr0aZtPhF
|
||||
v/8b3btFJoGgPMLxgWEZ+2U4ju6sSFhPf7FXvLJu2QfQRkHZRDbEh7t5DLpTK4Fp
|
||||
va9vl6Ml7uM/HsGpOLuqfIQJUs87OFCc7iCSvMJDDU37I7ekT2GKkpfbCQKBgBrE
|
||||
0NeY0WcSJrp7/oqD2sOcYurpCG/rrZs2SIZmGzUhMxaa0vIXzbO59dlWELB8pmnE
|
||||
Tf20K//x9qA5OxDe0PcVPukdQlH+/1zSOYNliG44FqnHtyd1TJ/gKVtMBiAiE4uO
|
||||
aSClod5Yosf4SJbCFd/s5Iyfv52NqsAyp1w3Aj/BAoGAVCnEiGUfyHlIR+UH4zZW
|
||||
GXJMeqdZLfcEIszMxLePkml4gUQhoq9oIs/Kw+L1DDxUwzkXN4BNTlFbOSu9gzK1
|
||||
dhuIUGfS6RPL88U+ivC3A0y2jT43oUMqe3hiRt360UQ1GXzp2dMnR9odSRB1wHoO
|
||||
IOjEBZ8341/c9ZHc5PCGAG8=
|
||||
-----END PRIVATE KEY-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIID7zCCAtegAwIBAgIJAIrEIthCfxUCMA0GCSqGSIb3DQEBCwUAMIGNMQswCQYD
|
||||
VQQGEwJFUzEPMA0GA1UECAwGTWFkcmlkMREwDwYDVQQHDAhBbGNvcmNvbjEMMAoG
|
||||
A1UECgwDVURTMQ4wDAYDVQQLDAVBY3RvcjESMBAGA1UEAwwJVURTIEFjdG9yMSgw
|
||||
JgYJKoZIhvcNAQkBFhlzdXBwb3J0QHVkc2VudGVycHJpc2UuY29tMB4XDTE0MTAy
|
||||
NjIzNDEyNFoXDTI0MTAyMzIzNDEyNFowgY0xCzAJBgNVBAYTAkVTMQ8wDQYDVQQI
|
||||
DAZNYWRyaWQxETAPBgNVBAcMCEFsY29yY29uMQwwCgYDVQQKDANVRFMxDjAMBgNV
|
||||
BAsMBUFjdG9yMRIwEAYDVQQDDAlVRFMgQWN0b3IxKDAmBgkqhkiG9w0BCQEWGXN1
|
||||
cHBvcnRAdWRzZW50ZXJwcmlzZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
|
||||
ggEKAoIBAQCb50K3mIznNklzyVAD7xSQOSJQ6+NPXj7U9/4zLZ+TvmbQ7RqUUsxb
|
||||
fxHbeRnoYTWV2nKk4+tHqmvzujLSS/loFhTSMqtrLn7rowSYJoQhKOUkAiQlWkqC
|
||||
fItWgL5pJopDpNHFul9Rn3dsPMWQTiGeUNR4Y3RnBhr1Q1BsqAzf4m6zFUmgLPPm
|
||||
VLdF4uJ3Tuz8TSy2gWLs5aSr5do4WamwUfYjRSVMJECmwjUM4rQ8SQgg0sHBeBuD
|
||||
UGNBvBQFac1G7qUcMReeu8ZrDUtMsXma/l4rA8NB5CRmTrQbTBF4l+jb2BDFebDq
|
||||
DUK1Oqs9X35yOQfDOAFYHiixPX0IsXOZAgMBAAGjUDBOMB0GA1UdDgQWBBRShS90
|
||||
5lJTNvYPIEqP3GxWwG5iiDAfBgNVHSMEGDAWgBRShS905lJTNvYPIEqP3GxWwG5i
|
||||
iDAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAU0Sp4gXhQmRVzq+7+
|
||||
vRFUkQuPj4Ga/d9r5Wrbg3hck3+5pwe9/7APoq0P/M0DBhQpiJKjrD6ydUevC+Y/
|
||||
43ZOJPhMlNw0o6TdQxOkX6FDwQanLLs7sfvJvqtVzYn3nuRFKT3dvl7Zg44QMw2M
|
||||
ay42q59fAcpB4LaDx/i7gOYSS5eca3lYW7j7YSr/+ozXK2KlgUkuCUHN95lOq+dF
|
||||
trmV9mjzM4CNPZqKSE7kpHRywgrXGPCO000NvEGSYf82AtgRSFKiU8NWLQSEPdcB
|
||||
k//2dsQZw2cRZ8DrC2B6Tb3M+3+CA6wVyqfqZh1SZva3LfGvq/C+u+ItguzPqNpI
|
||||
xtvM
|
||||
-----END CERTIFICATE-----'''
|
||||
with open(certFile, "wt") as f:
|
||||
f.write(certData)
|
||||
|
||||
return certFile
|
||||
|
||||
class HTTPServerHandler(BaseHTTPRequestHandler):
|
||||
service = None
|
||||
protocol_version = 'HTTP/1.0'
|
||||
server_version = 'OpenGnsys Test REST Server'
|
||||
sys_version = ''
|
||||
|
||||
def sendJsonError(self, code, message):
|
||||
self.send_response(code)
|
||||
self.send_header('Content-type', 'application/json')
|
||||
self.end_headers()
|
||||
self.wfile.write(json.dumps({'error': message}))
|
||||
return
|
||||
|
||||
def sendJsonResponse(self, data):
|
||||
self.send_response(200)
|
||||
data = json.dumps(data)
|
||||
self.send_header('Content-type', 'application/json')
|
||||
self.send_header('Content-Length', len(data))
|
||||
self.end_headers()
|
||||
# Send the html message
|
||||
self.wfile.write(data)
|
||||
|
||||
|
||||
# parseURL
|
||||
def parseUrl(self):
|
||||
# Very simple path & params splitter
|
||||
path = self.path.split('?')[0][1:].split('/')
|
||||
|
||||
try:
|
||||
params = dict((v[0], unquote(v[1])) for v in (v.split('=') for v in self.path.split('?')[1].split('&')))
|
||||
except Exception:
|
||||
params = {}
|
||||
|
||||
return (path, params)
|
||||
|
||||
|
||||
def do_GET(self):
|
||||
path, params = self.parseUrl()
|
||||
|
||||
self.sendJsonResponse({'path': path, 'params': params})
|
||||
|
||||
def do_POST(self):
|
||||
path, getParams = self.parseUrl()
|
||||
|
||||
# Now post parameters, that are in JSON format
|
||||
self.sendJsonResponse({'path': path, 'params': getParams})
|
||||
|
||||
def log_error(self, fmt, *args):
|
||||
logger.error('HTTP ' + fmt % args)
|
||||
|
||||
def log_message(self, fmt, *args):
|
||||
logger.info('HTTP ' + fmt % args)
|
||||
|
||||
|
||||
class HTTPThreadingServer(ThreadingMixIn, HTTPServer):
|
||||
pass
|
||||
|
||||
class HTTPServerThread(threading.Thread):
|
||||
def __init__(self, address, service):
|
||||
super(self.__class__, self).__init__()
|
||||
|
||||
HTTPServerHandler.service = service
|
||||
|
||||
self.certFile = createSelfSignedCert()
|
||||
self.server = HTTPThreadingServer(address, HTTPServerHandler)
|
||||
self.server.socket = ssl.wrap_socket(self.server.socket, certfile=self.certFile, server_side=True)
|
||||
|
||||
logger.info('Initialized HTTPS Server thread on {}'.format(address))
|
||||
|
||||
def getServerUrl(self):
|
||||
return 'https://{}:{}/{}'.format(self.server.server_address[0], self.server.server_address[1], HTTPServerHandler.uuid)
|
||||
|
||||
def stop(self):
|
||||
self.server.shutdown()
|
||||
|
||||
def run(self):
|
||||
self.server.serve_forever()
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
logging.basicConfig(
|
||||
filename='/tmp/restserver.log',
|
||||
filemode='w',
|
||||
format='%(levelname)s %(asctime)s %(message)s',
|
||||
level=logging.DEBUG
|
||||
)
|
||||
|
||||
thr = HTTPServerThread(('0.0.0.0', 9999), None)
|
||||
print('Server started: {}'.format(thr))
|
||||
thr.run()
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Copyright (c) 2014 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
function process {
|
||||
pyuic4 about-dialog.ui -o about_dialog_ui.py -x
|
||||
pyuic4 message-dialog.ui -o message_dialog_ui.py -x
|
||||
}
|
||||
|
||||
pyrcc4 -py3 OGAgent.qrc -o OGAgent_rc.py
|
||||
|
||||
|
||||
# process current directory ui's
|
||||
process
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
#!/bin/bash
|
||||
export WINEARCH=win32
|
||||
export WINEPREFIX=$(realpath $(dirname $0)/wine)
|
||||
wine cmd /c c:\\ogagent\\build.bat
|
|
@ -0,0 +1,6 @@
|
|||
C:
|
||||
CD \ogagent\src
|
||||
python setup.py
|
||||
CD ..
|
||||
"C:\Program Files\NSIS\makensis.exe" ogagent.nsi
|
||||
|
|
@ -0,0 +1,184 @@
|
|||
# We need http://nsis.sourceforge.net/NSIS_Simple_Firewall_Plugin
|
||||
# Copy inside the two x86_xxxxx folders inside nsis plugins folder
|
||||
Name "OpenGnSys Agent"
|
||||
|
||||
# OpenGnsys Actor version
|
||||
!define OGA_VERSION 1.0.0
|
||||
|
||||
# General Symbol Definitions
|
||||
!define REGKEY "SOFTWARE\OGAgent"
|
||||
!define VERSION ${OGA_VERSION}.0
|
||||
!define COMPANY "Virtual Cable S.L.U."
|
||||
!define URL http://www.udsenterprise.com
|
||||
|
||||
# MultiUser Symbol Definitions
|
||||
!define MULTIUSER_EXECUTIONLEVEL Admin
|
||||
#!define MULTIUSER_INSTALLMODE_DEFAULT_CURRENTUSER
|
||||
!define MULTIUSER_INSTALLMODE_COMMANDLINE
|
||||
!define MULTIUSER_INSTALLMODE_INSTDIR OGAgent
|
||||
!define MULTIUSER_INSTALLMODE_INSTDIR_REGISTRY_KEY "${REGKEY}"
|
||||
!define MULTIUSER_INSTALLMODE_INSTDIR_REGISTRY_VALUE "Path"
|
||||
|
||||
# MUI Symbol Definitions
|
||||
#!define MUI_ICON "${NSISDIR}\Contrib\Graphics\Icons\orange-install.ico"
|
||||
!define MUI_ICON "src\img\oga.ico"
|
||||
!define MUI_FINISHPAGE_NOAUTOCLOSE
|
||||
!define MUI_UNICON "src\img\oga.ico"
|
||||
!define MUI_UNFINISHPAGE_NOAUTOCLOSE
|
||||
!define MUI_LANGDLL_REGISTRY_ROOT HKLM
|
||||
!define MUI_LANGDLL_REGISTRY_KEY ${REGKEY}
|
||||
!define MUI_LANGDLL_REGISTRY_VALUENAME InstallerLanguage
|
||||
|
||||
# Included files
|
||||
!include MultiUser.nsh
|
||||
!include Sections.nsh
|
||||
!include MUI2.nsh
|
||||
|
||||
# Reserved Files
|
||||
!insertmacro MUI_RESERVEFILE_LANGDLL
|
||||
|
||||
# Variables
|
||||
Var StartMenuGroup
|
||||
|
||||
# Installer pages
|
||||
!insertmacro MUI_PAGE_WELCOME
|
||||
!insertmacro MUI_PAGE_LICENSE src\license.txt
|
||||
!insertmacro MUI_PAGE_DIRECTORY
|
||||
!insertmacro MUI_PAGE_INSTFILES
|
||||
!insertmacro MUI_PAGE_FINISH
|
||||
!insertmacro MUI_UNPAGE_CONFIRM
|
||||
!insertmacro MUI_UNPAGE_INSTFILES
|
||||
|
||||
# Installer languages
|
||||
!insertmacro MUI_LANGUAGE English
|
||||
!insertmacro MUI_LANGUAGE Spanish
|
||||
!insertmacro MUI_LANGUAGE French
|
||||
!insertmacro MUI_LANGUAGE German
|
||||
|
||||
# Installer attributes
|
||||
BrandingText "OpenGnSys"
|
||||
OutFile OGAgentSetup-${OGA_VERSION}.exe
|
||||
InstallDir OGAgent
|
||||
CRCCheck on
|
||||
XPStyle on
|
||||
ShowInstDetails hide
|
||||
VIProductVersion "${VERSION}.0.0"
|
||||
VIAddVersionKey /LANG=${LANG_ENGLISH} ProductName "OGAgent"
|
||||
VIAddVersionKey /LANG=${LANG_ENGLISH} ProductVersion "${VERSION}"
|
||||
VIAddVersionKey /LANG=${LANG_ENGLISH} CompanyName "${COMPANY}"
|
||||
VIAddVersionKey /LANG=${LANG_ENGLISH} CompanyWebsite "${URL}"
|
||||
VIAddVersionKey /LANG=${LANG_ENGLISH} FileVersion "${VERSION}"
|
||||
VIAddVersionKey /LANG=${LANG_ENGLISH} FileDescription "OpenGnSys Agent installer"
|
||||
VIAddVersionKey /LANG=${LANG_ENGLISH} LegalCopyright "(c) 2015 Virtual Cable S.L.U."
|
||||
InstallDirRegKey HKLM "${REGKEY}" Path
|
||||
ShowUninstDetails show
|
||||
|
||||
# Installer sections
|
||||
Section -Main SEC0000
|
||||
SetShellVarContext all
|
||||
SetOutPath $INSTDIR
|
||||
SetOverwrite on
|
||||
File /r bin\*.*
|
||||
File vcredist_x86.exe
|
||||
WriteRegStr HKLM "${REGKEY}\Components" Main 1
|
||||
SectionEnd
|
||||
|
||||
Section -post SEC0001
|
||||
SetShellVarContext current
|
||||
WriteRegStr HKLM "${REGKEY}" Path $INSTDIR
|
||||
SetOutPath $INSTDIR
|
||||
WriteUninstaller $INSTDIR\OGAgentUninstaller.exe
|
||||
SetOutPath $SMPROGRAMS\$StartMenuGroup
|
||||
CreateShortcut "$SMPROGRAMS\$StartMenuGroup\$(^UninstallLink).lnk" $INSTDIR\OGAgentUninstaller.exe
|
||||
WriteRegStr HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" DisplayName "$(^Name)"
|
||||
WriteRegStr HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" DisplayVersion "${VERSION}"
|
||||
WriteRegStr HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" Publisher "${COMPANY}"
|
||||
WriteRegStr HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" URLInfoAbout "${URL}"
|
||||
WriteRegStr HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" DisplayIcon $INSTDIR\OGAgentUninstaller.exe
|
||||
WriteRegStr HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" UninstallString $INSTDIR\OGAgentUninstaller.exe
|
||||
WriteRegStr HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Run" OGAgentTool $INSTDIR\OGAgentUser.exe
|
||||
WriteRegDWORD HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" NoModify 1
|
||||
WriteRegDWORD HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" NoRepair 1
|
||||
ExecWait '"$INSTDIR\vcredist_x86.exe" /passive /norestart'
|
||||
# Add the application to the firewall exception list - All Networks - All IP Version - Enabled
|
||||
# SimpleFC::AddApplication "OpenGnSys Agent Service" "$INSTDIR\OGAgentService.exe" 0 2 "" 1
|
||||
# SimpleFC::AdvAddRule [name] [description] [protocol] [direction]
|
||||
# [status] [profile] [action] [application] [service_name] [icmp_types_and_codes]
|
||||
# [group] [local_ports] [remote_ports] [local_address] [remote_address]
|
||||
#
|
||||
SimpleFC::AdvAddRule "OpenGnSys Agent Firewall rules" "Firewall rules for OpenGnSys Agent interaction with broker." "6" "1" \
|
||||
"1" "7" "1" "$INSTDIR\OGAgentService.exe" "" "" \
|
||||
"" "" "" "" ""
|
||||
Pop $0 ; return error(1)/success(0)
|
||||
# Install service
|
||||
nsExec::Exec /OEM "$INSTDIR\OGAgentService.exe --startup auto install" # Add service after installation
|
||||
# Update recovery options
|
||||
nsExec::Exec /OEM "$INSTDIR\OGAServiceHelper.exe"
|
||||
SectionEnd
|
||||
|
||||
# Macro for selecting uninstaller sections
|
||||
!macro SELECT_UNSECTION SECTION_NAME UNSECTION_ID
|
||||
Push $R0
|
||||
ReadRegStr $R0 HKLM "${REGKEY}\Components" "${SECTION_NAME}"
|
||||
StrCmp $R0 1 0 next${UNSECTION_ID}
|
||||
!insertmacro SelectSection "${UNSECTION_ID}"
|
||||
GoTo done${UNSECTION_ID}
|
||||
next${UNSECTION_ID}:
|
||||
!insertmacro UnselectSection "${UNSECTION_ID}"
|
||||
done${UNSECTION_ID}:
|
||||
Pop $R0
|
||||
!macroend
|
||||
|
||||
# Uninstaller sections
|
||||
Section /o -un.Main UNSEC0000
|
||||
nsExec::Exec /OEM "$INSTDIR\OGAgentService.exe stop" # Stops the service prior uninstall
|
||||
nsExec::Exec /OEM "$INSTDIR\OGAgentService.exe remove" # Removes the service prior uninstall
|
||||
Delete /REBOOTOK "$INSTDIR\*.*"
|
||||
DeleteRegValue HKLM "${REGKEY}\Components" Main
|
||||
DeleteRegValue HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Run" OGAgentTool
|
||||
SectionEnd
|
||||
|
||||
Section -un.post UNSEC0001
|
||||
# Remove application from the firewall exception list
|
||||
# SimpleFC::RemoveApplication "$INSTDIR\OGAgentService.exe"
|
||||
SimpleFC::AdvRemoveRule "OpenGnSys Agent Firewall rules"
|
||||
Pop $0 ; return error(1)/success(0)
|
||||
|
||||
SetShellVarContext current
|
||||
StrCpy $StartMenuGroup "OpenGnSys Agent"
|
||||
DeleteRegKey HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)"
|
||||
Delete /REBOOTOK "$SMPROGRAMS\$StartMenuGroup\$(^UninstallLink).lnk"
|
||||
Delete /REBOOTOK $INSTDIR\OGAgentUninstaller.exe
|
||||
DeleteRegValue HKLM "${REGKEY}" Path
|
||||
DeleteRegKey /IfEmpty HKLM "${REGKEY}\Components"
|
||||
DeleteRegKey /IfEmpty HKLM "${REGKEY}"
|
||||
RmDir /REBOOTOK $SMPROGRAMS\$StartMenuGroup
|
||||
SetShellVarContext all
|
||||
RmDir /REBOOTOK $INSTDIR
|
||||
SetRebootFlag true
|
||||
MessageBox MB_OK|MB_USERICON "Your system needs to reboot to complete uninstallation."
|
||||
Reboot # Reboot is needed after uninstalling, so new installs works fine
|
||||
SectionEnd
|
||||
|
||||
# Installer functions
|
||||
Function .onInit
|
||||
InitPluginsDir
|
||||
StrCpy $StartMenuGroup "OpenGnSys Agent"
|
||||
|
||||
!insertmacro MUI_LANGDLL_DISPLAY
|
||||
!insertmacro MULTIUSER_INIT
|
||||
FunctionEnd
|
||||
|
||||
# Uninstaller functions
|
||||
Function un.onInit
|
||||
StrCpy $StartMenuGroup "OpenGnSys Agent"
|
||||
!insertmacro MUI_UNGETLANGUAGE
|
||||
!insertmacro MULTIUSER_UNINIT
|
||||
!insertmacro SELECT_UNSECTION Main ${UNSEC0000}
|
||||
FunctionEnd
|
||||
|
||||
# Installer Language Strings
|
||||
LangString ^UninstallLink ${LANG_ENGLISH} "Uninstall $(^Name)"
|
||||
LangString ^UninstallLink ${LANG_SPANISH} "Desinstalar $(^Name)"
|
||||
LangString ^UninstallLink ${LANG_FRENCH} "D<>sinstaller $(^Name)"
|
||||
LangString ^UninstallLink ${LANG_GERMAN} "deinstallieren $(^Name)"
|
|
@ -0,0 +1,72 @@
|
|||
#!/bin/sh
|
||||
|
||||
# We need:
|
||||
# * Wine (32 bit)
|
||||
# * winetricks
|
||||
|
||||
export WINEARCH=win32
|
||||
WINE=wine
|
||||
|
||||
download() {
|
||||
mkdir downloads
|
||||
# Get needed software
|
||||
cd downloads
|
||||
wget -nd https://www.python.org/ftp/python/2.7.10/python-2.7.10.msi
|
||||
wget -nd http://download.microsoft.com/download/7/9/6/796EF2E4-801B-4FC4-AB28-B59FBF6D907B/VCForPython27.msi
|
||||
wget -nd https://bootstrap.pypa.io/get-pip.py
|
||||
wget -nd http://sourceforge.net/projects/pywin32/files/pywin32/Build%20219/pywin32-219.win32-py2.7.exe/download -O pywin32-install.exe
|
||||
wget -nd http://sourceforge.net/projects/py2exe/files/py2exe/0.6.9/py2exe-0.6.9.win32-py2.7.exe/download -O py2exe-install.exe
|
||||
wget -nd http://prdownloads.sourceforge.net/nsis/nsis-3.0b1-setup.exe?download -O nsis-install.exe
|
||||
wget -nd http://sourceforge.net/projects/pyqt/files/PyQt4/PyQt-4.11.4/PyQt4-4.11.4-gpl-Py2.7-Qt4.8.7-x32.exe/download -O pyqt-install.exe
|
||||
wget -nd http://nsis.sourceforge.net/mediawiki/images/d/d7/NSIS_Simple_Firewall_Plugin_1.20.zip
|
||||
cd ..
|
||||
}
|
||||
|
||||
install_python() {
|
||||
WINEPREFIX=`pwd`/wine
|
||||
export WINEPREFIX
|
||||
echo "Setting up wine prefix (using winetricks)"
|
||||
winetricks
|
||||
|
||||
cd downloads
|
||||
echo "Installing python"
|
||||
$WINE msiexec /qn /i python-2.7.10.msi
|
||||
echo "Installing vc for python"
|
||||
$WINE msiexec /qn /i VCForPython27.msi
|
||||
|
||||
echo "Installing pywin32 (needs X)"
|
||||
$WINE pywin32-install.exe
|
||||
echo "Installing py2exe (needs X)"
|
||||
$WINE py2exe-install.exe
|
||||
echo "Installing pyqt"
|
||||
$WINE pyqt-install.exe
|
||||
echo "Installing nsis (needs X?)"
|
||||
$WINE nsis-install.exe
|
||||
|
||||
cd ..
|
||||
}
|
||||
|
||||
setup_pip() {
|
||||
echo "Seting up pip..."
|
||||
#mkdir $WINEPREFIX/drive_c/temp
|
||||
#cp downloads/get-pip.py $WINEPREFIX/drive_c/temp
|
||||
#cd $WINEPREFIX/drive_c/temp
|
||||
#$WINE c:\\Python27\\python.exe get-pip.py
|
||||
wine c:\\Python27\\python -m pip install --upgrade pip
|
||||
}
|
||||
|
||||
install_packages() {
|
||||
echo "Installing required packages"
|
||||
wine c:\\Python27\\python -m pip install requests pycrypto six
|
||||
# Copy nsis required NSIS_Simple_Firewall_Plugin_1
|
||||
echo "Copying simple firewall plugin for nsis installer"
|
||||
unzip -o downloads/NSIS_Simple_Firewall_Plugin_1.20.zip SimpleFC.dll -d $WINEPREFIX/drive_c/Program\ Files/NSIS/Plugins/x86-ansi/
|
||||
unzip -o downloads/NSIS_Simple_Firewall_Plugin_1.20.zip SimpleFC.dll -d $WINEPREFIX/drive_c/Program\ Files/NSIS/Plugins/x86-unicode/
|
||||
}
|
||||
|
||||
download
|
||||
install_python
|
||||
setup_pip
|
||||
install_packages
|
||||
|
||||
|
Loading…
Reference in New Issue