UUTTA! Exam on siirtynyt avoimen lähdekoodin piirin. Jatkossa lähdekoodi on kaikkien haettavissa osoitteessa https://github.com/CSCfi/exam.

Aiemmista ohjeista muuttuneet kohdat on merkattu symbolilla (warning)

Exam käännetään, paketoidaan ja käynnistetään Scala Build Tool -työkalun (SBT) avulla, sitä ajetaan Play-sovelluspalvelimen päällä ja Apache HTTP-proxypalvelimen takana. Autentikointi ja autorisointi on ulkoistettu Shibboleth SSO -toteutukselle, josta vastaavat eri HAKA-organisaatiot.

Järjestelmäriippuvuudet

Riippuen käyttöjärjestelmästä, aseta aikavyöhykkeeksi UTC ja käytössä olevan lokaalin oletusenkoodaukseksi UTF-8. Jotta ne asetetaan palvelimen käynnistyessä, tulee ne asettaa profiilitiedostossa, RHEL 6 -palvelimella esimerkiksi näin.

$ sudo vi /etc/environment
    -> kirjoita
    TZ=UTC
    LC_ALL=en_US.UTF-8

Asenna Oraclen tai OpenJDK:n Java versio 1.8, esim:

$ wget --no-check-certificate --no-cookies --header "Cookie: oraclelicense=accept-securebackup-cookie" http://download.oracle.com/otn-pub/java/jdk/8u40-b26/jdk-8u40-linux-x64.rpm
$ sudo rpm -ivh jdk-8u40-linux-x64.rpm
 
# Repositorysta
$ sudo yum install java-1.8.0-openjdk-devel.x86_64

Asenna SBT, esimerkiksi:

$ curl https://bintray.com/sbt/rpm/rpm | sudo tee /etc/yum.repos.d/bintray-sbt-rpm.repo
$ sudo yum install sbt

Asenna Apache HTTP-palvelin, versio 2.2.15 tai uudempi, esim:

$ sudo yum install httpd
$ sudo chkconfig --add httpd
$ sudo chkconfig httpd on
...

