Compare commits

...

86 Commits
main ... oglive

Author SHA1 Message Date
Ramón M. Gómez eb2c5f8768 #908: Fast-forward branch. 2020-05-20 14:23:02 +02:00
Ramón M. Gómez a0bd02cdc4 #930: Fast-forward the branch 2020-01-15 10:39:27 +01:00
Ramón M. Gómez a3f2b23e80 #930: OGAgent for ogLive can launch the Browser. 2020-01-15 09:48:26 +01:00
Juan Manuel Bardallo fb1405778b Bug fixed when out and err are None in operation exec_command 2020-01-15 09:46:55 +01:00
Ramón M. Gómez 53f167e585 #908: Trying to fix a bug when obteining execution outputs. 2020-01-15 09:46:55 +01:00
Ramón M. Gómez 3c08c36716 #761: OGAGent checks for dobule slash before connecting to REST URL. 2020-01-15 09:45:41 +01:00
Ramón M. Gómez 4d89f8218e #750: Simple REST route to get the list of running commands. 2020-01-15 09:44:19 +01:00
Ramón M. Gómez 15eb6949ce #750: Using PEP 8 Style Guide for Python in new module; implementing basic {{{getconfig}}} operation. 2020-01-15 09:43:38 +01:00
Ramón M. Gómez e140d8d037 #750: Process to build OGAgent for ogLive package. 2020-01-15 09:43:38 +01:00
Ramón M. Gómez 0fbb893e75 #750: Adapting route {{GET /command}}} parameters. 2020-01-15 09:42:43 +01:00
Ramón M. Gómez d1b88b05ee #750: Using more descriptive status; new route {{{POST /command}}} to launch command/script in a callback thread that returns all data to a server route. 2020-01-15 09:40:07 +01:00
Ramón M. Gómez dc8c12bf6e #750: Using PEP 8 Style Guide for Python in new module; implementing basic {{{getconfig}}} operation. 2020-01-15 09:32:59 +01:00
Ramón M. Gómez b8d05a72c6 #750: Process to build OGAgent for ogLive package. 2020-01-15 09:29:07 +01:00
Ramón M. Gómez bb549c7878 #930: Correct some typos. 2020-01-15 09:24:46 +01:00
Ramón M. Gómez a648e3fbbe #930: Remove duplicate code and fix some typos. 2020-01-15 09:24:46 +01:00
Ramón M. Gómez d8ba7b2bf0 #930: OGAgent for ogLive can launch the Browser. 2020-01-15 09:24:46 +01:00
Ramón M. Gómez b9ed5ca8f6 #908 OGAgent for ogLive launches the Browser with an animation while getting initial configuration. 2020-01-15 09:24:46 +01:00
Juan Manuel Bardallo 8055b1358a Bug fixed when out and err are None in operation exec_command 2020-01-15 09:24:46 +01:00
Ramón M. Gómez 2ac6daa3f5 #908: Trying to fix a bug when obteining execution outputs. 2020-01-15 09:24:46 +01:00
Ramón M. Gómez 16c3792567 #761: OGAgent launchs client's default menu on activation process. 2020-01-15 09:24:46 +01:00
Ramón M. Gómez 8ef3e73b9e #908 OGAgent for ogLive code clean up. 2020-01-15 09:24:46 +01:00
Ramón M. Gómez bdfcb0d1fe #761: OGAGent checks for dobule slash before connecting to REST URL. 2020-01-15 09:24:46 +01:00
Ramón M. Gómez 198088d7f4 #750: Using PEP 8 Style Guide for Python in new module; implementing basic {{{getconfig}}} operation. 2020-01-14 14:10:42 +01:00
Ramón M. Gómez ecf49815c1 #750: Process to build OGAgent for ogLive package. 2020-01-14 12:02:30 +01:00
Ramón M. Gómez ae813486ce #750: Renaming server REST route {{{GET /done}}} to {{{GET /command_done}}} to log commands executed on clients. 2020-01-14 11:58:38 +01:00
Ramón M. Gómez 85f395ee78 #750: Adapting route {{GET /command}}} parameters. 2020-01-14 11:58:38 +01:00
Ramón M. Gómez 633c90c26e #750: Simple REST route to get the list of running commands. 2020-01-14 11:57:34 +01:00
Ramón M. Gómez ddd54eea4b #750: Using more descriptive status; new route {{{POST /command}}} to launch command/script in a callback thread that returns all data to a server route. 2020-01-14 11:56:33 +01:00
Ramón M. Gómez f0c847c35f #750: Route {{{GET /getconfig}}} renamed as {{{GET /config}}}; route {{{GET /hardware}}} returns data in JSON format; new basic route {{{GET /software?disk=NDisk&part=NPart}}} 2020-01-14 11:53:59 +01:00
Ramón M. Gómez 863e038f24 #750: New route {{{GET /hardware}}}. 2020-01-14 11:53:59 +01:00
Ramón M. Gómez bb1ff4dc1d #750: OGAgent for ogLive looks for {{{oglive}}} environ variable; route {{{GET /getconfig}}} returns data in JSON format. 2020-01-14 11:53:59 +01:00
Ramón M. Gómez be334a5c17 #750: Using PEP 8 Style Guide for Python in new module; implementing basic {{{getconfig}}} operation. 2020-01-14 11:53:09 +01:00
Ramón M. Gómez 983213c9df #750: Process to build OGAgent for ogLive package. 2020-01-14 11:05:44 +01:00
Ramón M. Gómez 7b07f5c983 #930: OGAgent `GET /script` route accepts a new optional `send_config` parameter to send back the client configuration after command execution. 2019-12-12 12:07:22 +01:00
Ramón M. Gómez 37c8fb71d4 #930: Correct some typos. 2019-12-12 11:23:17 +01:00
Ramón M. Gómez c3cd292d0d #930: Remove duplicate code and fix some typos. 2019-12-12 11:23:17 +01:00
Ramón M. Gómez 582ab7873b #930: OGAgent for ogLive can launch the Browser. 2019-12-12 11:20:05 +01:00
Ramón M. Gómez 3642196f14 #908 OGAgent for ogLive launches the Browser with an animation while getting initial configuration. 2019-12-12 11:17:20 +01:00
Juan Manuel Bardallo f3f6b350bc Bug fixed when out and err are None in operation exec_command 2019-12-12 11:17:20 +01:00
Ramón M. Gómez 10c30f9fca #908: Trying to fix a bug when obteining execution outputs. 2019-12-12 11:17:20 +01:00
Ramón M. Gómez 7ad4f2f559 #761: OGAgent launchs client's default menu on activation process. 2019-12-12 11:17:20 +01:00
Ramón M. Gómez f2c21d888a #908 OGAgent for ogLive code clean up. 2019-12-12 11:17:20 +01:00
Ramón M. Gómez 65c74510f7 #761: OGAGent checks for dobule slash before connecting to REST URL. 2019-12-12 11:10:05 +01:00
Ramón M. Gómez 1cfe9dc9db #750: Simple REST route to get the list of running commands. 2019-12-12 11:08:35 +01:00
Ramón M. Gómez 3c5a6993d7 #750: Using PEP 8 Style Guide for Python in new module; implementing basic {{{getconfig}}} operation. 2019-12-12 10:42:23 +01:00
Ramón M. Gómez 079b250bb1 #750: Process to build OGAgent for ogLive package. 2019-12-12 10:14:13 +01:00
Ramón M. Gómez 0e7fbadeb9 #750: Renaming server REST route {{{GET /done}}} to {{{GET /command_done}}} to log commands executed on clients. 2019-12-12 10:05:29 +01:00
Ramón M. Gómez f01a01aee4 #750: Adapting route {{GET /command}}} parameters. 2019-12-12 10:05:29 +01:00
Ramón M. Gómez dcc3b83968 #750: Simple REST route to get the list of running commands. 2019-12-12 10:02:13 +01:00
Ramón M. Gómez dfd2c05275 #750: Using more descriptive status; new route {{{POST /command}}} to launch command/script in a callback thread that returns all data to a server route. 2019-12-12 09:57:41 +01:00
Ramón M. Gómez ae066d2d6c #750: Route {{{GET /getconfig}}} renamed as {{{GET /config}}}; route {{{GET /hardware}}} returns data in JSON format; new basic route {{{GET /software?disk=NDisk&part=NPart}}} 2019-12-12 09:53:34 +01:00
Ramón M. Gómez 8d427bb0d0 #750: New route {{{GET /hardware}}}. 2019-12-12 09:53:34 +01:00
Ramón M. Gómez 8e4fedd75e #750: OGAgent for ogLive looks for {{{oglive}}} environ variable; route {{{GET /getconfig}}} returns data in JSON format. 2019-12-12 09:53:34 +01:00
Ramón M. Gómez 81a9b65d79 #750: Using PEP 8 Style Guide for Python in new module; implementing basic {{{getconfig}}} operation. 2019-12-12 09:50:15 +01:00
Ramón M. Gómez 88d3c4642b #750: Process to build OGAgent for ogLive package. 2019-12-12 09:28:18 +01:00
Ramón M. Gómez 85057befc1 #930: Correct some typos. 2019-12-02 18:43:52 +01:00
Ramón M. Gómez 888f92a60e Merge branch 'master' into ogagent-oglive 2019-12-02 18:15:13 +01:00
Ramón M. Gómez 40402bd267 #930: Remove duplicate code and fix some typos. 2019-09-30 14:22:21 +02:00
Ramón M. Gómez b3bdeb414e #930: OGAgent for ogLive can launch the Browser. 2019-09-30 13:27:04 +02:00
Ramón M. Gómez 1954ef5cfa #908 OGAgent for ogLive launches the Browser with an animation while getting initial configuration. 2019-09-30 11:53:50 +02:00
Juan Manuel Bardallo d0a7766b08 Bug fixed when out and err are None in operation exec_command 2019-09-30 11:35:00 +02:00
Ramón M. Gómez a5117cbf55 #908: Trying to fix a bug when obteining execution outputs. 2019-09-30 11:33:35 +02:00
Ramón M. Gómez f24fea2a9c #761: OGAgent launchs client's default menu on activation process. 2019-09-30 11:32:36 +02:00
Ramón M. Gómez 221bcd14cc #908 OGAgent for ogLive code clean up. 2019-09-30 11:26:01 +02:00
Ramón M. Gómez 01adfee493 #761: OGAGent checks for dobule slash before connecting to REST URL. 2019-09-30 11:20:51 +02:00
Ramón M. Gómez cb1fb02df5 #750: Fast forward branch 2019-09-30 11:04:46 +02:00
Ramón M. Gómez 46d3308a5f #750: Renaming server REST route {{{GET /done}}} to {{{GET /command_done}}} to log commands executed on clients. 2019-09-30 10:58:04 +02:00
Ramón M. Gómez a0ce0fc9ea #750: Adapting route {{GET /command}}} parameters. 2019-09-30 10:58:04 +02:00
Ramón M. Gómez aab7ec58aa #750: Simple REST route to get the list of running commands. 2019-09-30 10:57:24 +02:00
Ramón M. Gómez 2af37100e0 #750: Using more descriptive status; new route {{{POST /command}}} to launch command/script in a callback thread that returns all data to a server route. 2019-09-30 10:54:04 +02:00
Ramón M. Gómez 9e81e9020c #750: Route {{{GET /getconfig}}} renamed as {{{GET /config}}}; route {{{GET /hardware}}} returns data in JSON format; new basic route {{{GET /software?disk=NDisk&part=NPart}}} 2019-09-30 10:49:25 +02:00
Ramón M. Gómez a5905575e2 #750: New route {{{GET /hardware}}}. 2019-09-30 10:49:25 +02:00
Ramón M. Gómez 149d1bdc4f #750: OGAgent for ogLive looks for {{{oglive}}} environ variable; route {{{GET /getconfig}}} returns data in JSON format. 2019-09-30 10:49:25 +02:00
Ramón M. Gómez 70ce2377da #750: Using PEP 8 Style Guide for Python in new module; implementing basic {{{getconfig}}} operation. 2019-09-30 10:47:52 +02:00
Ramón M. Gómez cf4de0c2d2 #750: Process to build OGAgent for ogLive package. 2019-09-30 10:40:22 +02:00
Ramón M. Gómez 1ff2475ee3 #750: OGAgent activation and deactivation now compatible with new web console. 2019-04-09 10:52:05 +02:00
Ramón M. Gómez 417f9497dd #750: Fast-forward. 2018-11-26 13:09:55 +01:00
Ramón M. Gómez da9bd96ec8 #750: Renaming server REST route {{{GET /done}}} to {{{GET /command_done}}} to log commands executed on clients. 2018-07-05 13:50:17 +02:00
Ramón M. Gómez 91bdf9040d #750: Adapting route {{GET /command}}} parameters. 2018-07-04 12:15:50 +02:00
Ramón M. Gómez 3806f120c6 #750: Simple REST route to get the list of running commands. 2018-07-03 17:55:25 +02:00
Ramón M. Gómez 0c8032d137 #750: Using more descriptive status; new route {{{POST /command}}} to launch command/script in a callback thread that returns all data to a server route. 2018-06-30 17:13:45 +02:00
Ramón M. Gómez a108f36cff #750: Route {{{GET /getconfig}}} renamed as {{{GET /config}}}; route {{{GET /hardware}}} returns data in JSON format; new basic route {{{GET /software?disk=NDisk&part=NPart}}} 2018-06-21 19:23:10 +02:00
Ramón M. Gómez e5ba6cfc10 #750: New route {{{GET /hardware}}}. 2018-06-20 20:25:30 +02:00
Ramón M. Gómez 4272d559e7 #750: OGAgent for ogLive looks for {{{oglive}}} environ variable; route {{{GET /getconfig}}} returns data in JSON format. 2018-06-20 19:48:49 +02:00
Ramón M. Gómez 0a085de592 #750: Using PEP 8 Style Guide for Python in new module; implementing basic {{{getconfig}}} operation. 2018-06-18 20:47:35 +02:00
Ramón M. Gómez e20838c641 #750: Process to build OGAgent for ogLive package. 2018-06-18 13:54:44 +02:00
25 changed files with 1014 additions and 75 deletions

