Commit 3ee3e70c authored by Alessandro Elias's avatar Alessandro Elias
Browse files

Merge branch 'issue/511' into 'develop'

SCRUM#511: added linter to ci + solve linter problems

See merge request !27
parents 3c58937c 097ac7f9
Pipeline #16572 failed with stages
in 9 minutes and 7 seconds
......@@ -6,13 +6,13 @@ apt-get update && apt-get install -y devscripts
CHANGELOG="package/debian/changelog"
LINE=$(head -n 1 $CHANGELOG)
PACKAGE=$(echo $LINE | cut -d' ' -f1)
VERSION=$(echo $LINE | cut -d' ' -f2 | grep -o -E '[0-9]*\.[0-9]*\.[0-9]*')
tar --exclude=debian -czf ${PACKAGE}_${VERSION}.orig.tar.gz package/*
PACKAGE=$(echo "$LINE" | cut -d' ' -f1)
VERSION=$(echo "$LINE" | cut -d' ' -f2 | grep -o -E '[0-9]*\.[0-9]*\.[0-9]*')
tar --exclude=debian -czf "${PACKAGE}"_"${VERSION}".orig.tar.gz package/*
cd package
cd package || exit
debuild -us -uc --lintian-opts --profile debian
cd ../
cd ../ || exit
mkdir build/
mv ${PACKAGE}* build/
mv "${PACKAGE}"* build/
#!/bin/bash
# shellcheck disable=SC2029
# This script uploads an includes a .deb package in our debian repository.
# The distribution is chosen based on the gitlab-ci stage we are on.
......@@ -12,7 +12,6 @@ echo "Deploy job name: $CI_JOB_NAME"
if [ "$CI_JOB_NAME" = "deploy_for_unstable" ]; then
dput -u -f --config=dput.cf repo build/*.changes
else
if [ "$CI_JOB_NAME" = "deploy_for_testing" ]; then
REPO_SRC="unstable"
......
## Template para empacotamento utilizando o Gitlab-ci.
stages:
- lint
- build
- test
- deploy
lint_shell:
stage: lint
tags:
- debian-packaging
script:
- apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install wget locales locales-all -y
- locale-gen pt_BR.UTF-8
- export LANG=pt_BR.UTF-8
- scversion="stable" # or "v0.4.7", or "latest"
- wget "https://storage.googleapis.com/shellcheck/shellcheck-$scversion.linux.x86_64.tar.xz"
- tar --xz -xvf "shellcheck-$scversion.linux.x86_64.tar.xz"
- shellcheck() { "shellcheck-$scversion/shellcheck" "$@"; }
- ./.linter_shell.sh
lint_python:
stage: lint
tags:
- debian-packaging
script:
- apt-get update && apt-get install python3-pip -y
- pip3 install -r py_linter_requirements.txt
- ./.linter_python.sh
build:
stage: build
artifacts:
......
#!/bin/bash
YELLOW='\033[0;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
py_files=$(find . -name "*.py")
exe_files=$(grep -Erl "#\!/usr/bin/python*" --exclude=*.* package)
files="$py_files\n$exe_files"
#find no files
if [[ "$files" == "\n" ]];then
echo -e "${YELLOW}No python files found!${NC}"
exit 0
fi
echo -e "$files" | xargs flake8
rv=$?
if [[ $rv -eq 0 ]];then
echo "AWESOME!No problems found."
exit 0
else
echo -e "Understand errors in: ${BLUE}http://flake8.pycqa.org/en/latest/user/error-codes.html${NC}"
exit 1
fi
#!/bin/bash
YELLOW='\033[0;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
sh_files=$(find . -name "*.sh")
exe_files=$(grep -Erl "#\!/bin/(bash|sh)" --exclude=*.* package)
files="$sh_files\n$exe_files"
#find no files
if [[ "$files" == "\n" ]];then
echo -e "${YELLOW}No shell files found!${NC}"
exit 0
fi
echo -e "$files"| xargs shellcheck -s bash
rv=$?
if [[ $rv -eq 0 ]];then
echo "AWESOME!No problems found."
exit 0
else
echo -e "Understand errors in: ${BLUE}https://github.com/koalaman/shellcheck/wiki${NC}"
exit 1
fi
......@@ -28,7 +28,7 @@ set -e
# Disable the extension
gnome-shell-extension-tool -d le-epoptes || true
if [ remove = "$1" -o abort-install = "$1" -o disappear = "$1" ]; then
if [ remove = "$1" ] || [ abort-install = "$1" ] || [ disappear = "$1" ]; then
dpkg-divert --package le-epoptes --remove --rename \
--divert /usr/bin/epoptes.real /usr/bin/epoptes
fi
......
......@@ -21,25 +21,19 @@
# USA.
from gi.repository import GObject as gobject
from subprocess import Popen, PIPE, STDOUT
from lelab.utils import call_error_dialog, check_if_user_is_in_group, FailedToConnectWithDbusException
from lelab.utils import call_error_dialog, check_if_user_is_in_group
from lelab.utils import FailedToConnectWithDbusException
import socket
import logging
import dbus
import dbus.service
import dbus.mainloop.glib
import lelab.constants as constants
import lelab.services as services
import psutil
import time
import sys
import socket
import signal
class LEEpoptes(object):
class LEEpoptes(object):
epoptes_bin = '/usr/bin/epoptes.real'
config_file = '/etc/default/epoptes-client'
......@@ -49,15 +43,16 @@ class LEEpoptes(object):
# Check if the current user is in the 'epoptes' group
if(not check_if_user_is_in_group(psutil.users()[0].name,"epoptes")):
call_error_dialog("O usuário atual não está no grupo 'epoptes'. Para mais informações, consulte o manual do usuário do Linux Educacional 6")
exit(0)
if(not check_if_user_is_in_group(psutil.users()[0].name, "epoptes")):
call_error_dialog("O usuário atual não está no grupo 'epoptes'."
" Para mais informações, consulte o manual do "
"usuário do Linux Educacional 6")
exit(1)
try:
self.conn = services.get_connection()
except FailedToConnectWithDbusException as e:
call_error_dialog(str(e))
exit(0)
exit(1)
def get_current_server(self):
myhost = socket.gethostname() + ".local"
......@@ -83,14 +78,18 @@ class LEEpoptes(object):
if self.conn.get_attribute('epoptes', '_status') == 'disabled':
call_error_dialog("O epoptes está desabilitado. Peça para o administrador habilitá-lo no painel de controle.")
call_error_dialog("O epoptes está desabilitado. Peça "
"para o administrador habilitá-lo no "
"painel de controle.")
else:
if current_server != '':
logging.info("The current server is %s. Changing server to local machine instead.", current_server)
logging.info("The current server is %s. Changing "
"server to local machine instead.",
current_server)
logging.info("Starting server %s", my_server)
self.conn.advertise('epoptes')
if self.wait_for_lelab():
self.open_epoptes()
......@@ -100,8 +99,8 @@ class LEEpoptes(object):
logging.debug("Server %s closed", my_server)
else:
call_error_dialog("This computer is already registered as an epoptes server.")
call_error_dialog("This computer is already registered as an"
" epoptes server.")
def open_epoptes(self):
......@@ -110,7 +109,6 @@ class LEEpoptes(object):
p = Popen(params, stderr=STDOUT, stdout=PIPE)
p.wait()
def wait_for_lelab(self):
# Wait for le-lab to register the epoptes service
......@@ -121,10 +119,13 @@ class LEEpoptes(object):
timeout += 1
if timeout == 10:
call_error_dialog("Epoptes was unable to establish a connection with le-lab. Please check your internet connection.")
call_error_dialog("Epoptes was unable to establish a "
"connection with le-lab. Please check "
"your internet connection.")
return False
logging.debug("Waiting for le-lab to detect the local epoptes service...")
logging.debug("Waiting for le-lab to detect the local epoptes "
"service...")
time.sleep(1)
return True
......@@ -134,18 +135,22 @@ def get_lock(proc_name):
try:
get_lock._lock_socket.bind('\0' + proc_name)
except socket.error:
proc = Popen ("xdotool search --class epoptes.real", shell=True, stdout=PIPE,stderr=PIPE)
output,err = proc.communicate()
proc = Popen("xdotool search --class epoptes.real",
shell=True, stdout=PIPE, stderr=PIPE)
output, err = proc.communicate()
eu = [int(x) for x in output.split()]
for x in eu:
Popen ("xdotool windowactivate " + str(x), shell=True, stdout=PIPE,stderr=PIPE)
sys.exit()
def signal_handler (signal, frame):
Popen("xdotool windowactivate " + str(x),
shell=True, stdout=PIPE, stderr=PIPE)
sys.exit(1)
def signal_handler(signal, frame):
return
if __name__ == "__main__":
signal.signal(signal.SIGINT,signal_handler)
signal.signal(signal.SIGINT, signal_handler)
get_lock("epoptes")
# Setup log info
loglevel = getattr(logging, 'DEBUG')
......
......@@ -21,12 +21,11 @@
# USA.
from subprocess import Popen, PIPE, STDOUT
from lelab.utils import *
import argparse
import dbus
import lelab.constants as constants
from lelab.utils import run_shell_command
from lelab.utils import FailedToConnectWithDbusException
from lelab.utils import time, setup_logging
from lelab.utils import get_current_X_display
from lelab.utils import run_subprocess
import lelab.services as services
import logging
import sys
......@@ -34,7 +33,6 @@ import re
import os
import psutil
import socket
import sys
# Constants
LOG_FILE = '/var/log/epoptes-tracker.log'
......@@ -43,7 +41,7 @@ CLIENT_CONFIG_FILE = "/etc/default/epoptes-client"
def kill_epoptes_client():
# Kill all active epoptes-client subprocesses
logging.debug("Killing active epoptes-client processes")
run_shell_command(["pkill", "-f", "epoptes-client"])
......@@ -56,34 +54,38 @@ def kill_epoptes_server():
def stop_service():
# Called by 'stop' action from le-lab, closes all epoptes and epoptes client instances
# Called by 'stop' action from le-lab,
# closes all epoptes and epoptes client instances
kill_epoptes_client()
kill_epoptes_server()
# Update the SSL certificate so epoptes doesn't return an error upon startup
# Update the SSL certificate so epoptes doesn't
# return an error upon startup
generate_SSL_certificate()
def start_service():
# Called by 'start' action from le-lab, starts the epoptes systemd service if inactive.
# Called by 'start' action from le-lab, starts the epoptes
# systemd service if inactive.
try:
lelab_services = services.get_connection()
except FailedToConnectWithDbusException:
logging.error("Failed to connect with the le-lab dbus. Interrupting process.")
logging.error("Failed to connect with the le-lab dbus."
" Interrupting process.")
exit(1)
status = lelab_services.systemctl("epoptes","is-active")
status = lelab_services.systemctl("epoptes", "is-active")
if not status:
# TODO: Check if it's needed to update the SSL key here
# Might be necessary if the computer was powerd off as a client
# Might be necessary if the computer was powerd off as a client
# Start the epoptes service if it's inactive
generate_SSL_certificate()
lelab_services.systemctl('epoptes','enable')
lelab_services.systemctl('epoptes','start')
lelab_services.systemctl('epoptes', 'enable')
lelab_services.systemctl('epoptes', 'start')
def restart_service():
......@@ -92,17 +94,21 @@ def restart_service():
stop_service()
start_service()
def generate_SSL_certificate():
'''
To authenticate its connections, Epoptes uses a pair of SSL keys that it generates upon
installation. These keys are stored in /etc/epoptes/. However, when epoptes-client connects
to an epoptes host, it overwrites the public key with the certificate that it fetches from
the host.
Consequently, when there's a key from a foreign host stored in the computer, epoptes returns
an error upon start-up warning that the private and public key values are mismatched. To fix
this, a new key pair has to be generated every time before epoptes is started,.
To authenticate its connections, Epoptes uses a pair of SSL keys
that it generates upon installation. These keys are stored in
/etc/epoptes/. However, when epoptes-client connects to an epoptes
host, it overwrites the public key with the certificate that it
fetches from the host.
Consequently, when there's a key from a foreign host stored in
the computer, epoptes returns an error upon start-up warning that
the private and public key values are mismatched. To fix this,
a new key pair has to be generated every time before epoptes
is started.
'''
......@@ -128,8 +134,6 @@ def generate_SSL_certificate():
class LEEpoptes_control(object):
def __init__(self):
......@@ -137,7 +141,8 @@ class LEEpoptes_control(object):
try:
self.conn = services.get_connection()
except FailedToConnectWithDbusException:
logging.error("Failed to connect with the le-lab dbus. Interrupting process.")
logging.error("Failed to connect with the le-lab dbus. "
"Interrupting process.")
exit(1)
def set_as_server(self):
......@@ -145,31 +150,29 @@ class LEEpoptes_control(object):
Called when a local epoptes service is detected
"""
status = self.conn.get_attribute('epoptes', '_status')
server = self.conn.get_attribute('epoptes', '_server')
status = self.conn.get_attribute('epoptes', '_status')
server = self.conn.get_attribute('epoptes', '_server')
if status == 'client':
self.update_server('pre_server',server)
self.update_server('pre_server', server)
else:
self.update_server('server',socket.gethostname()+".local")
self.update_server('server', socket.gethostname()+".local")
return server
def unset_as_server(self):
"""
Called when a local epoptes service disconnects
"""
status = self.conn.get_attribute('epoptes', '_status')
server = self.conn.get_attribute('epoptes', '_server')
status = self.conn.get_attribute('epoptes', '_status')
server = self.conn.get_attribute('epoptes', '_server')
if status == 'pre_client':
self.update_server('client',server)
else:
self.update_server('enabled',"")
self.update_server('client', server)
else:
self.update_server('enabled', "")
def set_server(self, host, port):
"""
......@@ -182,9 +185,9 @@ class LEEpoptes_control(object):
while status == 'disabled' and hosts:
time.sleep(0.5)
status = self.conn.get_attribute('epoptes', '_status')
hosts = self.conn.get_connected_hosts('epoptes')
hosts = self.conn.get_connected_hosts('epoptes')
if status == 'server':
if status == 'server':
status = 'pre_client'
else:
status = 'client'
......@@ -192,17 +195,16 @@ class LEEpoptes_control(object):
if hosts:
self.update_server(status, host)
def unset_server(self, host):
"""
Called when a remote epoptes service disconnects
"""
status = self.conn.get_attribute('epoptes', '_status')
server = self.conn.get_attribute('epoptes', '_server')
status = self.conn.get_attribute('epoptes', '_status')
server = self.conn.get_attribute('epoptes', '_server')
if status == 'pre_server':
self.update_server('server',socket.gethostname()+".local")
self.update_server('server', socket.gethostname()+".local")
elif status == 'client':
'''
Check if the server that disconnected is the one that this
......@@ -212,21 +214,18 @@ class LEEpoptes_control(object):
'''
if host == server:
self.update_server('enabled',"")
self.update_server('enabled', "")
elif status != 'disabled':
self.update_server('enabled',"")
self.update_server('enabled', "")
def update_server(self,status,host):
def update_server(self, status, host):
logging.info("epoptes updating machine status to %s,%s", status, host)
self.update_epoptes(status,host)
self.update_epoptes(status, host)
self.conn.set_attribute('epoptes', '_status', status)
self.conn.set_attribute('epoptes', '_server', host)
self.conn.set_attribute('epoptes', '_server', host)
def update_epoptes(self,status,host):
def update_epoptes(self, status, host):
# Update the active epoptes instances according to the new status
if status == 'enabled' or status == 'disabled':
......@@ -242,9 +241,6 @@ class LEEpoptes_control(object):
elif status == 'server':
self.disable_client()
self.enable_server()
def enable_server(self):
'''
......@@ -253,20 +249,18 @@ class LEEpoptes_control(object):
generate_SSL_certificate()
# Start the epoptes service if it's inactive
if not self.conn.systemctl('epoptes','is-active') :
self.conn.systemctl('epoptes','enable')
self.conn.systemctl('epoptes','start')
if not self.conn.systemctl('epoptes', 'is-active'):
self.conn.systemctl('epoptes', 'enable')
self.conn.systemctl('epoptes', 'start')
def disable_server(self):
'''
Remove the self-signed ssl certificate. This is necessary because
Remove the self-signed ssl certificate. This is necessary because
when epoptes-client gets the server certificate, it checks if the
file isn't empty to ensure that it was fetched correctly. If we don't
previously remove the file, it will always return true even if the
certificate wasn't able to be fetched.
file isn't empty to ensure that it was fetched correctly.
If we don't previously remove the file, it will always return
true even if the certificate wasn't able to be fetched.
'''
filepath = '/etc/epoptes/server.crt'
try:
......@@ -275,24 +269,26 @@ class LEEpoptes_control(object):
pass
kill_epoptes_server()
def enable_client(self, host, port=789):
"""
Configure Epoptes client
1. Set the server and port on the config file (/etc/default/epoptes-client).
This is needed because epoptes-client connects to the host set on this file when
it is run.
2. Get the server public certificate and store it in /etc/epoptes/server.crt. This is
1. Set the server and port on the config file
(/etc/default/epoptes-client).
This is needed because epoptes-client connects to
the host set on this file when it is run.
2. Get the server public certificate and store it in
/etc/epoptes/server.crt. This is
done automatically by 'epoptes-client -c'.
3. Set the display variable as the current X server display. Epoptes gets screenshots
of the users' current screens to display in its UI. If this variable isn't set, it
tries to get a screenshot of the current (empty) display and returns an error.
4. Run epoptes client as a normal user. If epoptes-client is called as root, it
immediately closes itself.
3. Set the display variable as the current X server display.
Epoptes gets screenshots of the users' current screens to
display in its UI. If this variable isn't set, it
tries to get a screenshot of the current (empty) display
and returns an error.
4. Run epoptes client as a normal user. If epoptes-client is
called as root, it immediately closes itself.
"""
logging.debug("configuring client to host %s, port %d", host, port)
......@@ -300,7 +296,7 @@ class LEEpoptes_control(object):
# Set parameters in config file
server = "SERVER=" + host
port = "PORT=" + str(port)
config = open(CLIENT_CONFIG_FILE).read()
config = re.sub("#?SERVER=.*", server, config)
config = re.sub("#?PORT=.*", port, config)
......@@ -318,43 +314,44 @@ class LEEpoptes_control(object):
timeout -= 1
if success:
logging.info("epoptes ssl certificate sucessfully fetched for %s:%s",host,port)
# Set the display enviroment to use for epoptes-client
logging.info("epoptes ssl certificate sucessfully fetched"
" for %s:%s", host, port)
# Set the display enviroment to use for epoptes-client
os.environ["DISPLAY"] = get_current_X_display()
# Get the current user name
user = psutil.users()[0].name
run_subprocess(["sudo", "-u", user, "epoptes-client"])
logging.info("epoptes-client process restart for user {}".format(user))
logging.info("epoptes-client process restart for user"
" {}".format(user))
else:
logging.critical("unable to fetch epoptes certificate for %s:%s - %s", host, port,
logging.critical("unable to fetch epoptes certificate for "
"%s:%s - %s", host, port,
message)
return success
def disable_client(self):
'''
Kill any active 'epoptes-client' instances. When epoptes-client is called, it summons
a socat process with a timeout of 60 seconds that calls epoptes-client again. This causes
situations where there might be active 'zombie' instances of epoptes-client even after
disconnecting from a server.
Kill any active 'epoptes-client' instances. When epoptes-client
is called, it summons a socat process with a timeout of 60 seconds
that calls epoptes-client again. This causes situations where
there might be active 'zombie' instances of epoptes-client even
after disconnecting from a server.
'''
kill_epoptes_client()