(warning) Vaadittu versio muuttunut 8.4 -> 9.4. Tämä siksi, koska uudet toiminnot edellyttävät tukea JSONB-tietokantatyypille, jota vanhemmat postgres-versiot eivät tue.

 Asenna postgresql, versio 9.4 tai uudempi (ks. esim https://wiki.postgresql.org/wiki/YUM_Installation).

$ sudo vi /etc/yum/pluginconf.d/rhnplugin.conf 
-> lisää osion 'main' alle:
exclude=postgresql*
 
$ sudo yum install https://download.postgresql.org/pub/repos/yum/9.6/redhat/rhel-7-x86_64/pgdg-redhat96-9.6-3.noarch.rpm
$ sudo yum install postgresql94-server
$ sudo chkconfig postgresql-9.4 on
$ sudo service postgresql-9.4 initdb

Muokkaa postgresql-serverin autentikointiasetuksia. Ilmeisesti Play ei saa yhteyttä tietokantaan oletuksena olevaa ident-tunnistautumismetodia käytettäessä, joten on suositeltavaa vaihtaa IP:n yli tapahtuvien yhteyksien autentikointimetodiksi md5. Lokaalisti voi luottaa yhteyden olevan autentikoitu, jos haluaa.

$ sudo -u postgres vi /var/lib/pgsql/9.4/data/pg_hba.conf
    -> muokkaa tiedoston lopussa olevia asetuksia vaikka näin
    # TYPE  DATABASE        USER            ADDRESS                 METHOD
    # "local" is for Unix domain socket connections only
    local   all             all                                     trust
    # IPv4 local connections:
    host    all             all             127.0.0.1/32            md5
    # IPv6 local connections:
    host    all             all             ::1/128                 md5

Käynnistä tietokantapalvelin:

$ sudo service postgresql-9.4 start

Asenna Git, esim:

$ sudo yum install git


(warning) Suositeltu NodeJS versio muuttunut 4.x -> 6.9.5. Samalla asennusohjeita päivitetty.
Asenna NodeJS (suositellaan versiota 6.9.5 tai uudempi) ja grunt, esim:

$ curl --silent --location https://rpm.nodesource.com/setup_6.x | sudo bash -
$ sudo yum install -y nodejs
$ sudo npm install -g grunt-cli
 
# Reposta asennus
# $ sudo yum install nodejs npm
# $ sudo npm install -g grunt-cli

Tietokanta

Luo palvelimelle tietokanta sitnet ja käyttäjä haluamillasi tunnuksilla, esimerkiksi:

$ createuser -Upostgres -SPRD sitnet
$ createdb -Upostgres --owner=sitnet sitnet

Jos kaikki on mennyt oikein, seuraavan kirjautumisen pitäisi onnistua:

$ psql -Usitnet sitnet
psql (9.4.1)
Type "help" for help.
sitnet=>

Poistu psql-konsolista komennolla \q

Jos haluat importata tietokannan dumpista:

$ psql -Upostgres sitnet < /tmp/sitnet-dump.psql

Jos haluat ajaa integraatiotestejä tarvitset lisäksi testitietokannan:

$ createdb -Upostgres --owner=sitnet sitnet_test

Apache & Shibboleth

Lisää reverse proxy Exam-järjestelmälle. Apachen tai valitun http-proxyn konfiguraatioon tulee myös organisaatiokohtaiset shibboleth-asetukset. Portti 9000 on Playn oletusportti. Esimerkki:

<VirtualHost 193.166.44.29:443>
	ProxyPreserveHost On
	ServerName https://example.exam.org
	# no proxy for Shibboleth
	ProxyPass /Shibboleth.sso/ !
	ProxyPass / http://127.0.0.1:9000/
	ProxyPassReverse / http://127.0.0.1:9000/

	# Koko asennus Shibboleth-autentikoinnin taakse
	<Location "/">
    	AuthType            shibboleth
    	ShibRequestSetting requireSession 1
    	# http headereita ei saisi käyttää, mutta tämä on nyt ainoa vaihtoehto 
    	ShibUseHeaders      On
    	# tämä olisi suositusten mukainen tapa välittää käyttäjäattribuutit, mutta Play Framework ei tue AJP-protokollaa, joka edellytyksenä
    	# ShibUseEnvironment On 
    	require             valid-user
	</Location>

</VirtualHost>

(warning) Lisätty yhteiskäyttöisyyspalvelun konfiguraatio

Examiin on toteutettu erilaisia integraatiorajapintoja ulkopuolista tiedonhakua ja -siirtoa varten. Exam-sovellus ei rajoita pääsyä näihin rajapintoihin mitenkään, joten autorisointi tehdään apachen konfiguraatioissa:

# interface for getting exam records
<LocationMatch /integration/record>
  Order deny,allow
  Deny from all
  Allow from <IP of the party making the requests>
  Satisfy Any
</LocationMatch>

# interface for getting reservation/room/exam data
<LocationMatch /integration/(reservations|rooms|exams)>
  Order deny,allow
  Deny from all
  Allow from <IP of the party making the requests>
  Satisfy Any
</LocationMatch>

# interface for IOP services, allow access only from dedicated XM server
<LocationMatch /integration/iop>
  Order deny,allow
  Deny from all
  Allow from 86.50.28.251 # subject to change
  Satisfy Any
</LocationMatch>

Toteuttaessa suoritus-, varaus- ja tenttitietoja hyödyntäviä palveluita, on syytä käyttää keskitettyä instanssia/proxya, jolla on kiinteä IP. Näin autorisoinnin konfigurointi on yksinkertaista. Alimpana listattu yhteiskäyttöisyyskonfiguraatio (ks. alla) on syytä ottaa käyttöön jos yhteiskäyttöisyystoiminnallisuutta halutaan tukea.

attribute-map.xml

Kun konfiguroit shibbolethia, pitäisi seuraavat attribuutit (attribute-map.xml) saada headerien mukana Exam-järjestelmään asti:

Virallinen nimi
Nimi Examissa
Käyttö
Pakollinen
Muuta
eduPersonAffiliationunscoped-affiliationkäyttäjärooli(tick) 
eduPersonPrincipalNameeppnkäyttäjätunnus(tick) 
mailmailsähköpostiosoite(tick) 
snsnsukunimi(tick) 
displayNamedisplayNameetunimi(tick) 
Shib-Session-IDShib-Session-IDShibboleth-istunnon tunniste(tick) 
preferredLanguagepreferredLanguagekieli oletus on englanti
schacPersonalUniqueCodeschacPersonalUniqueCodeopiskelijanumero tieto vaaditaan, jos opiskeluoikeuden tarkistus kolmannen osapuolen järjestelmästä on käytössä
employeeNumberemployeeNumbertyöntekijän numero kirjataan suoritukselle opettajan osalta
logout-urllogouturlShibboleth IdP -uloskirjautumisen URL URL, jonne käyttäjä ohjataan exam-uloskirjautumisen jälkeen IdP-uloskirjautumista varten
schacHomeOrganizationhomeOrganisationorganisaation tunnus toistaiseksi käyttöä ainoastaan jaetuissa asennuksissa, joissa käyttäjäkunta koostuu useamman organisaation henkilöistä (katso: Organisaatiotietojen tuonti Examiin)
schacHomeOrganizationType organisaation tyyppi ei vielä käytössä Examissa

Attribuutit tulee olla URL-enkoodattuna:

shibboleth2.xml
 <!--
    To customize behavior for specific resources on Apache, and to link vhosts or
    resources to ApplicationOverride settings below, use web server options/commands.
    See https://wiki.shibboleth.net/confluence/display/SHIB2/NativeSPConfigurationElements for help.

    For examples with the RequestMap XML syntax instead, see the example-shibboleth2.xml
    file, and the https://wiki.shibboleth.net/confluence/display/SHIB2/NativeSPRequestMapHowTo topic.
    -->

    <RequestMapper type="Native">
        <RequestMap applicationId="default" encoding="URL">
     ...

Exam-applikaatio

Lisää järjestelmään haluamallasi tavalla rajoitettu käyttäjä/rooli (tässä: sitnet/sitnet)

$ sudo groupadd sitnet
$ sudo useradd -s /bin/bash -g sitnet -d /home/sitnet sitnet
$ sudo passwd sitnet
$ sudo chown -R sitnet.sitnet /opt/exam
$ sudo chmod 755 /opt/exam

Lähdekoodi

Ota gitiä apuna käyttäen examin-lähdekoodi repositoriosta haluamaasi hakemistoon (tässä käytetään /opt/exam -hakemistoa)

$ cd /opt; sudo -u sitnet git clone https://github.com/CSCfi/exam.git

Tämän jälkeen käytössäsi on viimeisimmän julkaisun lähdekoodit. Jos haluat tietyn version käyttöösi, pitää sinun tehdä checkout julkaisun tägille:

$ git checkout tags/3.3.4

Voit listata kaikki tägit komennolla

$ git tag

Alustus

Luo examin tarvitsemat hakemistot ja anna niille tarvittavat oikeudet, esimerkiksi:

$ sudo mkdir -p /var/lib/exam/attachments
$ sudo chown -R sitnet.sitnet /var/lib/exam

Lopuksi optimoi käyttöliittymän koodit grunt-työkalulla. Tämä pitää tehdä ennen Examin paketointia ja käynnistystä.

$ cd /opt/exam
$ sudo -u sitnet npm install
$ sudo -u sitnet grunt minify

Tämä pakkaa examin käyttöliittymäkoodin tiedostoon public/app/exam.min.js, josta se on applikaation käytettävissä.

Examin asetukset

Asetuksia muokataan asetustiedostojen kautta. Tiedostot sijaitsevat hakemistossa conf. Oletuksena Play käyttää tiedostoa conf/application.conf, mutta tämän voi ohittaa määrittelemällä vaihtoehtoisen asennustiedoston antamalla käynnistysskriptille argumentin -Dconfig.file=conf/myconfig.conf (tai -Dconfig.resource=myconfig.conf).

Versiopäivityksen yhteydessä on aina syytä ottaa versionhallinnasta uusin asetustiedosto pohjaksi, jonka päälle kirjoittaa omat asetuksensa. Sisäisiin asetuksiin (joita ei ole tässä ohjeessa dokumentoitu) on nimittäin saattanut tulla muutoksia, joita ilman ohjelmisto ei välttämättä toimi oikein.

HTTP-proxyyn liittyvät asetukset

Jos reverse proxy ei ole localhost-osoitteessa, täytyy Play eksplisiittisesti konfiguroida luottamaan sen tarjoamaan X-Forwarded-For-headerin sisältämään osoitetietoon. Käyttäjän IP:tä käytetään tarkistettaessa onko käyttäjä varaamallansa tenttikoneella tentin alkaessa. Oletusarvoisesti Play ei luota X-Forwarded-For-headeriin, jos proxy on eri IP:ssä kuin Play-applikaatio. Lisätietoa: https://www.playframework.com/documentation/2.6.x/HTTPServer

play.http.forwarded.trustedProxies=[123.123.123.123]

Play-salasana

(warning) asetuksen nimi muuttunut (play.crypto.secret -> play.http.secret.key)

Play käyttää applikaatiokohtaista salasanaa mm. sessioavainten allekirjoitukseen ja enkryptaustoimintoihin. Salasana on vapaavalintainen ja sen voi määrittää asetustiedostossa

# Secret key
# ~~~~~
# The secret key is used to secure cryptographics functions.
# If you deploy your application to several instances be sure to use the same key!
play.http.secret.key="changeme"

mutta suositeltavampaa on määritellä salasana EXAMIn käynnistysskriptissä komentoriviparametrina (ks. kohta examin käynnistys):

APP_SECRET="J9va1P\\\`crEz<n1fzB5mq_Ru[X;fQS2u6YxO[^::DF=;yAQWxX8wJf/7R0gPsIQhB"

On huomioitava, että jos salasanassa on erikoismerkkejä, pitää ne korvata jollain muulla merkillä tai escapata asiaankuuluvasti (esim `-> \\\`).

Salasanan voi generoida mm. näin

$ sbt
[info] Loading project definition from /opt/exam/project
[info] Set current project to exam (in build file:/opt/exam/)
[CSCEXAM] $ playGenerateSecret
[info] Generated new secret: z/ea_EC=qal0hxzt`fy4]@e[9wOBA/O2QlOG[lyVLRuTVL?=NeM50Xg7@QfM=G=C
[success] Total time: 0 s, completed Apr 8, 2015 9:53:56 AM

Lisätietoa: https://www.playframework.com/documentation/2.6.x/ApplicationSecret

Tietokantayhteys

Yhteysparametrit examin tietokantaan täytyy määrittää asetustiedostossa. Jos tietokanta on luotu tässä dokumentissa kuvatulla tavalla, näyttävät parametrit tältä:

db.default.driver=org.postgresql.Driver
db.default.url="jdbc:postgresql://localhost/sitnet"
db.default.user=sitnet
db.default.password=sitnet

Käyttäjäroolien määritys

Exam tukee kolmea käyttäjäroolia:

  • teacher (opettaja)
  • student (opiskelija)
  • admin (pääkäyttäjä)

Käyttäjärooli asetetaan käyttäjälle kun hän kirjautuu järjestelmään ensimmäisen kerran HAKA:n kautta unscoped-affiliation attribuutin mukaan. Käyttäjällä voi olla myös useampi käyttäjärooli.
Koska unscoped-affiliation attribuutin käyttö ei ole yhdenmukaista eri organisaatioissa, voidaan Examin konfiguraatiossa määritellä, mitä Examin roolia unscoped-affiliation arvot vastaavat.

esimerkiksi:

sitnet.roles = {
  student = [
    "student"
  ]
  teacher = [
    "faculty"
    "affiliate"
    "alum"
  ]
  admin = [
    "staff"
  ]
}

Unscoped-affiliation attribuutti voi sisältää myös useamman roolin puolipisteillä erotettuna. Tässä tapauksessa exam vertailee kutakin roolia omiin määrityksiinsä ja osuman kohdalla asettaa käyttäjälle kyseisen roolin. Esimerkiksi jos vaikka unscoped-affiliation on "x;y;z" ja examin määrityksessä olisi vaikkapa sitnet.roles.teacher="a;b;z;" ja sitnet.roles.student="c;y;d", tulisi käyttäjälle käyttäjäroolit teacher eli opettaja sekä student eli opiskelija.

Hostname

Järjestelmän hostname asetetaan sitnet.application.hostname muuttujaan. Muuttujaa käytetään mm. erilaisten linkkien generoinnissa.

sitnet.application.hostname="https://exam.uni.org"

Sähköpostiasetukset

Exam lähettää erilaisia muistutusviestejä ja raportteja sähköpostilla. Sähköpostiasetukset konfiguroidaan asetustiedostossa

play.mailer.host=smtp.yliopisto.fi
play.mailer.port=587
play.mailer.ssl=true
play.mailer.tls=true
play.mailer.user="exam@yliopisto.fi"
play.mailer.password="111111111"

Järjestelmän sähköpostiosoite

Osoite, jolla järjestelmän lähettämät sähköpostit lähtevät vastaanottajalle.

# mail address for the system, appears in From-header of emails sent by the app.
sitnet.email.system.account="no-reply@exam.edu"

Opintohallintajärjestelmän URL

Opintohallintajärjestelmän osoite asetetaan muuttujaan. Muuttujaa käytetään mm. sähköpostiviesteissä linkkien generointiin, esimerkiksi:

sitnet.baseSystemURL="http://base.uni.org"

Opintojaksohaun tiedot

Opintojaksoja voi hakea ulkopuolisesta järjestelmästä. Haun saa päälle asettamalla sitnet.integration.courseUnitInfo.active=true. Haussa käytettävät URLit määritetään erikseen:

# External course interface in use: true=on, false=off
sitnet.integration.courseUnitInfo.active = true

# URL configuration for the course interface(s). Each URL should have the course code either as path parameter or query
# parameter. Use ${course_code} for marking that part of the path.
# You can specify URLs on a per-organisation basis in order to use different URLs for users belonging to different
# organisations. In that case the key should match with "code" column of organisation table.
# "default" is used if no other match is found. You can remove the "default" key if you don't want a default URL at all.
sitnet.integration.courseUnitInfo.url = {
  default = "http://base.uni.org?courseCode=${course_code}"
  a.uni.org = "http://a.uni.org?courseCode=${course_code}"
  b.uni.org = "http://a.uni.org?courseCode=${course_code}"
} 

(warning) Huom. Jotta organisaatiokohtainen URL-konfiguraatio toimii, täytyy organisaatiotieto olla tuotuna EXAMiin (ks. Organisaatiotietojen tuonti Examiin). Jos tarvetta organisaatiokohtaiselle konfiguraatiolle ei ole, riittää että määrittelee pelkän default-URLin:

sitnet.integration.courseUnitInfo.url = {
  default = "http://base.uni.org?courseCode=${course_code}"
}

Liitetiedostojen hakemisto

Exam tallentaa tenttiin ja kysymyksiin liittyvät tiedostot levylle. Tiedostojen juurihakemiston polku voidaan asettaa kofiguraatiotiedostossa olevaan muuttujaan. Jos polku ei ole absoluuttinen, luodaan hakemisto suhteessa examin juurihakemistoon (/opt/exam/target/universal/stage). Huomioithan että examin käyttäjällä on kirjoitusoikeudet kyseiseen hakemistoon.

# Attachment directory
sitnet.attachments.path=/var/lib/exam/attachments

Tenttien kestot

Tenttien mahdolliset kestot minuuteissa määritellään asetuksissa. Kestot näkyvät käyttöliittymässä siinä järjestyksessä kuin ne on tässä määritelty. Oletusarvona käytetään ensimmäistä kestoa. 

# exam durations available for choosing, in minutes. The order is the same as the one that end user sees on UI. First duration is used as default.
sitnet.exam.durations="45,90,110,180"

Oletusaikavyöhyke

Käyttäjien oletusaikavyöhyke, jota käytetään mm. tenttitilojen kulloisenkin kellonajan määritykseen ja ajan esittämiseen sähköposteissa. Jos oletuksena on, että tenttitilat ja järjestelmän käyttäjät ovat pääasiassa Suomessa, kannattaa käyttää oletusarvoa:

# application timezone, used for:
# - formatting timestamps in emails to users
# - setting default timezone for exam rooms, this affects how and when they are eligible for reservations
# - deciding the moment when user should be having an exam, system needs to take possible DST into consideration
# For allowed values see: http://joda-time.sourceforge.net/timezones.html
sitnet.application.timezone="Europe/Helsinki"

Arvosana-asteikon muokattavuus

Tällä asetuksella voidaan estää opettajaa muuttamasta arvosana-asteikkoa tekemilleen tenteille. Asetus on järkevää ottaa pois käytöstä silloin, kun halutaan että opintojaksolle määritelty arvosana-asteikko määrittää aina myös kaikkien siihen kuuluvien tenttien asteikot.

# Enable / disable possibility of users to override course grade scale for individual exams associated with the course.
sitnet.course.gradescale.overridable=true

Osallistumisoikeuden tarkistus

Opiskelijoiden oikeus ilmoittautua tentteihin voidaan rajoittaa koskemaan tiettyjä opintojaksoja. Exam ei itse ylläpidä tietoa oikeuksista, vaan kyseinen tieto haetaan perusjärjestelmästä. Perusjärjestelmän rajapinnan tulee pystyä ottamaan parametrina opiskelijan yksilöivä tunniste, jonka perusteella sen tulee palauttaa lista opintojaksojen yksilöivistä tunnisteista.

# enable / disable checking of permission to enroll for exams
sitnet.integration.enrolmentPermissionCheck.active=true
# URL for the API implementing this check. The URL should have the employee number either as path parameter or query
# parameter. Use ${employee_number} for marking that part of the path.
# examples: https://x.y.z/enrolmentPermissions?id=${employee_number}
#           https://x.y.z/enrolment/${employee_number}/permissions
# Response should provide EXAM with the identifiers for the courses that the person is allowed to enroll for.
sitnet.integration.enrolmentPermissionCheck.url="https://x.y.z/enrolment/${employee_number}/permissions"

Liitetiedoston maksimikoko

Oletuksena on 50MB. Tätä suurempien tiedostojen tallennus on estetty.

# maximum allowed attachment file size in bytes
sitnet.attachment.maxsize=50000000

Tenttisuoritusten vanhentumisaika

Tällä voidaan määritellä kesto, jonka jälkeen prosessin läpikäyneet tenttisuoritukset poistuvat järjestelmästä. Ajan umpeuduttua suoritukset siirtyvät DELETED-tilaan, jolloin ne eivät enää näy käyttöliittymässä kenellekään ja niiden omistajuustiedot pyyhitään, mutta itse tentit jäävät vielä tietokantaan esim. tilastointitarkoituksia varten. Oletuskesto on kuusi kuukautta.

# Period after which processed exams (aborted, registered or archived) are marked as deleted and thus hidden from users.
# Value is to be provided in ISO 8601 duration format, default is six months
sitnet.exam.expiration.period="P6M"

Yhteiskäyttöisyysasetukset

(warning) Uusi toiminnallisuus

Yhteiskäyttöisyydellä tarkoitetaan mahdollisuutta siirtää tietoja eri oppilaitosten ja niiden EXAM-asennusten välillä sekä hyödyntää tästä syntyviä käyttötapauksia.

Ensimmäisessä vaiheessa tuetaan opiskelijan mahdollisuutta suorittaa "etänä" oman oppilaitoksensa tenttejä varaamalla aikoja ulkopuolisen oppilaitoksen EXAMista. Käänteisesti näin mahdollistetaan ulkopuolisten opiskelijoiden tenttisuoritukset oman oppilaitoksen tiloissa EXAMia apunakäyttäen. Jos tällaista halutaan tukea, tulee olla yhteydessä EXAMin kehittäjätiimiin, sillä organisaation tiedot tulee ensin lisätä yhteiskäyttöisyysjärjestelmään. 

# Interoperability (IOP) services configuration: true=IOP services in use, false=IOP services not in use
sitnet.integration.iop.active = false
# Hostname of the IOP server provided to you by development team
sitnet.integration.iop.host = "http://xm.org"
# Remote reference to your organisation provided to you by development tean
sitnet.integration.iop.organisationRef = "58a934c0e74c004753f50a9795f45327"

Toiminnallisuudet saa käyttöön asennuksessa asettamalla sitnet.integration.iop.active = true.Kun organisaatio kytketään yhteiskäyttöisyysjärjestelmään, annetaan sille tunnus, jonka avulla eri asennukset voivat kommunikoida keskenään.  Samoin yhteiskäyttöisyyspalvelimen tiedot pitää konfiguroida. Kehittäjäryhmä tarjoaa nämä tiedot sen jälkeen kun organisaatio on lisätty järjestelmään.

Examin käynnistys

Examin voi käynnistää sekä palveluna (suositeltu tapa) että manuaalisesti konsolissa. On huomioitava, että postgresql, apache ja shibd ovat käynnistetty ennen examin käynnistystä. Lisätietoa Play-applikaatioiden ajamisesta tuotantoympäristössä: https://www.playframework.com/documentation/2.6.x/Production

Käynnistys palveluna 

Tätä varten täytyy ensin kääntää ja paketoida lähdekoodit.

$ cd /opt/exam
$ sudo -u sitnet sbt clean stage
...
[info] Done packaging.
[success] Total time: 34 s, completed Apr 8, 2015 10:27:16 AM

Samalla SBT luo Playn kännistysskriptin ja muut tarvittavat tiedostot hakemistoon target/universal/stage. Examin start-stop-skripti löytyy lähdekoodeissa paikasta /scripts/exam. Se toimii wrapperina sbt:n generoimalle Playn käynnistysskriptille.

exam
#!/bin/sh
#
# /etc/init.d/exam
#
# chkconfig: - 90 10
# description: EXAM service daemon
# processname: exam
# pidfile: /var/run/exam/exam.pid

### BEGIN INIT INFO
# Provides: exam
# Required-Start: $local_fs $remote_fs $network
# Should-Start: $time
# Should-Stop: $time
# Required-Stop: $local_fs $remote_fs $network
# Default-Start: 3 5
# Default-Stop: 0 1 2 6
# Short-Description: EXAM Service Provider Daemon
# Description: Starts the EXAM Service Provider Daemon.
### END INIT INFO

# Source function library
. /etc/init.d/functions

RETVAL=0
prog="exam"

APP_ROOT_PATH=/opt/exam
APP_STAGING_PATH="${APP_ROOT_PATH}/target/universal/stage"
APP_PATH="${APP_STAGING_PATH}/bin/exam"
APP_USER=sitnet
PID_DIR=/var/run/$prog
LOG_DIR=/var/log/$prog
PID_FILE="${PID_DIR}/${prog}.pid"
LOCK_FILE=/var/lock/subsys/${prog}
APP_SECRET="J9va1P\\\`crEz<n1fzB5mq_Ru[X;fQS2u6YxO[^::DF=;yAQWxX8wJf/7R0gPsIQhB"
APP_OPTS="-Dplay.http.secret.key=\"${APP_SECRET}\" -Dplay.evolutions.db.default.autoApply=true -Dpidfile.path=${PID_FILE}"

[ -e /etc/sysconfig/${prog} ] && . /etc/sysconfig/${prog}

start()
{
    echo -n "Starting ${prog}:"
    if [ -f ${LOCK_FILE} ]; then
        if [ -f ${PID_FILE} ]; then
            read PID < ${PID_FILE}
            if checkpid ${PID} 2>&1; then
                echo "process already running"
                return 1;
            else
                echo "lock file found but no process running for pid ${PID}, continuing"
            fi
        fi
    fi

    mkdir -p ${PID_DIR} ${LOG_DIR}
    chown ${APP_USER}:${APP_USER} ${PID_DIR} ${LOG_DIR}

    su -l ${APP_USER} -c "nohup ${APP_PATH} ${APP_OPTS} > ${LOG_DIR}/${prog}.log 2>&1 < /dev/null" &
    i="0"
    while [ ${i} -lt 20 ]; do
        if [ -f ${PID_FILE} ]; then
            break
        fi
        sleep 1
        i=$[$i+1]
    done
    if [ -f ${PID_FILE} ]; then
        touch ${LOCK_FILE}
        success
    else
        failure
        RETVAL=1
    fi
    echo
}

stop()
{
    echo -n "Stopping exam:"
    if [ -f ${PID_FILE} ]; then
        su -l ${APP_USER} -c "kill `cat ${PID_FILE}`"
        rm -f ${LOCK_FILE} ${PID_FILE}
    fi
    success
    echo
}

status()
{
    if [ -f ${LOCK_FILE} ] && [ -f ${PID_FILE} ]; then
        read PID < ${PID_FILE}
        if checkpid ${PID} 2>&1; then
            echo "${prog} (PID: ${PID}) is running"
        else
            echo "${prog} not running but subsystem is locked"
        fi
    elif [ ! -f ${PID_FILE} ] && [ -f ${LOCK_FILE} ]; then
        echo "${prog} not running but subsystem is locked"
    elif [ ! -f ${LOCK_FILE} ] && [ -f ${PID_FILE} ]; then
        read PID < ${PID_FILE}
        if checkpid ${PID} 2>&1; then
            echo "${prog} (PID: ${PID}) running but subsystem is not locked"
        else
            echo "${prog} is stopped"
        fi
    else
       echo "${prog} is stopped"
    fi
}

case "$1" in
    start)
        start
        ;;
    stop)
        stop
        ;;
    restart)
        stop
        sleep 5
        start
        ;;
    status)
        status
        RETVAL=$?
        ;;
    *)
        echo $"Usage: $0 {start|stop|restart|status}"
        RETVAL=1