View File

@ -68,6 +68,4 @@ ifeq ($(DISTRO),rh)
endif
uninstall:
rm -rf $(LIBDIR)
# rm -f $(BINDIR)/ogagent
rm -rf $(CFGDIR)
rm -rf $(LIBDIR) $(CFGDIR) $(BINDIR)/ogagent $(INITDIR)/ogagent

42
oglive/Makefile 100644
View File

@ -0,0 +1,42 @@
#!/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
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 $(LIBDIR)/img
# Cleans up .pyc and cache folders
rm -f $(PYC) $(CACHES)
cp -r $(SOURCEDIR)/opengnsys $(LIBDIR)/opengnsys
cp -r $(SOURCEDIR)/cfg $(LIBDIR)/cfg
ln -fs $(LIBDIR)/cfg/ogagent.cfg $(CFGDIR)
ln -fs $(LIBDIR)/cfg/ogclient.cfg $(CFGDIR)
cp scripts/ogagent $(BINDIR)
chmod 755 $(BINDIR)/ogagent
uninstall:
rm -rf $(LIBDIR)
rm -f $(BINDIR)/ogagent
rm -rf $(CFGDIR)

View File

@ -0,0 +1,7 @@
#!/bin/bash
cd $(dirname "$0")
# Build package
dpkg-buildpackage -b -d

