Pages

Παρασκευή 31 Μαΐου 2013

Ubiquity UniFi Controller Software στο Raspberry Pi

Εισαγωγή

Βασικά η ιστορία συνεχίζεται από προηγούμενο άρθρο που βρίσκεται σε αυτό το blog. Για να υπάρξει μια σύνδεση με τα προηγούμενα, θα γίνει μια γενική περιγραφή του προβλήματος. Στη συνέχεια θα δούμε λίγα πράγματα για ένα εργαλείο που θα χρησιμοποιήσουμε (το Raspberry Pi) για τη λύση του προβλήματος και θα προχωρήσουμε στον τρόπο που ακολουθήθηκε για να επιτευχθεί το επιθυμητό αποτέλεσμα.

Επιγραμματικά ακολουθούν:

Το βασικό πρόβλημα

Το βασικό κομμάτι που μας ενδιαφέρει εδώ, είναι το στήσιμο ενός δικτύου ξενοδοχείου. Αυτό, με τη σειρά του, συνεπάγεται όλο το καλό πακέτο του ελέγχου σύνδεσης των πελατών, ποσού διακίνησης δεδομένων κ.λ.π. Αυτό το επιτυγχάνουν επαρκώς και με το παραπάνω τα Access Points της Ubiquity. Η χρήση ενός UniFi Outdoor Access Point λύνει όλα τα προβλήματα δικτύωσης. Το μόνο μειονέκτημα (και αυτό που μας απασχολεί στο παρόν άρθρο) είναι πως θα πρέπει να υπάρχει ένα μηχάνημα που να τρέχει το software της εταιρίας για τον έλεγχο και τη διαχείριση του δικτύου. Αυτό με τη σειρά του συνεπάγεται κατανάλωση ενέργειας για PC, θόρυβος από τα ανεμιστηράκια του, απαραίτητη χρήση UPS που να αντέχει σε μεγάλες διακοπές ρεύματος, license του λειτουργικού του συστήματος αν πρόκειται για μηχάνημα που τρέχει Bugindows, συχνές επανεκκινήσεις λόγω των προβλημάρων του αναφερόμενου λειτουργικού κ.λ.π. Ειδικα τα δύο τελευταία προβλήματα (που είναι και τα πιο σημαντικά) λύθηκαν με την εγκατάσταση λειτουργικού Linux και συγκεκριμένα της διανομής openSUSE, όπως φαίνεται και σε άλλο άρθρο του ίδιου blog.

Η λύση των υπολοίπων προβλημάτων διερευνήθηκε περισσότερο για να βρει ο γράφων δουλειά να κάνει (!!! Τι πρωτότυπο :)). Δεν είναι κάτι άλλο από το πασίγνωστο, πλέον στο χώρο των gadgetάκιδων, Raspberry Pi.

Raspberry Pi ως server...

Το Raspberry Pi είναι ένας υπολογιστής, όπως ακριβώς κι ένα κινητό. Η διαφορά του είναι πως δεν έχει οθόνη. Τι διαθέτει αυτός ο υπολογιστής (βασικά χαρακτηριστικά):

  • Επεξεργαστής: ARM στα 700MHz, με δυνατότητα Overclocking στο 1GHz
  • Μνήμη: 256 MBytes η παλιά έκδοση (Α), 512 MBytes η έκδοση Β
  • Ethernet: 10/100 Mbit
  • Video out: Δε μας ενδιαφέρει. Server θέλουμε να το κάνουμε, αλλά ως άχρηστη πληροφορία της ημέρας διαθέτει έξοδο HDMI και TV
  • USB: 2 πόρτες
  • Boot: από κάρτα μνήμηςfrom an SD
  • Τροφοδοσία: 5V με μικρή κατανάλωση ρεύματος (μέγιστη στα 700mA στην έκδοση Β)

Αυτά τα χαρακτηριστικά το κάνουν ιδανικό για χρήση ως server. Δίνουν, επίσης, τη δυνατότητα να μπορέσει να τροφοδοτηθεί, αργότερα, από ένα σύστημα UPS που να παράγει τα 5V που χρειάζονται απ' ευθείας από τη μπαταρία του. Κατά συνέπεια μια διακοπή της ΔΕΗ για... πολλές ώρες δεν θα το ενοχλήσει :)

Άλλο ένα καλό του εν λόγω gadget είναι πως πάρα πολλές διανομές Linux έχουν στηθεί για το Raspberry Pi· ακόμα και FreeBSD μπορούμε να βρούμε (αν και κανονικά αυτό δεν πρέπει να μας κάνει εντύπωση!). Μιας και την τελευταία φορά που έστησα το σύστημα του UniFi Controller ήταν επάνω σε openSUSE, δοκίμασα την εν λόγω διανομή και στο Raspberry Pi. Τα αποτελέσματα ήταν θαυμάσια. Το μόνο περίεργο ήταν η εγκατάσταση της Java, αλλά δεν ήταν κάτι που να αξίζει αναφοράς.

Κάτι που με "έτρωγε" ήταν πως αν κάποιος πάρει ένα Raspberry Pi και θελήσει να ασχοληθεί με τη χρήση του σε δίκτυο, όπως και αυτό που ήταν το έναυσμα για αυτή την ιστορία, τότε αμφιβάλλω αν θα ασχοληθεί με το να βάλει openSUSE· σίγουρα θα ασχοληθεί με το "έτοιμο" Raspbian που είναι βασισμένο επάνω στη διανομή Debian. Οπότε, για να μπορέσω να συμβάλλω και σε αυτό τον τομέα θα έπρεπε να δοκιμάσω αυτή τη διανομή για τις "ταρζανιές".

Το Στήσιμο

Το στήσιμο του συστήματος δεν είναι καθόλου δύσκολο. Μπορεί κάποιος να κατεβάσει το κατάλληλο image και να το γράψει σε μια κάρτα μνήμης SD, ή να χρησιμοποιήσει το BerryBoot. Η δεύτερη επιλογή απλά θα προσθέσει μερικά δευτερόλεπτα στο bootάρισμα του συστήματος, αλλά αν κάποιος θέλει να "παίξει" με το Raspberry τότε είναι μια καλή λύση.

Η κάρτα που χρησιμοποιήθηκε στο στήσιμό μας είναι μια 8GB SD Class 10. Δίνει αρκετό χώρο για "παιχνίδια", ενώ είναι αρκετά γρήγορη για ένα ικανοποιητικό χρόνο εκκίνησης. Εκεί εγκαταστάθηκε το Raspbian, ρυθμίστηκε για λίγο overclocking (800 MHz) και έγινε και expand το partition που περιέχει το λειτουργικό. Αυτά, επειδή δεν υπήρχε πληκτρολόγιο στο Raspberry, έγινε μέσω ssh, εκτελώντας από εκεί το raspi-config.

Σε γενικές γραμμές η εγκατάσταση του συστήματος δε νομίζω πως χρειάζεται παρουσίαση. Όλα υπάρχουν στο Internet και είναι αρκετά κατανοητά για κάποιον ο οποίος αποφασίζει να ασχοληθεί με το Raspberry. Έτσι, οι λεπτομέρειες της εγκατάστασης λειτουργικού και ενεργοποίησης του συστήματος, καθώς επίσης και της αναβάθμισης του λογισμικού δεν περιγράφονται.

Η αρχική εγκατάσταση περιέχει ένα χρήστη με το όνομα pi, ο οποίος ανήκει στο group pi, έχει password το raspberry, ενώ το όνομα του συστήματος στο δίκτυο είναι raspberrypi. Φυσικά, σε όλα αυτά έγιναν αλλαγές, οπότε ο χρήστης του συστήματος ονομάστηκε elias (λέμε τώρα!), το αρχικό group του χρήστη έχει το ίδιο όνομα, ενώ το δικτυακό όνομα του συστήματος έγινε unificontroll και διάφορα άλλα μικροσεταρίσματα.

Προεργασία

1. Εγκατάσταση Java

Για να λειτουργήσει το UniFi Controller χρειάζεται τη βάση δεδομένων mongodb και τη γλώσσα Java να είναι εγκαταστημένα στο σύστημα. Για τη Java δεν υπάρχει κάποιο πρόβλημα, μιας και είναι έτοιμη σε πακέτο .deb για το Raspbian. Αρκεί ένα

elias@unificontrol:~ > sudo apt-get install openjdk-7-jdk
[sudo] password for elias:
.
.
.

2. Εγκατάσταση MongoDB