esac
exit ${RETVAL}

Skriptin muuttujat (lähinnä APP_ROOT_PATHAPP_SECRET ja APP_USER) tulee asettaa sen mukaan miten asennus on tehty. Riippuen käyttöjärjestelmästä käynnistyskriptin käyttö tapahtuu jotenkin näin:

$ sudo cp scripts/exam /etc/init.d
$ sudo chmod 755 /etc/init.d/exam
$ sudo chkconfig --add /etc/init.d/exam
$ sudo chkconfig exam on
$ sudo service exam start (/stop/restart/status)

Käynnistys konsolissa 

Suositeltu tapa on käynnistää exam palveluna (ks. yllä). Konsolissa ajaminen on hyödyllinen lähinnä kehitys- tai testauskäytössä ja silloinkin on hyvä miettiä, josko sovelluksen käynnistää kehitys-moodissa komennolla run komennon start sijaan.

Lisäksi start-komento on deprekoitu Play-frameworkissa ja poistunee seuraavien päivitysten yhteydessä.

Käynnistääksesi exam tuotantoasetuksilla siirry Examin juurihakemistoon (/opt/exam) ja käynnistä Exam seuraavilla komennoilla

$ sudo -u sitnet sbt start -Dplay.evolutions.db.default.autoApply=true -Dplay.http.secret.key="mysecret" -Dconfig.resource=myconfiguration.conf
[warn] The start command is deprecated, and will be removed in a future version of Play.
[warn] To run Play in production mode, run 'stage' instead, and then execute the generated start script in target/universal/stage/bin.
[warn] To test your application using production mode, run 'testProd' instead.
[info] Wrote /opt/exam/target/scala-2.11/exam_2.11-4.0.0.pom

