Cost calculator for brutal sun

As a small side project me and Theron made a web based price calculator for determining the price and about of ingredients are required in order to make all sorts of artisan equipment. We made a web interface and API in order to register the base cost of materials, usually based on the amount of time it would take to gather the items. Then we made a concept of a recipe in order to combine base materials into higher order materials or items. I made the backend and Theron made the graphical interface where people could place orders and read out the price in gold we would take for the trade. These images are from the internal backend components.










The sourcecode is up at https://github.com/AndyNor/andynor/tree/master/conan
Nightwish - Shudder Before The Beautiful
MASTERPLAN - Time To Be King
System Of A Down - B.Y.O.B.
John Givez - Get a Bar of Tha Side
Ed Sheeran - Perfect
The HU - Yuve Yuve Yu

Reimen til rotoren/varmeveksleren på ventilasjonssystemet løsnet også her om dagen. Det ser ut til at den grønne gummikabelen var skjøtet ved smelting i stedet for å bruke en metallnippel. Møtte gjøre noen forsøk med reservereimen før jeg fikk det til. Jeg kuttet reservekabelen i skjøten og forsøkte å borre et hull for å kunne presse nippelen på i begge ender. Det fungerte svært dårlig. Kuttet så litt lenger ut på hver side og så at kabelen var hul inni. Nå var det vesentlig lettere å presse skjøtene sammen, og det ser ut til å holde.
  • En reim rundt varmeveksleren og her motorhjulet på tomgang En reim rundt varmeveksleren og her motorhjulet på tomgang
  • Reim på plass igjen Reim på plass igjen

Det ser ut til at jeg kan kjøpe ekstra reim her samt nye filter når det blir nødvendig fra fra leverandør ved type "25314 Filtersett 14 - SAVE VTR 300/B Tilluft (F7)/Avtrekk (G3)" eller eventuelt fra barefilter.no. Litt billigere ser det ut til.
Logger som ingen ser på har liten verdi. Frem til nå har jeg bare komprimert og arkivert loggene fra denne webserveren, og nå fant jeg ut at det er på tide å bruke dem til noe. Målet var å sette opp et system som automatisk leser inn logfilene fra webserveren min, og gjøre dem søkbare for i et grafisk verktøy med mulighet for å visualisere dataene.

Mitt oppsett: ELK-stack
Mitt oppsett: ELK-stack


Steg 1: Jeg startet først med å eksperimentere litt på en lokal virtuell maskin som jeg bruker for å utvikle og teste ny kode. Etter mye prøving og feiling fikk jeg installert og konfigurert ElasticSearch (database) og Logstash (innsamler og konvertering) slik at jeg fikk opp loggene for webserveren på utviklermaskinen (Apache) i Kibana. Kibana er et grafisk webgrensesnitt for visualisering av slike (og andre) typer logger. Disse tre er kjent som "ELK". I denne konfigurasjonen var det Logstash som leste /var/log/apache/access.log direkte. Som standard bruker Logstash gjeldende tidspunkt, og ikke loggfilens tidspunkt når den setter @timestamp feltet som Kibana grafer opp basert på. Dette måtte derfor overstyres i Logstash sin konfigurasjonsfil. Logstash støtter også funksjonalitet for å slå opp lokasjon, basert på IP. Kibana måtte så konfigureres for å "forstå" koordinatene riktig.

# Logstash konfigurasjon: For å lese inn fra fil, og tvinge lesing fra starten
input {
file {
path => "/var/log/apache2/access.log"
start_position => "beginning"
sincedb_path => "/dev/null"
}
}


# Logstash konfigurasjon: For å få riktig tid (tid fra log)
filter {
...
date {
locale => "en"
match => [ "timestamp", "dd/MMM/yyyy:HH:mm:ss Z" ]
timezone => "Europe/Oslo"
}
...
}


# Logstash konfigurasjon: For GeoIP
filter {
...
geoip {
source => "clientip"
target => "geoip"
database => "/path/to/GeoLiteCity.dat"
add_field => [ "[geoip][coordinates]", "%{[geoip][longitude]}" ]
add_field => [ "[geoip][coordinates]", "%{[geoip][latitude]}" ]
}
mutate {
convert => [ "[geoip][coordinates]", "float"]
}
...
}


# Laste ned GeoLiteCity
curl -O "http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz"
gunzip GeoLiteCity.dat.gz