Το περίεργο της υπόθεσης είναι πως δεν υπάρχει πακέτο για MongoDB (τουλάχιστον μέχρι τη στιγμή που γράφεται το παρόν άρθρο). Κατά συνέπεια μπαίνουμε σε διαδικασίες compile κ.λ.π. Μετά από λίγο ψάξιμο βρέθηκε ένα πολύ καλό άρθρο για την εγκατάσταση της mongopi που είναι η μεταφορά της εν λόγω βάσης δεδομένων στο Raspberry. Το συγκεκριμένο άρθρο που βρέθηκε δίνει πληροφορίες για την εγκατάσταση ενός ολόκληρου συστήματος με πολλά Raspberries. Η περιγραφή που θα γίνει στο παρόν άρθρο είναι μόνο για την εγκατάσταση της MongoDB, ως το σημείο που χρειάζεται για να λειτουργήσει με το UniFi Controller.

Ο κώδικας της mongopi είναι στο github. Για να γίνει η εγκατάσταση θα πρέπει να εγκατασταθούν πρώτα το git και κάτι ψιλά... Ξεκινάμε με την εγκατάσταση των απαραίτητων πακέτων γι' αυτή τη δουλειά:

elias@unificontrol:~ > sudo apt-get install git-core build-essential scons \
   libpcre++-dev xulrunner-dev libboost-dev \
   libboost-program-options-dev libboost-thread-dev \
   libboost-filesystem-dev
.
.
.

Στη συνέχεια κλωνοποιήσουμε το αποθετήριο με τα αρχεία της mongopi από το github:

elias@unificontrol:~ > git clone git://github.com/RickP/mongopi.git

Η συνέχεια θέλει υπομονή... Ώρα για compilation... Αυτό γίνεται με τη βοήθεια του εργαλείου scons και μπορεί να πάρει αρκετές ώρες (περίπου 4):

elias@unificontrol:~ > cd mongopi
elias@unificontrol:~/mongopi > scons

Μετά από... λίγη ημέρα :) το compilation θα έχει τελειώσει. Συνέχεια έχει η εγκατάσταση. Αυτή θα χρειαστεί μόνο... 3 ώρες!...

elias@unificontrol:~/mongopi > sudo scons --prefix=/opt/mongo install

Αυτή η εντολή θα εγκαταστήσει τη mongopi στον κατάλογο /opt/mongo. Φυσικά η όλη διαδικασία έπιασε και υπερβολικό χώρο στην κάρτα μνήμης (περίπου 2GB) οπότε καλό είναι να σβήσετε τον κατάλογο που περιέχει τον πηγαίο κώδικα:

elias@unificontrol:~/mongopi > cd ..
elias@unificontrol:~ > sudo rm -rf mongopi
elias@unificontrol:~ > 

Καλό είναι να μπει στο PATH του συστήματος ο κατάλογος με τα εκτελέσιμα της MongoDB για να είναι εύκολη η διαχείριση των βάσεών της. Αυτό γίνεται απλά με την προσθήκη του στο αρχείο .bashrc της ακόλουθης γραμμής:

export PATH=$PATH:/opt/mongo/bin

Σε αυτό το σημείο η εγκατάσταση της MongoDB έχει γίνει. Αν χρειαστεί να τη χρησιμοποιήσετε και σε άλλες εφαρμογές, τότε πιθανό είναι να πρέπει να δημιουργήσετε και τον κατάλογο /data/db στο σύστημά σας. Αυτό στην περίπτωση του UniFi Controller δεν είναι απαραίτητο γιατί τη δικιά του βάση δεδομένων την κρατάει σε δικό του κατάλογο.

Εγκατάσταση UniFi Controller

Η εγκατάσταση του UniFi Controller δεν έχει κάποια δυσκολία. Σε γενικές γραμμές είναι ίδια με αυτή που έχει γίνει και σε προηγούμενο άρθρο σε άλλη έκδοση του λειτουργικού Linux

Ξεκινάμε με το να δημιουργήσουμε ένα group με το όνομα unifid, όπου εκεί θα μπει και ο χρήστης που θα έχει τη δυνατότητα του custom portal για τους πελάτες του δικτύου. Μιας και ο μόνος χρήστης που υπάρχει αυτή τη στιγμή στο σύστημα είναι ο elias, αυτός είναι που θα προστεθεί και στο εν λόγω group.

elias@unificontrol:~ > sudo addgroup unifid
Adding group `unifid' (GID 1003) ...
Done.
elias@unificontrol:~ > sudo adduser elias unifid
Adding user `elias' to group `unifid' ...
Adding user elias to group unifid
Done.

Για να δει το σύστημα την αλλαγή στα groups θα πρέπει να κάνουμε ένα logout και μετά ξανά login. Αυτό που φαίνεται στις ακόλουθες εντολές είναι η σύνδεση μέσω ssh από άλλον υπολογιστή:

elias@unificontrol:~ > logout
Connection to 192.168.1.10 closed.
elias@otherpc:~> ssh 192.168.1.10
elias@192.168.1.10's password: 
Linux unificontrol 3.6.11+ #456 PREEMPT Mon May 20 17:42:15 BST 2013 armv6l

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Thu May 30 11:43:24 2013 from 192.168.1.20
elias@unificontrol:~ > groups
elias adm dialout cdrom sudo audio video plugdev games users netdev input unifid
elias@unificontrol:~ > 

Το επόμενο βήμα είναι να κατεβάσουμε το .zip αρχείο του προγράμματος. Οι διαθέσιμες εκδόσεις είναι δύο:

Όποια από τις δύο εκδόσεις και αν ενδιαφερθείτε να εγκαταστήσετε, ο τρόπος είναι ακριβώς ο ίδιος. Απλώς κατεβάστε το αρχείο .zip και αποσυμπιέστε το. Επειδή θα πρέπει να αποδεχθείτε την άδεια χρήσης του προγράμματος, θα πρέπει να το κατεβάσετε με τη βοήθεια κάποιου browser στον υπολογιστή σας και στη συνέχεια να το μεταφέρετε με scp στο Raspberry. Στη συνέχεια το αποσυμπιέζετε:

elias@otherpc:~ > scp ~/Downloads/UniFi.unix.zip 192.168.1.10:/home/elias/
elias@192.168.1.10's password:
UniFi.unix.zip    100%   28MB   1.2MB/s   00:23
elias@otherpc:~ > ssh 192.168.1.10
elias@192.168.1.10's password:
.
.
elias@unificontrol:~ > cd /opt/
elias@unificontrol:/opt > sudo unzip /home/elias/UniFi.unix.zip
Archive:  UniFi.unix.zip
   creating: UniFi/
   creating: UniFi/bin/
    linking: UniFi/bin/mongod        -> /usr/bin/mongod 
.
.
.
elias@unificontrol:/opt >

Το πρόγραμμα έχει εγκατασταθεί στο Raspberry. Μένουν λίγες ακόμα λεπτές πινελιές για τη λειτουργία του. Καταρχήν το link που βρίσκεται μέσα στον κατάλογο UniFi/bin δεν χρειάζεται κάποια αλλαγή, γιατί η εγκατάσταση της MongoDB έχει φροντίσει να υπάρχει το αρχείο /usr/bin/mongod που χρειάζεται το UniFi Controller. Αυτό που χρειαζεται να γίνει, είναι να δημιουργθεί ο κατάλογος data που θα φιλοξενεί όλες τις παραμέτρους για το δίκτυό μας. Ο κατάλογος αυτός θα περιέχει και το portal της εισόδου των πελατών του ξενοδοχείου στο δίκτυο, έτσι θα πρέπει να μπορεί ο χρήστης που ανήκει στο group unifid να αλλάζει τα δεδομένα χωρίς να υπάρχουν προβλήματα με τα δικαιώματα. Επειδή θα πειράξουμε λίγο τη λίστα δικαιωμάτων, θα χρειαστεί να εγκατασταθεί και το πακέτο acl με την εντολή:

elias@unificontrol:/opt > sudo apt-get install acl
...

Το επόμενο βήμα είναι να δημιουργθεί ο κατάλογος data και να του δοθούν τα κατάλληλα δικαιώματα:

elias@unificontrol:/opt > cd UniFi
elias@unificontrol:/opt/UniFi > sudo mkdir data
elias@unificontrol:/opt/UniFi > sudo chgrp unifid data
elias@unificontrol:/opt/UniFi > sudo chmod 0774 data
elias@unificontrol:/opt/UniFi > sudo chmod g+s data
elias@unificontrol:/opt/UniFi > sudo setfacl -d -m u::rwX,g::rwX,o::r data
elias@unificontrol:/opt/UniFi > ls -ld data
drwxrwsr--+ 7 root unifid 4096 May 29 13:13 data
elias@unificontrol:/opt/UniFi > getfacl data
# file: data
# owner: root
# group: unifid
# flags: -s-
user::rwx
group::rwx
other::r--
default:user::rwx
default:group::rwx
default:other::r--
elias@unificontrol:/opt/UniFi >

Πλέον είμαστε έτοιμοι να δοκιμάσουμε αν το πρόγραμμα λειτουργεί σωστά. Μην ξεχνάμε ότι η εγκατάσταση έχει γίνει με τέτοιο τρόπο που τρέχει από τον root. Για να ξεκινήσει το UniFi Controller θα πρέπει να δώσουμε την εντολή:

elias@unificontrol:/opt/UniFi > sudo /usr/bin/java -jar /opt/UniFi/lib/ace.jar start &

Εδώ θα πρέπει να περιμένουμε λίγο χρονικό διάστημα (αρκετά δευτερόλεπτα) πριν καταφέρουμε να μπούμε στο σύστημα. Για να δοκιμάσουμε το σύστημά μας, θα πρέπει να χρησιμοποιήσουμε τον browser ενός υπολογιστή. Αν προσπαθήσουμε να μπούμε πριν το πρόγραμμα κάνει όλα τα απαραίτητα, τότε απλά θα έχουμε μήνυμα λάθους από τον browser. Αν όμως το σύστημα ετοιμαστεί τότε δίνοντας τη διεύθυνση του Raspberry με πόρτα την 8080, θα δούμε την εισαγωγική οθόνη του UniFi Controller. Η διεύθυνση που έχει αυτή τη στιγμή είναι η 192.168.1.10, οπότε η διεύθυνση που θα πληκτρολογήσουμε στον browser μας είναι η http://192.168.1.10:8080/. Η σελίδα θα κάνει redirection σε https, αλλά στην ίδια διεύθυνση και ο browser θα μας παραπονεθεί για το πιστοποιητικό της σελίδας. Όταν τελικά το αποδεχτούμε:

Για να σταματήσουμε το πρόγραμμα, αρκεί να τρέξουμε την εντολή:

elias@unificontrol:/opt/UniFi > sudo /usr/bin/java -jar /opt/UniFi/lib/ace.jar stop

Για την ώρα δεν χρειάζεται να κάνουμε παραμετροποίηση του συστήματος. Μπορούμε να την αφήσουμε για αργότερα, όταν όλα θα είναι έτοιμα!

Δημιουργία service script

Τώρα που το σύστημα λειτουργεί, θα πρέπει να το κάνουμε να ενεργοποιείται στα κατάλληλα runlevels του Raspbian.

Η διαδικασία είναι η ίδια με αυτή που περιγράφεται στο αντίστοιχο άρθρο για το openSUSE. Ο κατάλογος /etc/init.d/ περιέχει όλα τα scripts για τα services. Περιέχει κι ένα αρχείο που μας ενδιαφέρει περισσότερο, το skeleton. Αυτό είναι ένα αρχείο στο οποίο μπορούμε να βασιστούμε για να φτιάξουμε το δικό μας script, έτσι ώστε το UniFi Controller να μπορεί να ενεργοποιηθεί και να απενεργοποιηθεί όπως ακριβώς και όλα τα υπόλοιπα services που διαθέτει το σύστημα. Το αρχείο που θα δημιουργήσουμε είναι το unifid. Μπορείτε να το δημιουργήσετε μόνοι σας από την αρχή, απλά αντιγράφοντας το ακόλουθο και σώζοντάς το μέσα στον εν λόγω κατάλογο:

#! /bin/sh
### BEGIN INIT INFO
# Provides:          unifid
# Required-Start:    $local_fs $syslog $network
# Required-Stop:     $local_fs $syslog $network
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: unifid daemon providing Controller server for UniFi Access Points
# Description:       Start unifid to allow the UniFi Controller Software to be able to
#       control the UniFi Access Points of Ubiquity in the network. The softare runs in Java
#       and is installed in /opt/ directory.
### END INIT INFO

# Author: Elias Chrysocheris 
#

# Do NOT "set -e"

# PATH should only include /usr/* if it runs after the mountnfs.sh script
PATH=/sbin:/usr/sbin:/bin:/usr/bin
DESC="UniFi Controller Service for assisting Ubiquity's UniFi Access Points"
JAVA_BIN=/usr/bin/java
NAME=unifid
MONGOD_BIN=/opt/UniFi/bin/mongod
DAEMON=/opt/UniFi/lib/ace.jar
DAEMON_ARGS="-jar $DAEMON"
SCRIPTNAME=/etc/init.d/$NAME

# Exit if Java package is not installed
[ -x "$JAVA_BIN" ] || { echo "Cannot find java executable in $JAVA_BIN, or java is not installed...";
    if [ "$1" = "stop" ]; then exit 0;
    else exit 5; fi; }

# Also, mongoDB must be installed. The extra step here is that there must be a valid link in
# /opt/UniFi/bin/mongod that points to the mongod executable
if [ ! \( -e $MONGOD_BIN \) ]
then
    echo "Cannot find mongod executable in $MONGOD_BIN, or mongoDB is not installed...";
    if [ "$1" = "stop" ]; then exit 0;
    else exit 5; fi;
fi

# Exit if the package is not installed
[ -e "$DAEMON" ] || { echo "Cannot find UniFi Controller executable in $DAEMON, or the controller software is not installed...";
    if [ "$1" = "stop" ]; then exit 0;
    else exit 5; fi; }

# Read configuration variable file if it is present
[ -r /etc/default/$NAME ] && . /etc/default/$NAME

# Load the VERBOSE setting and other rcS variables
. /lib/init/vars.sh

# Define LSB log_* functions.
# Depend on lsb-base (>= 3.2-14) to ensure that this file is present
# and status_of_proc is working.
. /lib/lsb/init-functions

#
# Function that starts the daemon/service
#
do_start()
{
    # Return
    #   0 if daemon has been started
    #   1 if daemon was already running
    #   2 if daemon could not be started
    start-stop-daemon --test --start --quiet --exec $JAVA_BIN -- $DAEMON_ARGS start > /dev/null \
        || return 1
    start-stop-daemon --start --quiet --exec $JAVA_BIN -- $DAEMON_ARGS start &
    RETVAL="$?"
    [ $RETVAL > 0 ] && return 2
    # Add code here, if necessary, that waits for the process to be ready
    # to handle requests from services started subsequently which depend
    # on this one.  As a last resort, sleep for some time.
}

#
# Function that stops the daemon/service
#
do_stop()
{
    # Return
    #   0 if daemon has been stopped
    #   1 if daemon was already stopped
    #   2 if daemon could not be stopped
    #   other if a failure occurred
    start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --exec $JAVA_BIN -- $DAEMON_ARGS stop
    RETVAL="$?"
    [ "$RETVAL" = 2 ] && return 2
    # Wait for children to finish too if this is a daemon that forks
    # and if the daemon is only ever run from this initscript.
    # If the above conditions are not satisfied then add some other code
    # that waits for the process to drop all resources that could be
    # needed by services started subsequently.  A last resort is to
    # sleep for some time.
    start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON
    [ "$?" = 2 ] && return 2
    return "$RETVAL"
}

#
# Function that sends a SIGHUP to the daemon/service
#
do_reload() {
    #
    # If the daemon can reload its configuration without
    # restarting (for example, when it is sent a SIGHUP),
    # then implement that here.
    #
    start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME
    return 0
}

case "$1" in
  start)
    [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
    do_start
    case "$?" in
        0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
        2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
    esac
    ;;
  stop)
    [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
    do_stop
    case "$?" in
        0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
        2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
    esac
    ;;
  status)
    status_of_proc "$JAVA_BIN -jar $DAEMON" "$NAME" && exit 0 || exit $?
    ;;
  #reload|force-reload)
    #
    # If do_reload() is not implemented then leave this commented out
    # and leave 'force-reload' as an alias for 'restart'.
    #
    #log_daemon_msg "Reloading $DESC" "$NAME"
    #do_reload
    #log_end_msg $?
    #;;
  restart|force-reload)
    #
    # If the "reload" option is implemented then remove the
    # 'force-reload' alias
    #
    log_daemon_msg "Restarting $DESC" "$NAME"
    do_stop
    case "$?" in
      0|1)
        do_start
        case "$?" in
            0) log_end_msg 0 ;;
            1) log_end_msg 1 ;; # Old process is still running
            *) log_end_msg 1 ;; # Failed to start
        esac
        ;;
      *)
        # Failed to stop
        log_end_msg 1
        ;;
    esac
    ;;
  *)
    #echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
    echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2
    exit 3
    ;;