(Starting server. Type Ctrl+D to exit logs, the server will remain in background)

Ctrl+D jättäää prosessin tausta-ajoon, Ctrl+C tappaa prosessin. 

Esimerkissä on vaihtoehtoisina argumentteina asetustiedoston määrittely (-Dconfig.file, ks. yllä), applikaation salasanan määrittely (-Dplay.crypto.secret, ks. yllä) ja automaattinen tietokantaevoluutioiden suoritus (-Dplay.evolutions.db.default.autoApply). Viimeinen tarkoittaa sitä, että tietokantamuutokset ajetaan sisään ilman vahvistusta käyttäjältä. Lisätietoa: https://www.playframework.com/documentation/2.6.x/Evolutions

Oletuksena Exam käynnistetään application.conf-tiedoston asetuksilla.

Muu konsolikäyttö

Examin voi käynnistää kehitysmoodissa komennolla run.

$ sudo -u sitnet sbt run
[info] Loading project definition from /opt/exam/project
[info] Set current project to exam (in build file:/opt/exam/)


--- (Running the application, auto-reloading is enabled) ---

[info] p.c.s.AkkaHttpServer - Listening for HTTP on /0:0:0:0:0:0:0:0:9000
(Server started, use Ctrl+D to stop and go back to the console...)

Järjestelmää voi testailla ilman shibbolethia, jos asetustiedostossa oleva sitnet.login="HAKA" on muutettu sitnet.login="DEBUG". Tällöin käyttäjät ja käyttäjäroolit tulee olla lisättynä käsin examin-tietokantaan.