# Oppsett av ElasticSearch for at GeoIP data skal virke (må gjøres før data importeres)
curl -O https://gist.githubusercontent.com/thisismitch/3429023e8438cc25b86c/raw/d8c479e2a1adcea8b1fe86570e42abab0f10f364/filebeat-index-template.json
curl -XPUT 'http://localhost:9200/_template/filebeat?pretty' -d@filebeat-index-template.json # merk at denne kun gjelder for "logstash-*"
# Noen andre maler
curl -L -O https://download.elastic.co/beats/dashboards/beats-dashboards-1.1.0.zip
unzip beats-dashboards-*.zip
cd beats-dashboards-* && ./load.sh


# Konfigurasjonsendring i ElasticSearch (./config/elasticsearch.yml)
node.name: NAVN
path.data: /new/path/
path.logs: /new/path/


Steg 2: Logger tar mye plass, og for å unngå at de fyller opp harddisken, er det vanlig å ha roterende logger. På min server er det satt opp en rotasjon på 7 dager, der den 8. dagen overskriver loggen fra dag 1 osv. Siden jeg ønsker å ta vare på loggene, har jeg et lite script som kjører en gang hver dag. Dette scriptet tar gårsdagens loggfil, komprimerer den, og lagrer den i en struktur basert på /år/måned/ med en komprimert fil per dag. Jeg måtte derfor lage et lite script som tar alle disse filene, pakker dem opp og samler alt innholdet i en stor tekstfil (ArkivApache). I motsetning til steg 1, der jeg satt Logstash til å overvåke og lese inn endringer fortløpende fra en fil, kan logstash også konfigureres til å ta imot data via stdin (standard input). Metoden for å importere "gamle" data blir da å kjøre "logstash < ArkivApache".

Steg 3: Utfordringen i live-miljøet mitt (andynor.net) er at jeg bruker såkalt "shared hosting" der jeg deler en Linux-server med flere andre. Jeg har derfor ikke root-tilgang, og kan ikke installere programvare via pakkebehandlere som "apt-get". Løsningen ble derfor å kjøpe en server der jeg har full tilgang. Jeg gikk for en pakke med 2GB ram, to CPU-kjerner og 48GB SSD fra Linode til 20$ i måneden. Denne satt jeg opp med en Linuxdistro kalt Debian. Når man setter opp en maskin med en offentlig IP-adresse, må den selvsagt beskyttes. Etter at det var gjort, gjorde jeg noen forsøk med en lettvekts virtualiseringsteknologi kalt Docker, men gav til slutt opp. Det er spennende teknologi, men jeg støtte på en del unødvendige utfordringer. Jeg installerte så Logstash, ElasticSearch og Kibana på denne nye maskinen, åpnet opp nødvendige porter i brannmuren og plasserte Kibana bak en Nginx-webserver med enkel autentisering.