esac

Το script θα πρέπει να είναι εκτελέσιμο, οπότε όταν δημιουργηθεί στο δίσκο θα πρέπει να του ενεργοποιηθούν και τα κατάλληλα δικαιώματα εκτέλεσης. Επίσης, η δημιουργία του γίνεται από τον χρήστη root, αλλοιώς το σύστημα θα αρνηθεί να το σώσει μέσα στον κατάλογο init.d. Τέλος θα πρέπει να γίνουν update τα links των καταλόγων rc?.d, έτσι ώστε το service να ξεκινάει ή να σταματάει αυτόματα, ανάλογα με το runlevel στο οποίο μεταπηδάει το Raspbian. Οι εντολές για τα δικαιώματα και την ενημέρωση των runlevels είναι οι ακόλουθες:

elias@unificontrol:/opt/UniFi > cd /etc/init.d/
elias@unificontrol:/etc/init.d > sudo chmod 0755 unifid
elias@unificontrol:/etc/init.d > sudo update-rc.d unifid defaults
update-rc.d: using dependency based boot sequencing
elias@unificontrol:/etc/init.d > 

Μπορεί να γίνει να δοκιμή του script που μόλις ενεργοποιήθηκε δίνοντας τις ακόλουθες εντολές και κοιτάζοντας τις αποκρίσεις:

elias@unificontrol:/etc/init.d > sudo /etc/init.d/unifid start
elias@unificontrol:/etc/init.d > sudo /etc/init.d/unifid status
[ ok ] unifid is running.
elias@unificontrol:/etc/init.d > sudo /etc/init.d/unifid stop
elias@unificontrol:/etc/init.d > sudo /etc/init.d/unifid status
[FAIL] unifid is not running ... failed!
elias@unificontrol:/etc/init.d > 

Αν όλα πήγαν καλά, τότε μετά από μια επανεκκίνηση αν εκτελέσουμε την εντολή ps aux | grep ace.jar θα πρέπει να δούμε τα ακόλουθα:

elias@unificontrol:~ > ps aux | grep ace.jar
root      3189 54.0  5.2 370688 25212 ?        Sl   23:43   0:16 /usr/bin/java -jar /opt/UniFi/lib/ace.jar start
elias     3241  0.0  0.1   3548   892 pts/0    S+   23:43   0:00 grep --color=auto ace.jar
elias@unificontrol:~ > 

Αυτό που μας ενδιαφέρει είναι η πρώτη γραμμή που δείχνει πως ένα process τρέχει αυτή τη στιγμή στον επεξεργαστή κι έχει την εντολή ενεργοποίησης του service του UniFi Controller. Η συνέχεια είναι απλή. Ανοίγουμε και πάλι τον browser και δίνοντας την IP διεύθυνση του Raspberry με την πόρτα 8080, όπως κάναμε και πριν, ξεκινάμε την παραμετροποίηση του συστήματος των Access Points. Όταν όλα τελειώσουν μπορούμε να έχουμε μια εικόνα σαν αυτή:

Συμπεράσματα

Το Raspberry Pi, είναι ένα gadgetάκι που, μπορεί κάποιος να μη μείνει ικανοποιημένος αν προσπαθήσει να το χρησιμοποιήσει όπως ένα Desktop υπολογιστή. Όταν το χρησιμοποιήσετε απλά για internet κ.λ.π. θα διαπιστώσετε ότι μοιάζει πολύ με ένα υπολογιστή τεχνολογίας εποχής του KDE3. Ναι μεν μπορείς να κάνεις κάποια δουλειά, αλλά οι χρόνοι καθυστέρησης σε γυρίζουν λίγο πίσω... Από την άλλη, σαν ένας μικρός server έχει αρκετά πλεονεκτήματα. Έχει ικανοποιητική ταχύτητα για τη διαχείριση ενός μικρού δικτύου. Μπορεί να αναλάβει "μικροδουλειές" όπως backup/file server, firewall ή ακόμα και για να τραβάει φωτογραφίες σαν σύστημα παρακολούθησης/ασφάλειας. Στη δική μας περίπτωση, αυτό που μας ενδιέφερε είναι να μπορέσει να λειτουργήσει ως διαχειριστής δικτύου ξενοδοχείου και αυτή τη δουλειά την κάνει αρκετά καλά.

Μια ακόμα δυνατότητα είναι πως μπορεί πολύ εύκολα να τροφοδοτηθεί από μια επαναφορτιζόμενη μπαταρία. Λόγω την μικρής του κατανάλωσης μια τέτοια μπαταρία είναι ικανή να το κρατήσει σε λειτουργία για πραγματικά πολλές ώρες, σε περίπτωση διακοπής της ΔΕΗ.

Όσο για την τιμή του, είναι ιδανική για αυτό που προσφέρει και αυτά που μπορεί να κάνει, ειδικά σαν "δικτυακό βοήθημα". Οι γενικές εντυπώσεις μας είναι άριστες!

Ηλίας Χρυσοχέρης

Σάββατο 11 Μαΐου 2013

Ubiquity UniFi Controller Software στο openSUSE

Το ξεκίνημα της ιστορίας

Κάποια στιγμή μου ζητήθηκε από ένα φίλο να τον βοηθήσω να στήσει ένα δίκτυο σε ένα ξενοδοχείο. Μετά από λίγο ψάξιμο βρέθηκαν τα κατάλληλα εργαλεία για αυτή τη δουλειά: τα Access Points της Ubiquity. Συγκεκριμένα η απόφαση πήγε στη σειρά UniFi που έχουν καταπληκτικά χαρακτηριστικά. Δίνουν τη δυνατότητα για custom guest portal για την είσοδο των πελατών, δημιουργία VPNs, μέχρι τέσσερα διαφορετικά SSIDs με το καθένα από αυτά να έχει τα δικά του χαρακτηριστικά, ορισμό μέγιστου bandwidth για κάθε client που συνδέεται επάνω, ορισμό μέγιστου ποσού δεδομένων που θα διακινήσει και πολλά άλλα. Όλα αυτά τα δίνουν σε αρκετά προσιτή τιμή.

Το μειονέκτημα που υπάρχει στην όλη ιστορία είναι πως για να έχει custom guest portal, ή δημιουργία voucher για τους πελάτες, θα πρέπει ένας υπολογιστής να τρέχει συνεχώς το software της μαμάς εταιρίας (Ubiquity). Για να λυθεί αυτό, αρχικά υπήρχε η ιδέα να χρησιμοποιηθεί το μηχάνημα της reception του ξενοδοχείου για αυτή τη δουλειά. Όμως το μηχάνημα αυτό θα πρέπει να σβήνει κάποιες φορές... Άλλο ένα μειονέκτημα είναι ότι το συγκεκριμένο μηχάνημα τρέχει το ακατονόμαστο λειτουργικό.

Μετά από μια επίδειξη του Ubuntu και του openSUSE, παρότι έχει κάποια ιδέα αυτός ο φίλος από Linux, προτίμησε (τι αναπάντεχο...) να χρησιμοποιήσει το προσωπικό του μηχάνημα με openSUSE και το software της Ubiquity να τρέχει σε αυτό το μηχάνημα. Αυτό το μηχάνημα δεν σβήνει ποτέ, οπότε είναι η καλύτερη ιδέα!

Τι θα δούμε

Τα κομμάτια που θα δούμε σε αυτό το άρθρο είναι τα ακόλουθα:

Προεργασία

Η προεργασία για το στήσιμο του συστήματος έχει το κλασικό backup αρχείων, εγκατάσταση του openSUSE στον υπολογιστή και επαναφορά των αρχείων από το backup του προηγούμενου λειτουργικού

Στη συνέχεια θα πρέπει να εγκατασταθούν οι εξαρτήσεις που χρειάζεται το UniFi Controller Software. Αυτές δεν είναι πολλές:

  • Java
  • MongoDB