View File

@ -0,0 +1,6 @@
ogagent-oglive (1.1.1) unstable; urgency=medium
* Initial release.
-- Ramón M. Gómez <ramongomez@us.es> Mon, 18 Jun 2018 13:00:00 +0200

View File

@ -0,0 +1 @@
9

View File

@ -0,0 +1,15 @@
Source: ogagent-oglive
Section: admin
Priority: optional
Maintainer: Ramón M. Gómez <ramongomez@us.es>
Build-Depends: debhelper (>= 7), po-debconf
Standards-Version: 3.9.2
Homepage: https://opengnsys.es
Package: ogagent-oglive
Section: admin
Priority: optional
Architecture: all
Depends: python-requests (>=0.8.2), python-six(>=1.1), python-prctl(>=1.1.1), python (>=2.7), libxss1, ${misc:Depends}
Description: OpenGnsys Agent for ogLive client
This package provides the required components to allow this machine to work on an environment managed by OpenGnsys.

View File

@ -0,0 +1,26 @@
Format-Specification: http://svn.debian.org/wsvn/dep/web/deps/dep5.mdwn?op=file&rev=135
Name: ogagent
Maintainer: Ramón M. Gómez
Source: https://opengnsys.es
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'.

View File

@ -0,0 +1 @@
readme.txt