Integraatiotestit voidaan ajaa kommennolla test. Sitä ennen koodit pitää olla paketoitu jar-tiedostoon komennolla package. Nämä voidaan yhdistää komennoksi package test. Myös testitietokannan pitää olla luotuna ennen testien ajoa (katso Tietokanta).

$ sudo -u sitnet sbt package test
...
[info] Passed: Total 74, Failed 0, Errors 0, Passed 72, Skipped 2
[success] Total time: 307 s, completed Oct 10, 2017 3:35:38 PM
$

Maturiteetti ja kielentarkastus

Maturiteettitenttityypin käyttöönotto tapahtuu tietokannassa lisäämällä se tuettujen suoritustyyppien joukkoon:

$ psql -Usitnet sitnet

sitnet=> insert into exam_execution_type values (3, 'MATURITY', 'Examination with language inspection process');
INSERT 0 1
sitnet=> \q

Maturiteettiohjeet syötetään niinikään tietokantaan (niin kauan kun muuta käyttöliittymää ei tätä varten ole) relaatioon general_settings seuraavin tiedoin:

  • id: seuraava vapaa id taulussa
  • object_version: 1
  • name: 'maturity_instructions_xx' missä xx joku seuraavista: fi, sv, en
  • value: itse ohje name-kohdassa määritellyllä kielellä. Voi sisältää html:ää