Η Java είναι από την αρχή εγκαταστημένη στο openSUSE (όπως και σε κάθε διανομή Linux), οπότε το μόνο που υπήρχε σαν εγκατάσταση είναι η database MongoDB. Δεν υπάρχει ευκολότερο πράγμα από αυτό. Απλώς ανοίγουμε το YaST (από το κεντρικό μενού επιλέγουμε το tab "Computer" και από τη λίστα που εμφανίζεται επιλέγουμε το "Install/Remove Software"

Μετά την εισαγωγή του συνθηματικού του root, ανοίγει το κεντρικό παράθυρο του "YaST - Software Management". Στο πεδίο εύρεσης γράφουμε το "mongodb" και πατάμε το "Search". Στο δεξί τμήμα του παραθύρου εμφανίζεται και το πακέτο που μας ενδιαφέρει. Κάνουμε διπλό κλικ επάνω του και αμέσως μαρκάρεται για εγκατάσταση. Πατώντας το "Accept" ξεκινάμε την εγκατάσταση του πακέτου μας:

Εγκατάσταση του UniFi Controller

Η εγκατάσταση του συστήματος είναι εύκολη. Δεν έχει κάτι το περίπλοκο. Το πρόγραμμα διατίθεται σε μορφή συμπιεσμένου αρχείου .zip σε δύο εκδόσεις:

Όποια έκδοση και αν προτιμήσετε η εγκατάσταση γίνεται με τον ίδιο τρόπο. Σε γενικές γραμμές, για να είναι κάπως clean το σύστημα, προτείνεται εγκαταστάσεις τέτοιου είδους (που δεν είναι δηλαδή από αποθετήρια του λειτουργικού) να γίνονται στον κατάλογο /opt/, ή στον κατάλογο /usr/local/. Εδώ η εγκατάσταση θα γίνει στον κατάλογο /opt/. Απλά αποσυμπιέστε ως root τα περιεχόμενα του αρχείου .zip που κατεβάσατε, στον κατάλογο /opt/.

eliaschr@orion:~> su
Password: 
orion:/home/eliaschr # cd /opt/
orion:/opt # unzip /home/eliaschr/Downloads/UniFi.unix.zip
.
.
.
orion:/opt # 

Δημιουργία group unifi - Προαιρετικό Βήμα

Επειδή λογικά θα χρειάζεστε κατά καιρούς να κάνετε κάποιες αλλαγές, όπως δημιουργία guest portal κ.λ.π. που έχουν να κάνουν με απ' ευθείας αλλαγές στα αρχεία του δίσκου, καλό είναι να δημιουργήσετε ένα group με ονομασία unifi και να κάνετε τα αρχεία του καταλόγου UniFi/data να ανήκουν σε αυτό το group. Αν ενεργοποιήσετε και το SGID bit του εν λόγω υποκαταλόγου, τότε κάθε καινούργιο αρχείο ή κατάλογο που θα δημιουργείτε μέσα στον data θα ανήκει στο group unifi. Είναι προαιρετικό βήμα, αλλά ας δούμε πως γίνεται. Γενικά, οι επεξηγήσεις που υπάρχουν γίνονται όσο το δυνατόν με λιγότερη χρήση κονσόλας για να είναι λίγο πιο κατανοητά σε καινούργιους χρήστες του λειτουργικού:

Η δημιουργία του group γίνεται από το YaST. Αφού γίνει η επιλογή του YaST από το μενού και δωθεί ο κωδικός του root, εμφανίζεται το κεντρικό παράθυρο. Για τη δημιουργία ένός group γίνεται επιλογή της ομάδας "Security and Users" και στη δεξιά πλευρά του "User and Group Management"

Το παράθυρο που ανοίγει δείχνει τους χρήστες που υπάρχουν αυτή τη στιγμή στο σύστημα. Στο επάνω μέρος υπάρχουν τέσσερις καρτέλες. Η δεύτερη ονομάζεται "Groups" και μιας και μας ενδιαφέρει να προσθέσουμε ομάδα στο σύστημα, την επιλέγουμε. Με την επιλογή της καρτέλας των ομάδων, εμφανίζονται στην οθόνη οι διαθέσιμες ομάδες ενώ στο κάτω τμήμα της οθόνης υπάρχει το πλήκτρο προσθήκης "Add". Με την επιλογή αυτού του πλήκτρου εμφανίζεται το παράθυρο της προσθήκης ομάδας.

Στη θέση ονόματος της καινούργιας ομάδας μπαίνει το όνομα "unifi". Το νούμερο του group δεν χρειάζεται να αλλάξει μιας κι επιλέγεται αυτόματα από το σύστημα. Στο δικό σας σύστημα μπορεί να είναι διαφορετικό. Από τη δεξιά στήλη γίνεται επιλογή των χρηστών που θα έχουν τα δικαιώματα να αλλάζουν τις ρυθμίσεις του guest portal χωρίς να χρειάζεται να γίνονται root. Στο παραπάνω στιγμιότυπο φαίνονται οι ρυθμίσεις στο δικό μου μηχάνημα, όπου έχει προστεθεί και ο δικός μου χρήστης στο εν λόγω group.

Φυσικά, με το πάτημα του πλήκτρου "ΟΚ" εμφανίζεται και πάλι η αρχική εικόνα. Εκεί πρέπει να φαίνεται και η καινούργια ομάδα που μόλις δημιουργήθηκε. Πατώντας και πάλι το "ΟΚ" εφαρμόζονται οι καινούργιες ρυθμίσεις.

Το τελευταίο βήμα είναι να ανήκει ο κατάλογος που μπαίνουν τα δεδομένα στο καινούργιο group. Παράλληλα πρέπει το σύστημα, όταν δημιουργείται ένα καινούργιο αρχείο, να το κάνει να ανήκει και αυτό στο group unifi, αυτόματα. Αυτό χρειάζεται για να μπορεί να το διαβάζει και ο server του UniFi Controller Software. Δυστυχώς, εδώ δε μπορούμε να αποφύγουμε την κονσόλα, αλλά γίνεται με απλές εντολές.

Ανοίγουμε μια κονσόλα και μπαίνουμε ως root εκτελώντας την εντολή su. Μετά την εισαγωγή του password του υπερχρήστη εκτελούνται οι εντολές που φαίνονται εδώ:

eliaschr@orion:~> su
Password: 
orion:/home/eliaschr # cd /opt/UniFi/
orion:/opt/UniFi # mkdir data
orion:/opt/UniFi # chgrp unifi data
orion:/opt/UniFi # chmod g+w data
orion:/opt/UniFi # chmod g+s data

Αυτό που κάνουν οι εντολές είναι να δημιουργήσουν ένα κατάλογο με το όνομα data (εντολή mkdir), να κάνουν τον κατάλογο αυτό να ανήκει στο group unifi που δημιουργήθηκε πριν (εντολή chgrp), να δοθούν δικαιώματα ανάγνωσης κι εγγραφής στο group (πρώτη εντολή chmod) κι επιπλέον, ό,τι αρχείο ή κατάλογος δημιουργείται εκεί μέσα να ανήκει στο group που ανήκει και ο κατάλογος, δηλαδή το unifi (η τελευταία εντολή chmod). Η επόμενη εντολή, χρησιμοποιεί ένα σύστημα που ονομάζεται File Access Control List που προσθέτει επιπλέον δικαιώματα. Αυτό που μας ενδιαφέρει είναι τα αρχεία που δημιουργούνται να έχουν διακαιώματα read/write για τον χρήστη και το group, ενώ για τους υπόλοιπους να έχουν μόνο διακαιώματα διαβάσματος:

orion:/opt/UniFi # setfacl -d -m u::rwX,g::rwX,o::r data

Τέλος, για να είναι ολοκληρωμένη η εγκατάσταση του συστήματος, θα πρέπει να δημιουργήσουμε ένα link προς το εκτελέσιμο της βάσης δεδομένων. Το link βρίσκεται ήδη στον κατάλογο /opt/UniFi/bin/ κι έχει το όνομα mongod. Δυστυχώς δείχνει σε λάθος τοποθεσία, οπότε πρέπει να το διορθώσουμε:

orion:/opt/UniFi # cd bin
orion:/opt/UniFi/bin # rm mongod
orion:/opt/UniFi/bin # ln -s /usr/sbin/mongod mongod

Τώρα το εν λόγω link δείχνει στο σωστό σημείο.

Μέχρι εδώ έχουμε κάνει μισή δουλειά... Βασικά μας δίνεται η δυνατότητα να μπορούμε να αλλάζουμε τα δεδομένα των αρχείων που θα δημιουργεί ο server μέσα στον κατάλογο data και τους υποκαταλόγους του, ως απλοί χρήστες. Η διαφορά είναι πως αν δημιουργήσουμε κάτι δικό μας, τότε για να το διαβάσει σωστά ο server θα πρέπει να του αλλάξουμε τα δικαιώματα, αλλά αυτό πλέον μπορεί να γίνεται εύκολα από το γραφικό περιβάλλον, χωρίς τη χρήση της κονσόλας...

Έλεγχος του UniFi Controller Software

Σε αυτό το σημείο είμαστε έτοιμοι να δούμε αν το πρόγραμμα που μόλις εγκαταστήσαμε τρέχει σωστά. Το πρόγραμμα είναι γραμμένο σε Java άρα για να τρέξει αρκεί να μπούμε σε μια κονσόλα, ως υπερχρήστες και να εκτελέσουμε την εντολή:

orion:/whateverpath # java -jar /opt/UniFi/lib/ace.jar start &

Με την εκτέλεση της εντολής αυτής θα παρατηρήσουμε ότι ο επεξεργαστής αρχίζει και λειτουργεί αρκετά. Μετά από μερικά δευτερόλεπτα, αν δεν έχει εμφανιστεί κανένα μήνυμα λάθους, ο server του UniFi θα έχει ξεκινήσει και ο επεξεργαστής θα έχει πέσει πάλι για ύπνο! Για να τον ελέγξουμε ότι λειτουργεί σωστά αρκεί σε ένα browser να δωθεί η διεύθυνση http://localhost:8080/

Το πρώτο πράγμα που θα εμφανιστεί είναι το προειδοποιητικό μήνυμα για το άγνωστο ssl certificate. Φυσικά και θα πρέπει να γίνει αποδεχτή του και ο browser θα συνεχίσει στην τελική σελίδα που φαίνεται στο στιγμιότυπο:

Το configuration του συστήματος συνεχίζει με το πάτημα του "Next" κ.λ.π. Στο τέλος θα εμφανιστεί το τελικό login screen.

Τώρα ο server έχει δημιουργήσει κάποια αρχεία ρυθμίσεων. Μπορούμε να τα δούμε στον κατάλογο /opt/UniFi/data παρατηρώντας ότι όλα τα αρχεία ανήκουν όντως στην ομάδα unifi όπως ακριβώς ήταν επιθυμητό:

eliaschr@orion:/whateverpath # ls -l /opt/UniFi/data/
total 16
drwxrwsr--+ 2 root unifi 4096 May 10 22:29 backup
drwxrwsr--+ 4 root unifi 4096 May 10 22:30 db
-rw-rw-r--  1 root unifi 2184 May 10 22:29 keystore
-rw-rw-r--  1 root unifi  620 May 10 22:51 system.properties

Αν δεν έχετε ακόμα ενεργοποιημένο κάποιο UniFi Access Point στο δίκτυο δε θα καταλάβετε ένα "πρόβλημα" που υπάρχει. Αν όμως έχετε κάποιο Access Point στο δίκτυο, τότε ας δούμε και πάλι το μήνυμα που υπήρξε στο δεύτερο βήμα της παραμετροποίησης:

Το σύστημα μας λέει πολύ απλά ότι δεν βρίσκει κανένα Access Point...

Κάποιος μπλοκάρει την επικοινωνία... (Firewall)

Ο λόγος που δε μπορούμε να δούμε κανένα από τα Access Points που έχουμε συνδεδεμένα στο δίκτυό μας είναι ότι το Firewall του openSUSE μπλοκάρει την επικοινωνία. Αν γνωρίζουμε λίγα πράγματα από το firewall, τότε μπορούμε να ενεργοποιήσουμε το logging και να δούμε τι προσπαθεί να κάνει ο UniFi Controller το οποίο σταματάει εξ αιτίας του firewall. Θα δούμε μια επικοινωνία broadcast στην πόρτα 10001. Αν επιθυμούμε να έχουμε πρόσβαση στο πρόγραμμα και από άλλο υπολογιστή τότε χρειαζόμαστε και τις πόρτες 8080 και 8443. Αν χρειάζεστε και το shutdown θα πρέπει να ανοιχτεί και η πόρτα 8081. Αυτές είναι οι πόρτες που πρέπει να ανοίξουμε στο τείχος προστασίας για να μπορέσει να λειτουργήσει το σύστημα σωστά.

Επειδή μπορεί να θέλετε να αλλάξετε τις πόρτες που χρησιμοποιεί το σύστημα, τότε για να δείτε το πλήρες σετ που χρησιμοποιούνται από τις ρυθμίσεις, αρκεί να ανοίξετε το αρχείο data/system.properties. Απλά, στις πόρτες που θα ρυθμίσετε το firewall θα πρέπει να θυμηθείτε και την πόρτα 10001.

portal.http.port=8880
portal.https.port=8843
unifi.db.port=27117
unifi.http.port=8080
unifi.https.port=8443
unifi.shutdown.port=8081

Ας δούμε πως θα ανοίξουμε τις πόρτες που θέλουμε στο τείχος προστασίας. Αρχικά ανοίγουμε το YaST (αν δεν το έχουμε ήδη ανοικτό) και από την αριστερή στήλη επιλέγουμε την ομάδα "Security and Users", ενώ από τη δεξιά πλευρά ανοίγουμε το "Firewall"

Στο παράθυρο που θα ανοίξει έχουμε και πάλι κατηγορίες ρυθμίσεων από την αριστερή μεριά και η δεξιά αλλάζει ανάλογα με την κατηγορία που θα επιλέξουμε. Η κατηγορία που ας ενδιαφέρει είναι η "Allowed Services"

Επειδή οι πόρτες που θα ανοίξουμε στο τείχος προστασίας δεν ανήκουν σε κάποια γνωστή υπηρεσία θα πρέπει να τις ορίσουμε χειροκίνητα. Για να γίνει αυτό πατάμε το κάτω δεξιά πλήκτρο που ονομάζεται "Advanced...". Θα ανοίξει ένα καινούργιο παράθυρο στο οποίο θα βάλουμε τα νούμερα από τις πόρτες που μας ενδιαφέρουν. Η ρύθμιση φαίνεται στο ακόλουθο στιγμιότυπο:

Αν υπάρχουν και άλλες πόρτες ρυθμισμένες, απλά προσθέτετε αυτές που φαίνονται στο στιγμιότυπο και δεν σβήνετε τις παλιές. Πατώντας το "ΟΚ" επανερχόμαστε στην προηγούμενη οθόνη.

Αν ρυθμίζετε για πρώτη φορά το τείχος προστασίας, τότε πολύ πιθανό να χρειαστεί να ορίσετε και τη ζώνη προστασίας για την κάρτα δικτύου σας. Για να γίνει αυτό από την αριστερή μεριά του παραθύρου επιλέξτε την κατηγορία "Interfaces". Στη δεξιά μεριά εμφανίζονται όλες οι διαθέσιμες κάρτες δικτύου.

Κάνοντας διπλό κλικ στην κάρτα δικτύου που μας ενδιαφέρει εμφανίζεται ένα παράθυρο για τον ορισμό ζώνης. Εκεί ορίσουμε τη ζώνη που μας ενδιαφέρει και πατάμε το "ΟΚ" επανερχόμενοι στο αρχικό παράθυρο.

Τελειώνουμε τις ρυθμίσεις του firewall πατώντας "Next" και στη συνέχεια "Finish". Μόλις τελειώσει το σύστημα την εφαρμογή των ρυθμίσεων, το τείχος προστασίας πλέον θα αφήνει την επικοινωνία να γίνει κανονικά.

Χρήση του UniFi Controller ως service

Το τελευταίο στάδιο είναι να οριστεί το UniFi Controller ως service, δηλαδή να ανοίγει και να κλείνει ανάλογα με το runlevel του υπολογιστή, χωρίς να χρειάζεται την επέμβαση του χρήστη.

Για να γίνει αυτό θα πρέπει να δημιουργηθεί ένα script που να μπει μέσα στον κατάλογο /etc/init.d/. Αυτό το script θα πρέπει να έχει την ιδιότητα να ξεκινάει και να σταματάει τον server του UniFi, όπως ακριβώς γίνεται και στα υπόλοιπα services του συστήματος. Η βασική βοήθεια για τη συγγραφή αυτού του script είναι το /etc/init.d/skeleton. Με λίγο editing αυτού μπορούμε να φτιάξουμε το ακόλουθο:

#!/bin/sh
#
#     Template SUSE system startup script for service unifid
#     Copyright (C) 1995--2005  Kurt Garloff, SUSE / Novell Inc.
#          
#     This library is free software; you can redistribute it and/or modify it
#     under the terms of the GNU Lesser General Public License as published by
#     the Free Software Foundation; either version 2.1 of the License, or (at
#     your option) any later version.
#
#     This library 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
#     Lesser General Public License for more details.
# 
#     You should have received a copy of the GNU Lesser General Public
#     License along with this library; if not, write to the Free Software
#     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA     
#
# /etc/init.d/unifid
#   and its symbolic link
# /usr/sbin/rcunifid
#
# System startup script for the UniFi Controller Server software of Ubiquity. See
# http://www.ubnt.com/
#
# LSB compatible service control script; see http://www.linuxbase.org/spec/
# 
# Note: This script uses functions rc_XXX defined in /etc/rc.status on
# UnitedLinux/SUSE/Novell based Linux distributions and is based on /etc/init.d/skeleton
# script provided by the openSUSE Community.
#
### BEGIN INIT INFO
# Provides:          unifid
# Required-Start:    $syslog $local_fs $network
# Should-Start:      $time ypbind smtp
# Required-Stop:     $syslog $local_fs $network
# Should-Stop:       ypbind smtp
# Default-Start:     3 5
# Default-Stop:      0 1 2 6
# Short-Description: unifid daemon providing Controller server for UniFi Access Points
# Description:       Start unifid to allow the UniFi Controller Software to be able to
#       control the UniFi Access Points of Ubiquity in the network. The softare runs in Java
#       and is installed in /opt/ directory.
### END INIT INFO
# 
# Any extensions to the keywords given above should be preceeded by 
# X-VendorTag- (X-UnitedLinux- X-SuSE- for us) according to LSB.
# 
# Notes on Required-Start/Should-Start:
# * There are two different issues that are solved by Required-Start
#    and Should-Start
# (a) Hard dependencies: This is used by the runlevel editor to determine
#     which services absolutely need to be started to make the start of
#     this service make sense. Example: nfsserver should have
#     Required-Start: $portmap
#     Also, required services are started before the dependent ones.
#     The runlevel editor will warn about such missing hard dependencies
#     and suggest enabling. During system startup, you may expect an error,
#     if the dependency is not fulfilled.
# (b) Specifying the init script ordering, not real (hard) dependencies.
#     This is needed by insserv to determine which service should be
#     started first (and at a later stage what services can be started
#     in parallel). The tag Should-Start: is used for this.
#     It tells, that if a service is available, it should be started
#     before. If not, never mind.
# * When specifying hard dependencies or ordering requirements, you can 
#   use names of services (contents of their Provides: section)
#   or pseudo names starting with a $. The following ones are available
#   according to LSB (1.1):
#       $local_fs               all local file systems are mounted
#                               (most services should need this!)
#       $remote_fs              all remote file systems are mounted
#                               (note that /usr may be remote, so
#                                many services should Require this!)
#       $syslog                 system logging facility up
#       $network                low level networking (eth card, ...)
#       $named                  hostname resolution available
#       $netdaemons             all network daemons are running
#   The $netdaemons pseudo service has been removed in LSB 1.2.
#   For now, we still offer it for backward compatibility.
#   These are new (LSB 1.2):
#       $time                   the system time has been set correctly
#       $portmap                SunRPC portmapping service available
#   UnitedLinux extensions:
#       $ALL                    indicates that a script should be inserted
#                               at the end
# * The services specified in the stop tags 
#   (Required-Stop/Should-Stop)
#   specify which services need to be still running when this service
#   is shut down. Often the entries there are just copies or a subset 
#   from the respective start tag.
# * Should-Start/Stop are now part of LSB as of 2.0,
#   formerly SUSE/Unitedlinux used X-UnitedLinux-Should-Start/-Stop.
#   insserv does support both variants.
# * X-UnitedLinux-Default-Enabled: yes/no is used at installation time
#   (%fillup_and_insserv macro in %post of many RPMs) to specify whether
#   a startup script should default to be enabled after installation.
#   It's not used by insserv.
#
# Note on runlevels:
# 0 - halt/poweroff                     6 - reboot
# 1 - single user                       2 - multiuser without network exported
# 3 - multiuser w/ network (text mode)  5 - multiuser w/ network and X11 (xdm)
# 
# Note on script names:
# http://www.linuxbase.org/spec/refspecs/LSB_1.3.0/gLSB/gLSB/scrptnames.html
# A registry has been set up to manage the init script namespace.
# http://www.lanana.org/
# Please use the names already registered or register one or use a
# vendor prefix.

# First define a small helper function that converts the number of lines produced by ps
# shell command to a number of LSB status. Needed by the "status" parameter
function ConvertOut() {
        if (( $1 < 2 ))
        then
                CNVOUT=3
        else
                CNVOUT=0
        fi
        return $CNVOUT
}

# Check for missing binaries (stale symlinks should not happen)
# Note: Special treatment of stop for LSB conformance
# java executable must be installed...
JAVA_BIN=/usr/bin/java
test -x $JAVA_BIN || { echo "Cannot find java executable in $JAVA_BIN, or java is not installed..."; 
        if [ "$1" = "stop" ]; then exit 0;
        else exit 5; fi; }
# Also, mongoDB must be installed. The extra step here is that there must be a valid link in
# /opt/UniFi/bin/mongod that points to the mongod executable
MONGOD_BIN=/opt/UniFi/bin/mongod
if [ ! \( -e $MONGOD_BIN \) ]
then
        echo "Cannot find mongod executable in $MONGOD_BIN, or mongoDB is not installed..."; 
        if [ "$1" = "stop" ]; then exit 0;
        else exit 5; fi;
fi
# Last but not least, the java jar file should be present. No need to be executable, because
# it is executed via java -jar ...
UNIFID_BIN=/opt/UniFi/lib/ace.jar
test -e $UNIFID_BIN || { echo "Cannot find UniFi Controller executable in $UNIFID_BIN, or the controller software is not installed..."; 
        if [ "$1" = "stop" ]; then exit 0;
        else exit 5; fi; }
# Source LSB init functions
# providing start_daemon, killproc, pidofproc, 
# log_success_msg, log_failure_msg and log_warning_msg.
# This is currently not used by UnitedLinux based distributions and
# not needed for init scripts for UnitedLinux only. If it is used,
# the functions from rc.status should not be sourced or used.
#. /lib/lsb/init-functions

# Shell functions sourced from /etc/rc.status:
#      rc_check         check and set local and overall rc status
#      rc_status        check and set local and overall rc status
#      rc_status -v     be verbose in local rc status and clear it afterwards
#      rc_status -v -r  ditto and clear both the local and overall rc status
#      rc_status -s     display "skipped" and exit with status 3
#      rc_status -u     display "unused" and exit with status 3
#      rc_failed        set local and overall rc status to failed
#      rc_failed   set local and overall rc status to 
#      rc_reset         clear both the local and overall rc status
#      rc_exit          exit appropriate to overall rc status
#      rc_active        checks whether a service is activated by symlinks
. /etc/rc.status

# Reset status of this service
rc_reset

# Return values acc. to LSB for all commands but status:
# 0       - success
# 1       - generic or unspecified error
# 2       - invalid or excess argument(s)
# 3       - unimplemented feature (e.g. "reload")
# 4       - user had insufficient privileges
# 5       - program is not installed
# 6       - program is not configured
# 7       - program is not running
# 8--199  - reserved (8--99 LSB, 100--149 distrib, 150--199 appl)
# 
# Note that starting an already running service, stopping
# or restarting a not-running service as well as the restart
# with force-reload (in case signaling is not supported) are
# considered a success.

case "$1" in
    start)
        echo -n "Starting unifid "
        ## Start daemon with startproc(8). If this fails
        ## the return value is set appropriately by startproc.
        /sbin/startproc $JAVA_BIN  -jar $UNIFID_BIN start

        # Remember status and be verbose
        rc_status -v
        ;;
    stop)
        echo -n "Shutting down unifid "
        ## Stop daemon with killproc(8) and if this fails
        ## killproc sets the return value according to LSB.

        #/sbin/killproc $FOO_BIN
        $JAVA_BIN -jar $UNIFID_BIN stop

        # Remember status and be verbose
        rc_status -v
        ;;
    try-restart|condrestart)
        ## Do a restart only if the service was active before.
        ## Note: try-restart is now part of LSB (as of 1.9).
        ## RH has a similar command named condrestart.
        if test "$1" = "condrestart"; then
                echo "${attn} Use try-restart ${done}(LSB)${attn} rather than condrestart ${warn}(RH)${norm}"
        fi
        $0 status
        if test $? = 0; then
                $0 restart
        else
                rc_reset        # Not running is not a failure.
        fi
        # Remember status and be quiet
        rc_status
        ;;
    restart)
        ## Stop the service and regardless of whether it was
        ## running or not, start it again.
        $0 stop
        $0 start

        # Remember status and be quiet
        rc_status
        ;;
    force-reload)
        ## Signal the daemon to reload its config. Most daemons
        ## do this on signal 1 (SIGHUP).
        ## If it does not support it, restart the service if it
        ## is running.

        echo -n "Reload service unifid "
        ## if it supports it:
        #/sbin/killproc -HUP $FOO_BIN
        #touch /var/run/FOO.pid
        #rc_status -v

        ## Otherwise:
        $0 try-restart
        rc_status
        ;;
    reload)
        ## Like force-reload, but if daemon does not support
        ## signaling, do nothing (!)

        # If it supports signaling:
        echo -n "Reload service unifid "
        #/sbin/killproc -HUP $FOO_BIN
        #touch /var/run/FOO.pid
        #rc_status -v

        ## Otherwise if it does not support reload:
        $0 try-restart
        rc_status
        #rc_failed 3
        #rc_status -v
        ;;
    status)
        echo -n "Checking for service unifid "
        ## Check status with checkproc(8), if process is running
        ## checkproc will return with exit status 0.

        # Return value is slightly different for the status command:
        # 0 - service up and running
        # 1 - service dead, but /var/run/  pid  file exists
        # 2 - service dead, but /var/lock/ lock file exists
        # 3 - service not running (unused)
        # 4 - service status unknown :-(
        # 5--199 reserved (5--99 LSB, 100--149 distro, 150--199 appl.)

        # NOTE: checkproc returns LSB compliant status values.
        # /sbin/checkproc $FOO_BIN
        # NOTE: rc_status knows that we called this init script with
        # "status" option and adapts its messages accordingly.
        # The only way to test if the java program runs is to check it through ps:
        JAVA_COUNT=$(ps aux |grep $UNIFID_BIN | wc -l)
        # The ps aux shell command if used with the grep shell command, returns one line for grep
        # and another line for the real $UNIFID_BIN file. So the result of the executed command is
        # 1 if the server is stopped, 2 if the server is started. We need to convert these values
        # into valid LSB compliant ones, meaning 3 and 0 respectively. The easiest way to do this
        # is to use a function that returns the correct status
        ConvertOut $JAVA_COUNT
        rc_status -v
        ;;
    #probe)
        ## Optional: Probe for the necessity of a reload, print out the
        ## argument to this init script which is required for a reload.
        ## Note: probe is not (yet) part of LSB (as of 1.9)

        #test /etc/FOO/FOO.conf -nt /var/run/FOO.pid && echo reload
        #;;
    *)
        echo "Usage: $0 {start|stop|status|try-restart|restart|force-reload|reload}"
        exit 1
        ;;