View File

@ -0,0 +1,2 @@
/usr/share/OGAgent/cfg/ogagent.cfg /etc/ogagent/ogagent.cfg
/usr/share/OGAgent/cfg/ogclient.cfg /etc/ogagent/ogclient.cfg

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,2 @@
misc:Depends=
misc:Pre-Depends=

View File

@ -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

View File

@ -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-oglive 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

View File

@ -0,0 +1 @@
3.0 (native)

View File

@ -0,0 +1,3 @@
OGAgent is the agent intended for OpengGnsys interaction.
Please, visit https://opengnsys.es for more information

View File

@ -0,0 +1,6 @@
#!/bin/sh
FOLDER=/usr/share/OGAgent
cd $FOLDER
python -m opengnsys.linux.OGAgentService $@

View File

@ -1,9 +1,10 @@
<<<<<<< HEAD
<?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"
name="OGAgentService"
version="1.1.2.0"
processorArchitecture="x86"
/>
<description>Description</description>

View File

@ -155,11 +155,7 @@ def reboot(flags=0):
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'])
subprocess.call(['/sbin/reboot'])
def poweroff(flags=0):
@ -171,11 +167,7 @@ def poweroff(flags=0):
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'])
subprocess.call(['/sbin/poweroff'])
def logoff():

View File