# Nginx konfigurasjon (/etc/nginx/sites-available med symlink til sites-enabled)
server {
listen 80;
auth_basic "Restricted Access";
auth_basic_user_file /etc/nginx/htpasswd.users;

location / {
proxy_pass http://localhost:5601;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}


Steg 4: Nå ligger den såkalte "ELK" programvaren, og loggfilene på to forskjellige maskiner, og jeg trengte derfor en måte å få oversendt dem på. Jeg installerte Filebeat på webserveren, og satte opp en forbindelse mot Logstash på Linode-serveren. Måtte også åpne opp porten i brannmuren/iptables. Her benyttes sertifikater for å kryptere forbindelsen. I tillegg trengte jeg en enkel måte å sørge for at programmene alltid kjører. For det benyttet jeg Cron og noen enkle bash-script.

# Konfigurasjon av Logstash
input {
...
beats {
type => "apache"
port => 5044
ssl => true
ssl_certificate => "/path/to/logstash-forwarder.crt"
ssl_key => "/path/to/logstash-forwarder.key"
}
...
}


# Laste ned og konfigurasjon av filebeat
wget https://download.elastic.co/beats/filebeat/filebeat-1.1.2-x86_64.tar.gz # https://www.elastic.co/downloads/beats/filebeat
# filebeat.yml
filebeat:
prospectors:
-
paths:
- /path/to/access.log
input_type: log
document_type: apache
output:
logstash:
hosts: ["IP:5044"]
bulk_max_size: 1024
tls:
certificate_authorities: ["/path/to/logstash-forwarder.crt"]
logging:
to_files: true
files:
path: /home/andynor/serverapps/logs/
name: mybeat
rotateeverybytes: 10485760 # = 10MB
keepfiles: 7


# Lage sertifikater som lar filebeat snakke med logstash
# Min linode-server har ikke et domene (enda), så jeg måtte gjøre denne endringen
sudo nano /etc/ssl/openssl.cnf
# Legge til under "[ v3_ca ]" linjen: subjectAltName = IP: logstash_server_private_ip
sudo openssl req -config /etc/ssl/openssl.cnf -x509 -days 3650 -batch -nodes -newkey rsa:2048 -keyout logstash-forwarder.key -out logstash-forwarder.crt
# Offentlig nøkkel kan så kopieres til filebeat-klientene med scp
scp FIL USER@SERVER:PATH



crontab -l # edit cron jobs. -e for edit
*/3 * * * * /apps/elk/process_ctrl # hvert 3. minutt, kjør dette bash-scriptet
# Eksempel på process_ctrl
#!/bin/bash
OUTPUT="$(ps ux | grep elasticsearch | wc -l)"
if [[ ${OUTPUT} -lt 2 ]] ; then
nohup /apps/elk/bin/elasticsearch-2.2.1/bin/elasticsearch &
sleep 30
fi



Steg 5: Oppsett av Kibana dashboard er der moroa begynner. En Apache-log inneholder følgende informasjon:
  • timestamp (tidspunkt for hendelse)
  • clientip (som kan "oversettes" til en omtrentlig lokasjon basert på fordeling av IP-ranges)
  • verb (post, get osv)
  • request (URL som etterspørres)
  • referrer (URL nettleseren kom fra - ofte ikke i bruk)
  • agent (Navn på nettleser som ber om innhold)
  • auth (autentisering - hvis bruker er autentisert med webservers innebygde auth-mekanisme)
  • response (statuskode, normalt 200 OK)
  • bytes (antall byte som ble sendt til klienten)


Basert på dette er det masse spennende som kan grafes opp. F.eks:
  • Heatmap-kart over lokasjoner
  • Tid på x-aksen og (antall) IP-adresser på y-aksen, stacked
  • Antall unike IP-adresser
  • Mest etterspurte requests
  • Tid på x-aksen og (antall) response på y-aksen

Første versjon av mitt dashboard.
Første versjon av mitt dashboard.


Kilder:
hackzine.org: Importing Apache logs in ElasticSearch
linode.com: Visualizing Apache Webserver Logs in the ELK Stack on Debian 8
michael.bouvy.net: Collect & visualize your logs with Logstash Elasticsearch & Redis

Crawling for music part2

In a previous post (Crawling for music) I tried to automate the process of importing the soundtracks played in the Freakonomics podcast via their tags in the audio transcripts. Some time has passed, new songs have been added and my script required some maintenance. These are the new Python scripts:

freakocrawl
size 5.4 KiB
sha256: d2f9adde3e...bd5a7d476d

spotify_check
size 584.0 bytes
sha256: e71b09fd9c...787732cf6b

raw_music_tags
size 132.4 KiB
sha256: 57f3225cb7...eb6e9256e1

visited
size 16.8 KiB
sha256: 9cbc450b03...12f0500e9c



Removed a lot of unnecessary code and keep track of previously visited pages in order to avoid looking up a page over and over again.

  • Of the 296 unique songs found so far, 140 was found on Spotify (compared to 60 last run) Of the 296 unique songs found so far, 140 was found on Spotify (compared to 60 last run)
  • All tags gathered so far in raw format All tags gathered so far in raw format
  • After a lot of regex manipulation After a lot of regex manipulation
  • On the clipboard after using the ivy service. Use On the clipboard after using the ivy service. Use "spotify_check.py" for finding the difference between two such listings.


    Still using ivyishere.org though. Perhaps I'll look into using the Spotify API directly later...


    Server backup

    Backup and transfer for files between online of offline environments of this django installation consists of the following steps:

    Backup of mysql databse:
    mysqldump -u username -ppassword > ~/backup/dbs/mysql_`date +%F_%H:%M:%S`.sql

    Restore data to mysql database:
    mysql -u username -ppassword database < restore.sql

    Remove all rows of a table:
    TRUNCATE TABLE table_name;

    Update content in database: (via SQL terminal)
    update table set field = replace(field, 'old', 'new');

    Backup of files:
    tar -zcvf ~/backup/site/django_`date +%F_%H:%M:%S`.tar.gz ~/webapps/django/myproject/
    tar -zcvf ~/backup/site/images_`date +%F_%H:%M:%S`.tar.gz ~/webapps/static_media/
    tar -zcvf ~/backup/site/files_`date +%F_%H:%M:%S`.tar.gz ~/webapps/static/fileupload/

    Collect static
    python2.7 ~/webapps/django/myproject/manage.py collectstatic

    Restart apache
    ~/webapps/django/apache2/bin/restart

    Secure copy
    scp -P port -r target_path username@server:destination_path