esac
rc_exit

Αυτό το script μπορείτε να το κάνετε copy/paste από εδώ και να το σώσετε μέσα στον κατάλογο του χρήστη με την ονομασία unifid. Οι ακόλουθες εντολές πρέπει να εκτελεστούν σε μια κονσόλα από τον υπερχρήστη για να δημιουργηθεί όλη η υποδομή του service:

orion:/home/eliaschr # cp unifid /etc/init.d/
orion:/home/eliaschr # chmod 0755 /etc/init.d/unifid
orion:/home/eliaschr # ln -s /etc/init.d/unifid /sbin/rcunifid
orion:/home/eliaschr # ln -s /etc/init.d/unifid /usr/sbin/rcunifid

Τώρα θα τεστάρουμε το script και όσα έγιναν για τη χρήση του UniFi ως service. Για να γίνει αυτό θα πρέπει μέσα από το YaST να δούμε τα διαθέσιμα services και να προσπαθήσουμε να ανοίξουμε και να κλείσουμε αυτό που μας ενδιαφέρει, το unifid. Αφού ανοίξουμε το YaST (αν δεν το έχουμε ακόμα ανοικτό) και δώσουμε το password του root θα πρέπει να κάνουμε τα ακόλουθα:

Ανοίγουμε το "System Services (Runlevel)" από την ομάδα επιλογών "System".