@ -30,20 +30,21 @@
"""
from __future__ import unicode_literals
import threading
import os
import platform
import time
import random
import shutil
import signal
import string
import subprocess
import threading
import time
import urllib
from opengnsys.workers import ServerWorker
from opengnsys import REST, RESTError
from opengnsys import REST
from opengnsys import operations
from opengnsys.log import logger
from opengnsys.scriptThread import ScriptExecutorThread
from opengnsys.workers import ServerWorker
from six.moves.urllib import parse
# Check authorization header decorator
@ -51,6 +52,7 @@ def check_secret(fnc):
"""
Decorator to check for received secret key and raise exception if it isn't valid.
"""
def wrapper(*args, **kwargs):
try:
this, path, get_params, post_params, server = args # @UnusedVariable
@ -73,18 +75,100 @@ def catch_background_error(fnc):
fnc(*args, **kwargs)
except Exception as e:
this.REST.sendMessage('error?id={}'.format(kwargs.get('requestId', 'error')), {'error': '{}'.format(e)})
return wrapper
def check_locked_partition(sync=False):
"""
Decorator to check if a partition is locked
"""
def outer(fnc):
def wrapper(*args, **kwargs):
part_id = 'None'
try:
this, path, get_params, post_params, server = args # @UnusedVariable
part_id = post_params['disk'] + post_params['part']
if this.locked.get(part_id, False):
this.locked[part_id] = True
fnc(*args, **kwargs)
else:
return 'partition locked'
except Exception as e:
this.locked[part_id] = False
return 'error {}'.format(e)
finally:
if sync is True:
this.locked[part_id] = False
logger.debug('Lock status: {} {}'.format(fnc, this.locked))
return wrapper
return outer
class OpenGnSysWorker(ServerWorker):
name = 'opengnsys'
interface = None # Bound interface for OpenGnsys
REST = None # REST object
logged_in = False # User session flag
locked = {}
browser = {} # Browser info
commands = [] # Running commands
random = None # Random string for secure connections
length = 32 # Random string length
def _launch_browser(self, url):
"""
Launches the Browser with specified URL
:param url: URL to show
"""
logger.debug('Launching browser with URL: {}'.format(url))
# Trying to kill an old browser
try:
os.kill(self.browser['process'].pid, signal.SIGKILL)
except OSError:
logger.warn('Cannot kill the old browser process')
except KeyError:
# There is no previous browser
pass
self.browser['url'] = url
self.browser['process'] = subprocess.Popen(['browser', '-qws', url])
def _task_command(self, route, code, op_id, send_config=False):
"""
Task to execute a command and return results to a server URI
:param route: server callback REST route to return results
:param code: code to execute
:param op_id: operation id.
:param send_config: indicate if client will send configuration data after command execution
"""
menu_url = ''
# Show execution tacking log, if OGAgent runs on ogLive
os_type = operations.os_type.lower()
if os_type == 'oglive':
menu_url = self.browser['url']
self._launch_browser('http://localhost/cgi-bin/httpd-log.sh')
# Execute the code
(stat, out, err) = operations.exec_command(code)
# Remove command from the list
for c in self.commands:
if c.getName() == op_id:
self.commands.remove(c)
# Remove the REST API prefix, if needed
if route.startswith(self.REST.endpoint):
route = route[len(self.REST.endpoint):]
# Send back exit status and outputs (base64-encoded)
self.REST.sendMessage(route, {'mac': self.interface.mac, 'ip': self.interface.ip, 'trace': op_id,
'status': stat, 'output': out.encode('base64'), 'error': err.encode('base64')})
# Show latest menu, if OGAgent runs on ogLive
if os_type == 'oglive':
# Send configuration data, if needed
if send_config:
self.REST.sendMessage('ogagent/config', {'mac': self.interface.mac, 'ip': self.interface.ip,
'config': operations.get_configuration()})
self._launch_browser(menu_url)
def onActivation(self):
"""
Sends OGAgent activation notification to OpenGnsys server
@ -94,6 +178,12 @@ class OpenGnSysWorker(ServerWorker):
self.random = ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(self.length))
# Ensure cfg has required configuration variables or an exception will be thrown
url = self.service.config.get('opengnsys', 'remote')
if operations.os_type == 'ogLive' and 'oglive' in os.environ:
# Replacing server IP if it's running on ogLive client
logger.debug('Activating on ogLive client, new server is {}'.format(os.environ['oglive']))
url = parse.urlsplit(url)._replace(netloc=os.environ['oglive']).geturl()
if not url.endswith(os.path.sep):
url += os.path.sep
self.REST = REST(url)
# Get network interfaces until they are active or timeout (5 minutes)
for t in range(0, 300):
@ -134,18 +224,61 @@ class OpenGnSysWorker(ServerWorker):
logger.debug('Successful connection after {} tries'.format(t))
elif t == 100:
raise Exception('Initialization error: Cannot connect to remote server')
# Delete marking files
for f in ['ogboot.me', 'ogboot.firstboot', 'ogboot.secondboot']:
try:
os.remove(os.sep + f)
except OSError:
pass
# Copy file "HostsFile.FirstOctetOfIPAddress" to "HostsFile", if it exists
# (used in "exam mode" from the University of Seville)
hosts_file = os.path.join(operations.get_etc_path(), 'hosts')
new_hosts_file = hosts_file + '.' + self.interface.ip.split('.')[0]
if os.path.isfile(new_hosts_file):
shutil.copyfile(new_hosts_file, hosts_file)
# Completing OGAgent initialization process
os_type = operations.os_type.lower()
if os_type == 'oglive':
# # Following code may be separated into a different function to launch the browser while getting the disk
# # configuration
message = """
<html>
<head></head>
<style>
#bar { width: 20px; height: 10px; position: relative; background: darkslategrey; }
</style>
<body>
<h1 style="margin: 5em 0 0 5em; font-size: 250%; color: darkslategrey;">
<span id="opengnsys"><span style="font-weight: lighter;">Open</span>Gnsys 3</div>
<div id="bar"></span>
</h1>
<script>
var elem = document.getElementById("bar");
var max = document.getElementById("opengnsys").offsetWidth;
var pos = 0;
var inc = true;
var id = setInterval(frame, 5);
function frame() {
if (inc) {
if (pos == max - 20) { inc = false; } else { pos++; }
} else {
if (pos == 0) { inc = true; } else { pos--; }
}
elem.style.left = pos + 'px';
}
</script>
</body>
</html>
"""
f = open('/tmp/init.html', 'w')
f.write(message)
f.close()
# Launching the Browser
self._launch_browser('/tmp/init.html')
config = operations.get_configuration()
self.REST.sendMessage('ogagent/config', {'mac': self.interface.mac, 'ip': self.interface.ip,
'config': config})
else:
# Delete marking files
for f in ['ogboot.me', 'ogboot.firstboot', 'ogboot.secondboot']:
try:
os.remove(os.sep + f)
except OSError:
pass
# Copy file "HostsFile.FirstOctetOfIPAddress" to "HostsFile", if it exists
# (used in "exam mode" from the University of Seville)
hosts_file = os.path.join(operations.get_etc_path(), 'hosts')
new_hosts_file = hosts_file + '.' + self.interface.ip.split('.')[0]
if os.path.isfile(new_hosts_file):
shutil.copyfile(new_hosts_file, hosts_file)
def onDeactivation(self):
"""
@ -213,23 +346,14 @@ class OpenGnSysWorker(ServerWorker):
:param server:
:return: JSON object {"status": "status_code", "loggedin": boolean}
"""
res = {'status': '', 'loggedin': self.logged_in}
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'
res = {'loggedin': self.logged_in}
try:
res['status'] = operations.os_type.lower()
except KeyError:
res['status'] = ''
# Check if OpenGnsys Client is busy
if res['status'] == 'oglive' and len(self.commands) > 0:
res['status'] = 'busy'
return res
@check_secret
@ -247,6 +371,7 @@ class OpenGnSysWorker(ServerWorker):
# Rebooting thread
def rebt():
operations.reboot()
threading.Thread(target=rebt).start()
return {'op': 'launched'}
@ -266,6 +391,7 @@ class OpenGnSysWorker(ServerWorker):
def pwoff():
time.sleep(2)
operations.poweroff()
threading.Thread(target=pwoff).start()
return {'op': 'launched'}
@ -275,24 +401,42 @@ class OpenGnSysWorker(ServerWorker):
Processes an script execution (script should be encoded in base64)
:param path:
:param get_params:
:param post_params: JSON object {"script": "commands"}
:param server: authorization header
:return: JSON object {"op": "launched"}
:param post_params: object with format:
id: operation id.
script: command code
redirect_url: callback REST route
send_config: flag to send client's configuration after command execution (optional)
:param server: headers data
:rtype: JSON object with launching status
"""
logger.debug('Processing script request')
# Decoding script (Windows scripts need a subprocess call per line)
script = urllib.unquote(post_params.get('script').decode('base64')).decode('utf8')
if operations.os_type == 'Windows':
script = 'import subprocess; {0}'.format(
';'.join(['subprocess.check_output({0},shell=True)'.format(repr(c)) for c in script.split('\n')]))
else:
script = 'import subprocess; subprocess.check_output("""{0}""",shell=True)'.format(script)
# Executing script.
if post_params.get('client', 'false') == 'false':
thr = ScriptExecutorThread(script)
thr.start()
else:
self.sendClientMessage('script', {'code': script})
logger.debug('Processing script operation with params: {}'.format(post_params))
# Processing data
try:
# Decoding script (Windows scripts need a subprocess call per line)
script = urllib.unquote(post_params.get('script').decode('base64')).decode('utf8')
if operations.os_type == 'Windows':
script = 'import subprocess; {0}'.format(
';'.join(['subprocess.check_output({0},shell=True)'.format(repr(c)) for c in script.split('\n')]))
else:
script = 'import subprocess; subprocess.check_output("""{0}""",shell=True)'.format(script)
op_id = post_params.get('id')
route = post_params.get('redirect_uri')
send_config = (post_params.get('send_config', 'false') == 'true')
# Checking if the thread id. exists
for c in self.commands:
if c.getName() == str(op_id):
raise Exception('Task id. already exists: {}'.format(op_id))
if post_params.get('client', 'false') == 'false':
# Launching a new thread
thr = threading.Thread(name=op_id, target=self._task_command, args=(route, script, op_id, send_config))
thr.start()
self.commands.append(thr)
else:
# Executing as normal user
self.sendClientMessage('script', {'code': script})
except Exception as e:
logger.error('Got exception {}'.format(e))
return {'error': e}
return {'op': 'launched'}
@check_secret
@ -301,7 +445,7 @@ class OpenGnSysWorker(ServerWorker):
Closes user session
"""
logger.debug('Received logoff operation')
# Sending log off message to OGAgent client
# Send log off message to OGAgent client
self.sendClientMessage('logoff', {})
return {'op': 'sent to client'}
@ -311,9 +455,125 @@ class OpenGnSysWorker(ServerWorker):
Shows a message popup on the user's session
"""
logger.debug('Received message operation')
# Sending popup message to OGAgent client
# Send popup message to OGAgent client
self.sendClientMessage('popup', post_params)
return {'op': 'launched'}
def process_client_popup(self, params):
self.REST.sendMessage('popup_done', params)
@check_secret
def process_config(self, path, get_params, post_params, server):
"""
Returns client configuration
:param path:
:param get_params:
:param post_params:
:param server:
:return: object
"""
serial_no = '' # Serial number
storage = [] # Storage configuration
warnings = 0 # Number of warnings
logger.debug('Received getconfig operation')
# Processing data
for row in operations.get_configuration().split(';'):
cols = row.split(':')
if len(cols) == 1:
if cols[0] != '':
# Serial number
serial_no = cols[0]
else:
# Skip blank rows
pass
elif len(cols) == 7:
disk, part_no, part_type, fs, op_sys, size, usage = cols
try:
if int(part_no) == 0:
# Disk information
storage.append({'disk': int(disk), 'parttable': int(part_type), 'size': int(size)})
else:
# Partition information
storage.append({'disk': int(disk), 'partition': int(part_no), 'parttype': part_type,
'filesystem': fs, 'operatingsystem': op_sys, 'size': int(size),
'usage': int(usage)})
except ValueError:
logger.warn('Configuration parameter error: {}'.format(cols))
warnings += 1
else:
# Logging warnings
logger.warn('Configuration data error: {}'.format(cols))
warnings += 1
# Returning configuration data and count of warnings
return {'serial': serial_no, 'storage': storage, 'warnings': warnings}
@check_secret
def process_execinfo(self, path, get_params, post_params, server):
"""
Returns running commands information
:param path:
:param get_params:
:param post_params:
:param server:
:return: object
"""
data = []
logger.debug('Received execinfo operation')
# Returning the arguments of all running threads
for c in self.commands:
if c.is_alive():
data.append(c.__dict__['_Thread__args'])
return data
@check_secret
def process_stopcmd(self, path, get_params, post_params, server):
"""
Stops a running process identified by its trace id.
:param path:
:param get_params:
:param post_params: JSON object {"trace": trace_id}
:param server: authorization header
:return: JSON object: {"stopped": trace_id}
"""
logger.debug('Received stopcmd operation with params {}:'.format(post_params))
# Find operation id. and stop the thread
op_id = post_params.get('trace')
for c in self.commands:
if c.is_alive() and c.getName() == str(op_id):
c._Thread__stop()
return {"stopped": op_id}
return {}
@check_secret
def process_hardware(self, path, get_params, post_params, server):
"""
Returns client's hardware profile
:param path:
:param get_params:
:param post_params:
:param server:
:return: array of component data objects
"""
data = []
logger.debug('Received hardware operation')
# Processing data
try:
for comp in operations.get_hardware():
data.append({'component': comp.split('=')[0], 'value': comp.split('=')[1]})
except:
pass
# Return list of hardware components
return data
@check_secret
def process_software(self, path, get_params, post_params, server):
"""
Returns software profile installed on an operating system
:param path:
:param get_params:
:param post_params:
:param server:
:return:
"""
logger.debug('Received software operation with params: {}'.format(post_params))
return operations.get_software(post_params.get('disk'), post_params.get('part'))

View File

@ -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

View File

@ -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:
for i in range(10):
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().
"""