Eli esimerkiksi ruotsinkielinen maturiteettiohje lisätään näin:

$ psql -Usitnet sitnet

sitnet=> insert into general_settings (id, object_version, name, value) values (4, 1, 'maturity_instructions_sv', '<p>Instruktioner på svenska</p>');

Tulostettava tentti

Tulostettava tentti otetaan käyttöön samaan tapaan kuin maturiteetti:

$ psql -Usitnet sitnet

sitnet=> insert into exam_execution_type values (4, 'PRINTOUT', 'Paper exam. No enrolment or review process included');
INSERT 0 1
sitnet=> \q

Pääkäyttäjien lisääminen

Jos ja kun pääkäyttäjän roolin omaavia käyttäjiä ei voda suoraan tuoda HAKA:sta, täytyy käyttäjäroolin korotus tehdä käsin. Käyttäjän, josta halutaan pääkäyttäjä, täytyy ensin kirjautua EXAMiin HAKA-roolissansa. Tämän jälkeen tietokannassa korotetaan roolia vaikkapa näin:

$ psql -Usitnet sitnet

sitnet=> update app_user_role set role_id = (select id from role where name = 'ADMIN') where app_user_id = (select id from app_user where eppn = 'USER_EPPN');
UPDATE 1
sitnet=> \q