Στο παράθυρο που ανοίγει θα πρέπει να περιμένουμε λίγο για να αναγνωρίσει το σύστημα όλα τα services που υπάρχουν και να τα ρωτήσει αν είναι ενεργοποιημένα ή όχι. Μετά από λίγο που θα ολοκληρωθεί η λίστα, μπορούμε να βρούμε το service που μόλις δημιουργήσαμε, με την ονομασία unifid.

Ακόμα πιο ενδιαφέρον είναι αν γυρίσουμε σε Expert Mode, με επιλογή του από το επάνω μέρος της οθόνης. Τότε το παράθυρο μετασχηματίζεται, δίνοντας ακόμα περισσότερες πληροφορίες κι επιλογές:

Μπορούμε να δοκιμάσουμε την ενεργοποίηση και απενεργοποίηση του service από το κουμπί "Start/Stop/Refresh". Μπορούμε να δούμε την κατάσταση του service αν από το πλήκτρο αυτό επιλέξουμε το "Refresh status...". Αρχικά είναι απενεργοποιημένο. Το αναδυόμενο παράθυρο μας ενημερώνει για αυτή την κατάσταση.

Αν δοκιμάσουμε να ενεργοποιήσουμε το unifid από το πλήκτρο με την επιλογή "Start...". Θα ενημερωθούμε ανάλογα:

Φυσικά το αποτέλεσμα θα το δούμε και στη λίστα του κεντρικού παραθύρου. Μπορούμε να ξαναδοκιμάσουμε την κατάσταση που επιστρέφει το script όταν το service είναι ενεργοποιημένο, ξανά με την επιλογή "Refresh status...".

Ας το απενεργοποιήσουμε πάλι να δούμε την αντίδραση του συστήματος. Επιλέγουμε το "Stop...". Το παράθυρο που θα μας εμφανιστεί είναι το ακόλουθο:

Φυσικά, κάθε φορά που κάνουμε start το service ο επεξεργαστής εργάζεται αρκετά για ένα χρονικό διάστημα. Όταν τελειώσει, ο server μας είναι ενεργοποιημένος.

Τέλος, όταν ενεργοποιήσουμε την υπηρεσία στο σύστημα από το κάτω δεξιά κουμπί "Set/Reset", θα δούμε ότι το service θα ενεργοποιηθεί στα runlevels 3 και 5, όπως ακριβώς τα ρυθμίσαμε στο script που γράψαμε.

Όταν το ρυθμίσετε όπως θέλετε μπορείτε να αποθηκεύσετε τις ρυθμίσεις πατώντας το πλήκτρο "ΟΚ".

Από τώρα και στο εξής δεν είναι ανάγκη να ανοίγετε την κονσόλα για να ξεκινάτε το UniFi Controller Software. Εκτός του ότι μπορείτε να το έχετε να ανοίγει με τον υπολογιστή σας, μπορείτε να το ενεργοποιείτε ή απενεργοποιείτε από το YaST.

Όταν το unifid είναι ενεργοποιημένο τότε μπορείτε να κάνετε login σε αυτό από τον browser σας, στη διεύθυνση http://localhost:8080

Συμπεράσματα

Παρότι το πρόγραμμα της εταιρίας Ubiquity έχει γραφτεί σε java και στην αρχή υπήρχαν αμφοβολίες πως θα μπορούσε να λειτουργήσει σωστά ως service, τελικά με λίγο κόπο ακόμα κι αυτό μπόρεσε να λειτουργήσει. Τώρα το σύστημα του ασύρματου δικτύου, μπορεί να παραμετροποιηθεί για τις ανάγκες ενός ξενοδοχείου, ενώ θα μπορούσε να λειτουργήσει ακόμα και σε ένα σύστημα small computer όπως π.χ. το Raspberry Pi, το Cubieboard, το Beagleboard ή ότι άλλο έχετε υπόψη σας :)

Γενικά το UniFi είναι πολύ ενδιαφέρον και αν και ασχολήθηκα κάμποσο μαζί του ξέρω πολύ καλά πως έχει κρυφά σημεία που δεν τα έχω δει ακόμα!

Μια ακόμα επισήμανση που έχω να κάνω είναι πως όλη η διαδικασία ξεκίνησε αρκετό καιρό πριν κι έγινε σε σύστημα openSUSE 12.2

Ηλίας Χρυσοχέρης