View File

@ -0,0 +1,258 @@
# -*- 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: Ramón M. Gómez, ramongomez at us dot es
"""
from __future__ import unicode_literals
import socket
import platform
import os
import fcntl
import subprocess
import struct
import array
import six
import chardet
from opengnsys import utils
from opengnsys.log import logger
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 _exec_ogcommand(ogcmd):
"""
Loads OpenGnsys environment variables, executes the command and returns the result
"""
ret = subprocess.check_output(ogcmd, shell=True)
return ret
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 get_oglive_version():
"""
Returns ogLive Kernel version and architecture
:return: kernel version
"""
kv = platform.os.uname()
return kv[2] + ', ' + kv[4]
def reboot():
"""
Simple reboot using OpenGnsys script
"""
# Workaround for dummy thread
if six.PY3 is False:
import threading
threading._DummyThread._Thread__stop = lambda x: 42
_exec_ogcommand('/opt/opengnsys/scripts/reboot')
def poweroff():
"""
Simple power off using OpenGnsys script
"""
# Workaround for dummy thread
if six.PY3 is False:
import threading
threading._DummyThread._Thread__stop = lambda x: 42
_exec_ogcommand('/opt/opengnsys/scripts/poweroff')
def get_etc_path():
"""
Returns etc directory path.
"""
return os.sep + 'etc'
def get_configuration():
"""
Returns client's configuration
Warning: this operation may take some time
:return:
"""
try:
_exec_ogcommand('/opt/opengnsys/interfaceAdm/getConfiguration')
# Returns content of configuration file
cfgdata = open('/tmp/getconfig', 'r').read().strip()
except IOError:
cfgdata = ''
return cfgdata
def exec_command(cmd):
"""
Executing a shell command
:param cmd:
:return: object with components:
output: standard output
error: error output
exit: exit code
"""
proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(out, err) = proc.communicate()
try:
if out is not None:
encoding = chardet.detect(out)["encoding"]
if encoding is not None:
out = out.decode(encoding).encode("utf8")
if err is not None:
encoding = chardet.detect(err)["encoding"]
if encoding is not None:
err = err.decode(encoding).encode("utf8")
except Exception as e:
logger.debug("ERROR EXEC COMMAND: {}".format(str(e)))
stat = proc.returncode
return stat, out, err
def get_hardware():
"""
Returns client's hardware list
:return:
"""
try:
filepath = _exec_ogcommand('/opt/opengnsys/scripts/listHardwareInfo').strip()
# Returns content of configuration file, skipping the header line and newline characters
with open(filepath, 'r') as f:
harddata = map(str.strip, f.readlines()[1:])
except IOError:
harddata = ''
return harddata
def get_software(disk, part):
"""
Returns software list installed on an operating system
:param disk:
:param part:
:return:
"""
try:
filepath = _exec_ogcommand('/opt/opengnsys/scripts/listSoftwareInfo {} {}'.format(disk, part)).strip()
# Returns content of configuration file, skipping the header line and newline characters
with open(filepath, 'r') as f:
softdata = map(str.strip, f.readlines())
except IOError:
softdata = ''
return softdata

View File

@ -27,12 +27,13 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""
@author: Adolfo Gómez, dkmaster at dkmon dot com
@author: Ramón M. Gómez, ramongomez at us dot es
"""
# pylint: disable=unused-wildcard-import,wildcard-import
from __future__ import unicode_literals
import sys
import os
# Importing platform operations and getting operating system data.
if sys.platform == 'win32':
@ -45,6 +46,11 @@ else:
os_type = 'MacOS'
os_version = getMacosVersion().replace(',', '')
else:
from .linux.operations import * # @UnusedWildImport
os_type = 'Linux'
os_version = getLinuxVersion()
if os.path.exists('/scripts/oginit'):
from .oglive.operations import * # @UnusedWildImport
os_type = 'ogLive'
os_version = get_oglive_version().replace(',', '')
else:
from .linux.operations import * # @UnusedWildImport
os_type = 'Linux'
os_version = getLinuxVersion()

View File

@ -139,5 +139,5 @@ setup(
description='OpenGnsys Agent',
author='Adolfo Gomez',
author_email='agomez@virtualcable.es',
zipfile='OGAgent.zip',
zipfile='OGAgent.zip', requires=['six']
)