Korvaa ylläoleva USER_EPPN kyseisen käyttäjän eppn-tunnisteella. Kun käyttäjä seuraavan kerran kirjautuu EXAMiin, kirjautuu hän pääkäyttäjän roolissa.

Tenttimiskielten muokkaus

Oletuksena EXAMissa on määritelty neljä tuettua tenttimiskieltä, joista opettaja voi valita tenttiä luodessaan: suomi, ruotsi, englanti ja saksa. Nämä ovat ne kielet joilla opiskelijan on katsottu olevan mahdollista suorittaa tentti. Järjestelmään on mahdollista lisätä tai poistaa kieliä muokkaamalla tietokannan relaatiota language. Tietenkään poistaminen ei onnistu noin vain, jos kieli on jo jossain tentissä käytössä. Kielet identifioidaan ISO-639_1-koodin mukaan. Käytännössä kolumnilla name ei ole merkitystä vaan toimii ainoastaan selitteenä tietokannassa.

 

sitnet=> select * from language;
 code |   name   | object_version
------+----------+----------------
 fi   | Suomi    |              1
 sv   | Ruotsi   |              1
 en   | Englanti |              1
 de   | Saksa    |              1
(4 rows)


sitnet => delete from language where code = 'de';
DELETE 1
sitnet => insert into language values ('es', 'Espanja', 1);
INSERT 0 1

