diff options
-rw-r--r-- | admin/Sources/Clients/ogagent/src/opengnsys/modules/server/OpenGnSys/__init__.py | 104 | ||||
-rw-r--r-- | installer/vagrant/Vagrantfile-webconsole3-vbox | 171 | ||||
-rwxr-xr-x | server/bin/setserveraddr | 83 |
3 files changed, 251 insertions, 107 deletions
diff --git a/admin/Sources/Clients/ogagent/src/opengnsys/modules/server/OpenGnSys/__init__.py b/admin/Sources/Clients/ogagent/src/opengnsys/modules/server/OpenGnSys/__init__.py index 04c7ebc5..6e729046 100644 --- a/admin/Sources/Clients/ogagent/src/opengnsys/modules/server/OpenGnSys/__init__.py +++ b/admin/Sources/Clients/ogagent/src/opengnsys/modules/server/OpenGnSys/__init__.py @@ -47,6 +47,25 @@ from opengnsys.workers import ServerWorker from six.moves.urllib import parse +# Check authorization header decorator +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 + if this.random == server.headers['Authorization']: + fnc(*args, **kwargs) + else: + raise Exception('Unauthorized operation') + except Exception as e: + logger.error(e) + raise Exception(e) + + return wrapper + + # Error handler decorator. def catch_background_error(fnc): def wrapper(*args, **kwargs): @@ -93,7 +112,6 @@ class OpenGnSysWorker(ServerWorker): interface = None # Bound interface for OpenGnsys REST = None # REST object loggedin = False # User session flag - locked = {} # Locked partitions browser = {} # Browser info commands = [] # Running commands random = None # Random string for secure connections @@ -101,17 +119,6 @@ class OpenGnSysWorker(ServerWorker): access_token = refresh_token = None # Server authorization tokens grant_type = 'http://opengnsys.es/grants/og_client' - def _check_secret(self, server): - """ - Checks for received secret key and raise exception if it isn't valid. - """ - try: - if self.random != server.headers['Authorization']: - raise Exception('Unauthorized operation') - except Exception as e: - logger.error(e) - raise Exception(e) - def _launch_browser(self, url): """ Launchs the Browser with specified URL @@ -238,7 +245,7 @@ class OpenGnSysWorker(ServerWorker): <html> <head></head> <body> -<h1>Initializing...</h1> +<h1 style="margin: 5em; font-size: xx-large;">OpenGnsys 3</h1> </body> </html>""" f = open('/tmp/init.html', 'w') @@ -319,7 +326,12 @@ class OpenGnSysWorker(ServerWorker): def process_status(self, path, get_params, post_params, server): """ - Returns client status (OS type and login status). + Returns client status (OS type or execution status) and login status. + :param path: + :param get_params: + :param post_params: + :param server: + :return: JSON object {"status": "status_code", "loggedin": boolean} """ res = {'loggedin': self.loggedin} try: @@ -327,32 +339,42 @@ class OpenGnSysWorker(ServerWorker): except KeyError: res['status'] = '' # Check if OpenGnsys Client is busy - if res['status'] == 'oglive' and self.locked: + if res['status'] == 'oglive' and len(self.commands) > 0: res['status'] = 'busy' return res + @check_secret def process_reboot(self, path, get_params, post_params, server): """ Launches a system reboot operation. + :param path: + :param get_params: + :param post_params: + :param server: authorization header + :return: JSON object {"op": "launched"} """ logger.debug('Received reboot operation') - self._check_secret(server) - # Rebooting thread. + # Rebooting thread def rebt(): operations.reboot() threading.Thread(target=rebt).start() return {'op': 'launched'} + @check_secret def process_poweroff(self, path, get_params, post_params, server): """ Launches a system power off operation. + :param path: + :param get_params: + :param post_params: + :param server: authorization header + :return: JSON object {"op": "launched"} """ logger.debug('Received poweroff operation') - self._check_secret(server) - # Powering off thread. + # Powering off thread def pwoff(): time.sleep(2) operations.poweroff() @@ -360,18 +382,23 @@ class OpenGnSysWorker(ServerWorker): threading.Thread(target=pwoff).start() return {'op': 'launched'} + @check_secret def process_script(self, path, get_params, post_params, server): """ Processes an script execution (script should be encoded in base64) + :param path: + :param get_params: + :param post_params: JSON object {"redirect_uri, "uri", "script": "commands", "id": trace_id} + :param server: authorization header + :return: JSON object {"op": "launched"} or {"error": "message"} """ logger.debug('Processing script request') - self._check_secret(server) # Processing data try: script = urllib.unquote(post_params.get('script').decode('base64')).decode('utf8') op_id = post_params.get('id') route = post_params.get('redirect_uri') - # Checking if the thread id. exists + # Check 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)) @@ -388,43 +415,43 @@ class OpenGnSysWorker(ServerWorker): return {'error': e} return {'op': 'launched'} + @check_secret def process_logoff(self, path, get_params, post_params, server): """ Closes user session. """ logger.debug('Received logoff operation') - self._check_secret(server) - # Sending log off message to OGAgent client. + # Send log off message to OGAgent client. self.sendClientMessage('logoff', {}) return {'op': 'sent to client'} + @check_secret def process_popup(self, path, get_params, post_params, server): """ Shows a message popup on the user's session. """ logger.debug('Received message operation') - self._check_secret(server) - # 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 + :param server: authorization header + :return: JSON object """ serialno = '' # Serial number storage = [] # Storage configuration warnings = 0 # Number of warnings logger.debug('Received getconfig operation') - # self._check_secret(server) # Processing data for row in operations.get_configuration().split(';'): cols = row.split(':') @@ -450,33 +477,42 @@ class OpenGnSysWorker(ServerWorker): logger.warn('Configuration parameter error: {}'.format(cols)) warnings += 1 else: - # Logging warnings + # Log warnings logger.warn('Configuration data error: {}'.format(cols)) warnings += 1 # Return configuration data and count of warnings return {'serialno': serialno, '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 + :param server: authorization header + :return: JSON array: [["callback_url", "commands", trace_id], ...] """ data = [] logger.debug('Received execinfo operation') - self._check_secret(server) - # Returning the arguments of all running threads + # Return 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)) - self._check_secret(server) + # 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): diff --git a/installer/vagrant/Vagrantfile-webconsole3-vbox b/installer/vagrant/Vagrantfile-webconsole3-vbox new file mode 100644 index 00000000..6cf4f037 --- /dev/null +++ b/installer/vagrant/Vagrantfile-webconsole3-vbox @@ -0,0 +1,171 @@ +# Vagrantfile to prepare virtual environment using VirtualBox provider to develop new AngularJS-based web interface. + +VAGRANTFILE_API_VERSION = "2" +ENV['VAGRANT_DEFAULT_PROVIDER'] = "virtualbox" +LANGUAGE = "es_ES" +ENV['LC_ALL'] = LANGUAGE + ".UTF-8" +SERVERMEM = 2048 +SERVERCPUS = 2 +CLIENTMEM = 512 +NCLIENTS = 4 +REPODISK = "repo.vdi" +REPOSIZE = 50 +MACPREFIX = "08:00:27:0e:65" +NETPREFIX = "192.168.2" +SERVERIP = "#{NETPREFIX}.10" +LOCALWEBPORT = 8443 + + +# OpenGnsys Server provisioning script. +SCRIPT = <<EOT +# Set language. +export LANG="#{LANGUAGE}.UTF-8" +echo "LANG=\"$LANG\"" > /etc/default/locale +echo "LANG=\"$LANG\"" >> /etc/environment +echo "LANGUAGE=\"$LANG\"" >> /etc/environment +echo "LC_ALL=\"$LANG\"" >> /etc/environment +echo "LC_CTYPE=\"$LANG\"" >> /etc/environment +locale-gen --lang #{LANGUAGE} +sed -i "s/XKBLAYOUT=.*/XKBLAYOUT=\"${LANG%_*}\"/" /etc/default/keyboard +dpkg-reconfigure -fnoninteractive console-setup +# Exit if OpenGnsys is installed. +[ -f /opt/opengnsys/doc/VERSION.json ] && echo "Cannot provision, OpenGnsys is alread +y installed." && exit 1 +# Create repository disk using LVM, if necesary. +if [ -z "$(blkid /dev/mapper/og-images | grep ext4)" ]; then + pvcreate /dev/sdb + vgcreate og /dev/sdb + vgchange -ay + lvcreate -ay -n images -l 100%VG og + mkfs -t ext4 /dev/mapper/og-images + mkdir -p /opt/opengnsys/images + echo "/dev/mapper/og-images /opt/opengnsys/images ext4 defaults 0 0" >> /etc/fstab + mount -a +fi +# Update repositories. +add-apt-repository -y ppa:webupd8team/atom +apt-get update +# Install main dependencies. +apt-get install -y xfce4 gnome-icon-theme-full tango-icon-theme linux-headers-$(uname -r) firefox atom virtualbox-guest-dkms virtualbox-guest-utils virtualbox-guest-x11 +echo "allowed_users=anybody" > /etc/X11/Xwrapper.config +# Install OpenGnsys Server +tar xpvzf /vagrant/opengnsys3.tar.gz -C /tmp +/tmp/opengnsys/installer/opengnsys_installer.sh +echo y | /opt/opengnsys/bin/setserveraddr eth1 +# Configure the virtual lab. +read -e APIID APISECRET <<<$(/opt/opengnsys/www3/backend/app/console doctrine:query:sql "SELECT random_id, secret FROM og_core__clients WHERE id=1;" | awk -F\\" '$2~/^(random_id|secret)$/ {getline; printf("%s ", $2)}') +rm -fr /opt/opengnsys/www3/backend/var/cache/* +REQ=$(curl -sk 'https://localhost/opengnsys3/backend/web/app_dev.php/oauth/v2/token?client_id=1_'"$APIID"'&client_secret='"$APISECRET"'&grant_type=password&username=admin&password=admin') +TOKEN="$(echo $REQ | jq -r .access_token)" +REQ=$(curl -sk -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d '{"name":"Repositorio virtual", "ip":"#{SERVERIP}", "password":"'$(php -r 'echo md5(uniqid(rand(), true));')'", "configurationpath":"/", "adminpath":"/", "pxepath":"/", "port":0 }' https://localhost/opengnsys3/backend/web/app_dev.php/api/private/repositories) +REPOID=$(echo $REQ | jq -r .id) +REQ=$(curl -sk -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d '{"name":"Aula virtual", "description":"Despliegue virtual con Vagrant.", "networkSettings":{"mcastMode":"full-duplex", "mcastIp":"239.194.2.11", "mcastPort":9000, "mcastPort":9000, "mcastSpeed":100, "netmask":"#{NETPREFIX}.0", "router":"#{NETPREFIX}.1", "p2pMode":"peer", "p2pTime":60} }' https://localhost/opengnsys3/backend/web/app_dev.php/api/private/organizationalunits) +OUID=$(echo $REQ | jq -r .id) +for ((i=11; i<=10+#{NCLIENTS}; i++)); do + sed -i "/^}$/ i host pc${i} { hardware ethernet #{MACPREFIX}:${i}; fixed-address #{NETPREFIX}.${i}; }" /etc/dhcp/dhcpd.conf + [ $i == 11 ] && BOOTID=5 || BOOTID=6 + REQ=$(curl -sk -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d '{"name":"pc'$i'", "ip":"#{NETPREFIX}.'$i'", "mac":"#{MACPREFIX}:'$i'", "serialno":"", "netiface":"eth0", "netdriver":"generic", "netboot":'"$BOOTID"', "organizationalUnit":'"$OUID"', "repository":'"$REPOID"'}' https://localhost/opengnsys3/backend/web/app_dev.php/api/private/clients) +done +systemctl restart isc-dhcp-server +#/opt/opengnsys/bin/setclientmode ogLiveAdmin pc11 PERM +#for ((i=12; i<=#{NCLIENTS+10}; i++)); do +# /opt/opengnsys/bin/setclientmode ogLive pc$i PERM +#done +sed -i "s,\(url = 'https://\)[^/]*,\1localhost:#{LOCALWEBPORT}," /opt/opengnsys/www3/frontend/main.js +sed -i "s,\(url = 'https://\)[^/]*,\1localhost:#{LOCALWEBPORT}," /opt/opengnsys/www3/frontend/main.js.map +echo "Notes:" +echo "- New OpenGnsys Server URL: https://localhost:#{LOCALWEBPORT}/opengnsys3/frontend/" +EOT + +# Client 1 OS provisioning script. +OGAGENTPKG = "ogagent_1.1.1_all.deb" +MODELSCRIPT = <<EOT +# Comment out next lines to install and configure OGAgent for Ubuntu. +apt-get update -y +apt-get install -y curl +curl -ks https://#{SERVERIP}/opengnsys/descargas/#{OGAGENTPKG} -o /tmp/#{OGAGENTPKG} +if [ -f /tmp/#{OGAGENTPKG} ]; then + apt-get install -y /tmp/#{OGAGENTPKG} || exit $? + sed -i "0,/remote=/ s,remote=.*,remote=https://#{SERVERIP}/opengnsys/rest/," /usr/share/OGAgent/cfg/ogagent.cfg + rm -f /tmp/#{OGAGENTPKG} +else + echo "Warning: cannot install OGAgent package #{OGAGENTPKG}" +fi +# Remove network configuration added by Vagrant. +sed -i "/eth1/ d" /etc/network/interfaces +echo "Notes:" +echo "- After now, use VirtualBox GUI to disable network interface 1 and restart this VM." +# Leave VM halted. +sleep 2 +poweroff & +EOT + +Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| + + # OpenGnsys AngularJS VM definition. + config.vm.define "ogAngular", primary: true do |ag| + # Specific VirtualBox configuration. + ag.vm.provider "virtualbox" do |vb| + # VM name, memory and CPUs. + vb.name = "ogAngular" + vb.memory = SERVERMEM + vb.cpus = SERVERCPUS + # 2nd virtual disk path (current dir on Windows, VM dir on other OSes) + if Vagrant::Util::Platform.windows? then + second_disk = File.join(".", REPODISK) + else + line = `VBoxManage list systemproperties`.match("Default machine folder.*")[0] + vb_machine_folder = line.split(':')[1].strip() + second_disk = File.join(vb_machine_folder, vb.name, REPODISK) + end + # Create repo virtual disk, if needed. + unless File.exist?(second_disk) + vb.customize ['createhd', '--filename', second_disk, '--size', REPOSIZE * 1024] + end + # Attach repo virtual disk. + vb.customize ['storageattach', :id, '--storagectl', 'SATA Controller', '--port', 1, '--device', 0, '--type', 'hdd', '--medium', second_disk] + end + # VM base and host name. + ag.vm.box = "bento/ubuntu-18.04" + ag.vm.hostname = "ogAngular" + # Network settings. + ag.vm.network "forwarded_port", guest: 443, host: LOCALWEBPORT, host_ip: "127.0.0.1" + ag.vm.network "private_network", mac: "#{MACPREFIX}10".tr(":",""), ip: "#{SERVERIP}", virtualbox__intnet: true + # Launch provisioning script. + ag.vm.provision "shell", inline: SCRIPT + end + + # Client 1 VM definition. + config.vm.define "pc11", autostart: false do |v1| + v1.vm.box = "bento/ubuntu-18.04" + v1.vm.hostname = "pc11" + v1.vm.network "private_network", mac: "#{MACPREFIX}11".tr(":",""), type: "dhcp", virtualbox__intnet: true + v1.vm.provider "virtualbox" do |vb| + vb.name = "pc11" + vb.memory = CLIENTMEM + vb.cpus = 1 + vb.customize ['modifyvm', :id, '--boot1', 'net', '--boot2', 'disk'] + end + v1.vm.synced_folder ".", "/vagrant", disabled: true + v1.vm.provision "shell", inline: MODELSCRIPT + end + + # Clonable clients definition. + (2..NCLIENTS).each do |i| + config.vm.define "pc#{i+10}", autostart: false do |cl| + cl.vm.box = "clink15/pxe" + cl.ssh.insert_key = false + cl.vm.boot_timeout = 5 + cl.vm.network "private_network", mac: "#{MACPREFIX}#{i+10}".tr(":",""), type: "dhcp", virtualbox__intnet: true + cl.vm.provider "virtualbox" do |vb| + vb.name = "pc#{i+10}" + vb.memory = CLIENTMEM + vb.cpus = 1 + vb.customize ['modifyvm', :id, '--boot1', 'net', '--boot2', 'disk'] + vb.customize ["modifyvm", :id, "--nic1", "none"] + end + end + end + +end + diff --git a/server/bin/setserveraddr b/server/bin/setserveraddr index eb52d64d..a979595f 100755 --- a/server/bin/setserveraddr +++ b/server/bin/setserveraddr @@ -22,7 +22,7 @@ PROG="$(basename "$0")" OPENGNSYS=/opt/opengnsys PXEDIR=$OPENGNSYS/tftpboot/menu.lst -DEFAULTFILE=/etc/default/opengnsys +CONFIGFILE=$OPENGNSYS/etc/opengnsys.json # Checking parameters. if [ $# -ne 1 ]; then @@ -56,8 +56,7 @@ done if [ -n "$SERVERIP" ]; then # Temporary files. tmpfile=$(mktemp /tmp/og.XXXXX) - MYCNF=$(mktemp /tmp/.my.cnf.XXXXX) - trap "rm -f $tmpfile $MYCNF" 1 2 3 6 9 15 + trap "rm -f $tmpfile" 1 2 3 6 9 15 # Checking whether the DHCP settings need to be changed. CHANGE=0 @@ -85,73 +84,12 @@ if [ -n "$SERVERIP" ]; then echo "DHCP configuration has not changed." fi - # Saving old IP address. - source $OPENGNSYS/etc/ogAdmRepo.cfg - OLDSERVERIP=$IPlocal - - # Checking if configuration files need to be modified. - CHANGE=0 - for f in $OPENGNSYS/{etc/{ogAdmServer,ogAdmRepo,ogAdmAgent}.cfg,www/controlacceso.php,client/etc/ogAdmClient.cfg}; do - # Error if configuration file cannot be found. - if [ ! -f $f ]; then - echo "$PROG: File $file does not exist." >&2 - exit 2 - fi - # Updating configuration variables (if URLs does not contain "localhost"). - sed -e "s,ServidorAdm=.*,ServidorAdm=$SERVERIP," \ - -e "s,IPlocal=.*,IPlocal=$SERVERIP," \ - -e "s,UrlMenu=https?://\([^/]*\)/\(.*\),UrlMenu=https://$SERVERIP/\2," \ - -e '/localhost/!s,https\?://[^/]*/\(.*\),https://'$SERVERIP'/\1,' $f >$tmpfile - file="${f/./-$SERVERDEV.}" - # Copying updated file, if needed. - if [ ! $f -ef $file ] || ! diff -q $tmpfile $file &>/dev/null; then - cp $tmpfile $file - ln -f $file $f - CHANGE=1 - fi - done - - # Processing when something has changed. - if [ $CHANGE == 1 ]; then - # Restart OpenGnsys services. - /etc/init.d/opengnsys restart - # If Repository is active, generating a new API token. - source $DEFAULTFILE - if [ "$RUN_OGADMREPO" == "yes" ]; then - REPOKEY=$(php -r 'echo md5(uniqid(rand(), true));') - sed -i -e "s/ApiToken=.*/ApiToken=$REPOKEY/" $OPENGNSYS/etc/ogAdmRepo.cfg - fi - # If OpenGnsys Server is active, updating the database. - if [ "$RUN_OGADMSERVER" == "yes" ]; then - source $OPENGNSYS/etc/ogAdmServer.cfg - # Creating credentials file. - cat << EOT > $MYCNF -[client] -user=$USUARIO -password=$PASSWORD -EOT - # Updating OpenGnsys Server IP address. - mysql --defaults-extra-file=$MYCNF -D "$CATALOG" -e \ - "UPDATE entornos - SET ipserveradm='$SERVERIP' - WHERE identorno=1" - # If OpenGnsys Repository is active, updating IP address and API token. - if [ "$RUN_OGADMREPO" == "yes" ]; then - mysql --defaults-extra-file=$MYCNF -D "$CATALOG" -e \ - "UPDATE repositorios - SET ip='$SERVERIP', apikey='$REPOKEY' - WHERE ip='$OLDSERVERIP'" - unset REPOKEY - fi - # Updating all menu URLs. - mysql --defaults-extra-file=$MYCNF -D "$CATALOG" -e \ - "UPDATE menus - SET htmlmenupub = REPLACE(htmlmenupub, '$OLDSERVERIP', '$SERVERIP'), - htmlmenupri = REPLACE(htmlmenupri, '$OLDSERVERIP', '$SERVERIP');" - # Updating all PXE files. - find $PXEDIR -name "01-*" -exec sed -i -e "s/$OLDSERVERIP/$SERVERIP/g" {} \; - fi - + OLDSERVERIP=$(jq -r .server.ip $CONFIGFILE) + if [ "$SERVERIP" != "$OLDSERVERIP" ]; then + # Updating configuration file. + jq ".server.ip=\"$SERVERIP\"" $CONFIGFILE | sponge $CONFIGFILE + # Updating all PXE files. + find $PXEDIR -name "01-*" -exec sed -i -e "s/$OLDSERVERIP/$SERVERIP/g" {} \; # Showing manual task to do after execution. cat << EOT Default server interface set to: $SERVERDEV ($SERVERIP) @@ -161,7 +99,6 @@ Manual tasks: - Check PXE files. - Log-in as Web Console user: - Check menu URLs. -${REPOKEY:+" - Update repository API token"} EOT else # Showing message if nothing changes. @@ -173,6 +110,6 @@ else exit 1 fi -# Removing temporary files. -rm -f $tmpfile $MYCNF +# Removing temporary file. +rm -f $tmpfile |