Logitiedot

EXAM kirjoittaa logeja hakemistoon logs. Lisäksi jos EXAM on käynnistetty palveluna, kirjautuvat logit lisäksi (oletuksena) tiedostoon /var/log/exam/exam.log. Logia voi kätevästi seurata reaaliajassa komennolla

$ tail -f -n 100 /var/log/exam/exam.log

Logituksen asetuksia voi muokata asetustiedostosta. Ohjeet tähän löytyvät Playn sivuilta: https://www.playframework.com/documentation/2.6.x/SettingsLogger

Järjestelmän päivittäminen

Kun järjestelmää päivitetään, on syytä ottaa huomioon ainakin seuraavat asiat.

Ota varmuuskopiot ainakin seuraavista:

  • hakemisto, joka sisältää examin hallinnoimat liitetiedostot
  • käytettävä konfiguraatiotiedosto application.conf tai muu
  • tietokantadumppi ennen päivitystä
  • mahdolliset omat lähdekoodien kustomoinnit (ks. mm. alla)

Lokalisointi

Examin lokalisointi tapahtuu kahdessa paikassa

  1. Käyttöliittymän lokalisointitiedostot sijaitsevat hakemistossa /public/assets/languages json-tiedostojen muodossa. Tiedostoja on yksi per tuettu kieli ja sisältö on tämän suuntainen

    locale-fi.json
    {
      "sitnet_abort_exam": "Keskeytä tentin suoritus",
      "sitnet_accept_useragreement": "Käyttäjäehtojen hyväksyminen.",
      "sitnet_active_exams": "Opiskelijoille näkyvät tentit",
       ...
    } 

    eli se sisältää listauksen käännöksen tunnisteesta ja varsinaisesta käännöstekstistä. Näihin tiedostoihin sisältyy ylivoimaisesti suurin osa järjestelmän lokalisoinnista.

  2. Palvelimen lokalisointitiedostot sijaitsevat hakemistossa /conf/messages. Tiedostoja on yksi per tuettu kieli ja sisältö on tämän suuntainen

    messages.fi
    email.inspection.ready.subject=Tenttivastauksesi on arvioitu
    email.inspection.comment.subject=Tenttisuorituksen arviointiin on lisätty kommentti
    email.enrolment.no.reservation=HUOM! Et ole vielä varannut tenttiaikaa tenttitilasta
    ...

    Kyseisiä käännöksiä tarvitaan lähinnä järjestelmän lähettämissä sähköpostiviesteissä.

Näitä voi kustomoida mielensä mukaan, muutosten jälkeen exam pitää paketoida ja käynnistää uusiksi (ks: Examin käynnistys). Päivitettäessä Examin lähdekoodeja versionhallinnasta on odotettavissa merge-konflikteja, jos lokalisointitiedostoja on kustomoitu. Konfliktit on itse ratkottava siten että lopputuloksena tiedosto on halutunlainen. Ohjeita editointikonfliktin ratkomiseen löytyy esim. tästä: https://help.github.com/articles/resolving-a-merge-conflict-from-the-command-line/.

 

  • No labels