dinsdag 20 april 2010

Week 9 (12/04 - 19/04)

Google Maps. Om een overzicht van de datacenters te creeren werd google maps aangehaald. Op zich heel simpel te implementeren via javascript.

Probleem: De locatie van het adres dat ik wou weergeven kwam uit mijn database die via python code & Django naar men html wordt geschreven. Na een beetje googlen kwam ik deze website tegen die een degelijke uitleg gaf en me kon voorzien van de klasse PyMaps (Google Maps voor Python)

Dit gaf een goed resultaat en de locatie uit men database werd goed weergegeven:










Nu wou ik niet alleen het datacenter weergeven dat geselecteerd werd, maar ook een google map die mij een overzicht gaf van alle datacenters in Belgiƫ. Door naar de website maps.google.com te gaan kan je inloggen en meerdere locaties naar je map 'saven' en deze map dan gebruiken in je website.

Probleem: Wat als je locaties weer opgeslagen zitten in een database die via Django/Python met je website communiceert. Je kan deze locaties manueel invoegen via de site en dan die map in je website gebruiken, maar wat dan als iemand via het admin-panel een nieuwe locatie toevoegd?

Oplossing: XML! Google maps werkt met xml en kan locaties uit een xmlbestand halen (in deze xml moet dan wel 'latitude', 'longitude' 'naam', 'adres', enz aanwezig zijn voor elke locatie.

De klasse PyMaps bevat een functie die van het opgegeven adres de coordinaten berekent en deze dan teruggeeft. Door dus een combinatie te integreren van PyMaps & Xml kwam ik tot het volgende resultaat:










De klasse om de locaties op te slaan in het xmlbestand en deze te gebruiken in google maps ziet er zo uit:

from PyMaps import Icon, Map, PyMap
from xml.etree import ElementTree as ET


def savelocations(name, street, postalcode, city, country):
xml_file = os.path.abspath(__file__)
xml_file = os.path.dirname(xml_file)
xml_file = os.path.join(xml_file, MEDIA_ROOT + "media/files/Landmarks.xml")

add = "%s, %s, %s, %s" % (street, postalcode, city, country)
geo_data = get_geo(add)

lat = str(geo_data[1])
long = str(geo_data[0])

tree = ET.parse(xml_file)
child1 = ET.SubElement(tree.getroot(), "Row")
child2 = ET.SubElement(child1, "Longitude")
child2.text = long
child3 = ET.SubElement(child1, "Latitude")
child3.text = lat
child4 = ET.SubElement(child1, "Building_Name")
child4.text = name
child5 = ET.SubElement(child1, "Address")
child5.text = address
tree.write(xml_file)

Week 8 (27/03 - 03/04)

Deze week ben ik begonnen met SNMP. SNMP is een manier om informatie zoals netwerkinterfaces, uptime, system time, beschrijving, naam, enz... op te halen van een bepaalde asset in het netwerk.

Het CMDB zal bij het opvragen van de informatie van een asset die aanvraag uitvoeren en zo de system time & de uptime gaan invullen in het management systeem.

Hieronder ziet u hoe het CMDB toont of de info werd opgehaald of niet:



















De aanvragen van de info gebeuren via OID's. Dit zijn een reeks getallen waaraan de asset weet welke info hij moet teruggeven. Enkele voorbeelden:
  • .1.3.6.1.2.1.1.3 = System Uptime (TimeTicks)
  • .1.3.6.1.2.1.1.1 = System Description
  • .1.3.6.1.2.1.1.5 = System Name
Met behulp van de klasse SNMPWalk.py en de klasse SNMPGet.py (hieronder weergegeven) werd het dan mogelijk om die informatie te gaan opvragen aan een asset.

SnmpGet.py:

from pysnmp import role, v2c, asn1

class SNMPGet:

def __init__(self, host, port, community):
self.host = host
self.port = port
self.community = community

def snmpget (self, oid):
req = v2c.GETREQUEST ()
encoded_oids = map (asn1.OBJECTID().encode, [oid,])
req['community'] = self.community
tr = role.manager ((self.host, self.port))
rsp = v2c.RESPONSE ()
(rawrsp, src) = tr.send_and_receive (req.encode (encoded_oids=encoded_oids))
rsp.decode (rawrsp)
oids = map (lambda x: x[0], map(asn1.OBJECTID ().decode, rsp['encoded_oids']))
vals = map (lambda x: x[0] (), map(asn1.decode, rsp['encoded_vals']))
return vals

Week 7 (20/03 - 27/03)

Na het afronden en testen van de functie om te telefoneren (zie week 6) heb ik enkele bugs uit de design gehaald en aan de design nog enkele dingen toegevoegd. Vooral met betrekking op de gebruiksvriendelijkheid.

Ook is het weergeven van informatie van een gebruiker of fabrikant toegevoegd aan het CMDB. Dit is gebeurd aan de hand van een variant op Lightbox (hieronder een screenshot).






vrijdag 16 april 2010

Week 6 (13/03 – 20/03)

Nadat het adminpanel volledig was afgewerkt in django, ben ik begonnen aan de eigenlijke website (voormalig php, nu django (python)).

Omdat alle interne website's bij aserver beveiligd zijn via SSL, moest het asset management system ook over SSL worden aangeboden. Daarom is de login-pagina vervangen door SSL-Authentication

De layout van de website is behouden (zie vorige posts).

Deze week heb ik ook de resultpage van het zoekvenster aangepast. Het probleem was het volgende:

Omdat de tabellen maar in 1 richting naar elkaar linken, en ik van elke query die opgezocht werd ook het IP-adres, het MAC-adres, enz wou ophalen, werd er eerst gezocht door alle IP-addressen van de verschillende machine's en dan gekeken welke naam ze hadden. Deze naam werd vervolgens vergeleken met de query.

Probleem: Wat als een bepaalde asset geen IP-Adres heeft? Het management systeem bevat even goed assets die in de stock liggen bijvoorbeeld.

Dus werd dit alles aangepast en werd er gezocht op naam. EƩnmaal alle gezochte assets gevonden waren, werden ze opgenomen in 1 lijst, waar dan vervolgens de bijkomende info zoals vb. IP-Adres werd toegevoegd. Wanneer er bepaalde zaken niet werden gevonden in de database, werden deze vervangen door een "/"

Hier ook nog even een screenshot ter verduidelijking:










Nadat dit probleem opgelost was ben ik begonnen aan de'Phone-To' gedeelte. Er werd namelijk gevraagd om het mogelijk te maken te telefoneren vanop het cmdb, zowel intern als extern.

Hoe?: Iedereen in het bedrijf is in het bezit van een IP-Phone. Daarbij heeft elke gebruiker zijn eigen SIP (id). Via deze IP-Phone's is het mogelijk om naar anderen te bellen zowel intern als extern. Wat nu nog nodig was, was een script dat het via Python/Django mogelijk maakt deze telefoons te gebruiken.

Het eerste wat we doen is kijken of er een gebruiker is ingelogd en enkele variabelen definieren indien het SIP van de ingelogde gebruiker geldig is! Het asterisk_ip & port zijn het ip en de poort van de telefoon-server:
def phonecall(request, usersto, usersip, phonenumber):
currentuser = checkvaliduser(request, request.META['REMOTE_USER'])
if currentuser:
if usersip != "None":
asterisk_ip = "172.19.0.8"
asterisk_port = 5038
callerid = "93242577"
errno = 0
errstr = 0

connectingto = Users.objects.get(user_id=usersto)


Daarna gaan we aan de hand van volgende code het telefoonnummer controleren van de gebruiker die we willen contacteren. Onderaan kijken we ook of de lengte van de contactpersoon gelijk is aan '3'. Indien dat zo is, wil dit zeggen dat we intern willen bellen naar een andere contactpersoon (via zijn SIP):

phonenumber = phonenumber.strip()
if phonenumber.find("(0)") > -1:
phonenumber = phonenumber.replace("(0)", "")

phonenumber = phonenumber.replace(" ", "")
phonenumber = phonenumber.replace("/", "")
phonenumber = phonenumber.replace(".", "")
phonenumber = phonenumber.replace("-", "")
phonenumber = phonenumber.replace("+", "00")

if phonenumber.find("0", 0, 1) > -1 and phonenumber.find("00", 0, 2) == -1:
phonenumber = "0032" + phonenumber[1:]

if len(phonenumber) == 3:
phonenumber = "SIP/" + phonenumber
else:
phonenumber = "IAX2/Hold/" + phonenumber


Tenslotten nog het in stand brengen van de eigenlijke connectie:

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((asterisk_ip, asterisk_port))
s.send("Action: login\r\n")
s.send("Username: admin\r\n")
s.send("Secret: amp111\r\n")
s.send("Events: off\r\n\r\n")
sys.stdout.flush()
time.sleep(1)
s.send("Action: Originate\r\n")
s.send("Channel: SIP/" + usersip + "\r\n")
s.send("Context: callout\r\n")
s.send("Exten: s\r\n")
s.send("Priority: 1\r\n")
s.send("CallerID: Central\r\n")
s.send("Variable: number_to_dial=" + phonenumber + "|callerid=" + callerid + "\r\n\r\n")
sys.stdout.flush()
time.sleep(2)
s.close()

return dialing(request, currentuser, connectingto)

dinsdag 16 maart 2010

Week 5 (06/03 - 13/03)

Na men vorige post ben ik het admin-panel gaan opbouwen specifiek gericht op het asset-management-system. En het resultaat ziet er als volgt uit:



















Week 4 (27/02 - 06/03)

Deze week is het project een beetje gewijzigd. Aangezien de meeste mensen op A-Server programmeren in Python, werd mij gevraagd het asset-management ook in Python te maken.

Na een beetje research ben ik op het web framework Django gebotst. Het bevat een soort admin-panel dat het mogelijk maakt je website in python te onderhouden. Voor mijn opgave specifiek wil dit zeggen dat het vanuit dit admin-panel mogelijk zal zijn om asset's toe te voegen, te verwijderen en aan te passen. Het browsen tussen de verschillende asset's zal dan gebeuren in de website zelf waarvan ik de design zal gebruiken die in men voorgaande posts wordt weergegeven.

Om het admin-panel iets overzichtelijker en aantrekkelijker te maken, ben ik op de website van grappelli gestoten. Dit is een layout die specifiek is opgebouwd voor het Django adminpanel.

Het werken met databases in Django is een heel stuk anders opgebouwd dan in bijvoorbeeld php. Normaal gezien is het de bedoeling verschillende 'Models' aan te maken in je Python/Django code, en deze Models worden dan door Django zelf opgeslaan en verwerkt in de database. (MySQL in mijn geval). Omdat ik men database reeds had opgebouwd toen ik in php werkte, moest ik een manier vinden om via mijn bestaande database te werken.

Django werkt enerzijds met een aantal tabellen die hij zelf automatisch aanmaakt (Dit voor authenticatie van het admin-panel) en anderzijds met de zelf aangemaakte models.

Het is via volgende code mogelijk om van een bestaande database automatisch de Models te laten genereren:

python manage.py inspectdb > models.py

Deze code zal de database gaan bekijken en dan de Models ervan zelf toevoegen in het
bestand 'Models.py'. Deze Models zien er dan ongeveer zo uit:

class Datacenter(models.Model):
datacenter_id = models.AutoField(primary_key=True)
datacenter_name = models.CharField(('Name'), max_length=135)
datacenter_location = models.ForeignKey(Location, verbose_name='Location')

class Meta:

db_table = u'datacenter'

def __str__(self):
return self.datacenter_name


donderdag 4 maart 2010

Week 3 (23/02 – 26/02)

Nu de layout min of meer op punt staat, ging ik verder met de implementatie van het asset management system. Wat er ook gevraagd is, is een overzicht-pagina van een bepaalde rack. Wanneer op de detailpagina van een asset op een rack werd geklikt, moest er een overzicht gegenereerd worden waarop alle servers - die zich in die betreffende rack bevinden - worden getoond.

Leuk is natuurlijk ook een overzichtelijke grafische weergave. Doordat de meeste server-merken zelf ook visio-templates uitbrengen voor hun modellen, (zoals hp, cisco,... ) werd het mogelijk voor een bijvoorbeeld een dell poweredge 750 ook effectief die afbeelding te tonen in het rack. Verder werden deze dan ook aanklikbaar gemaakt. Op die manier komt in de lijst aan de rechterkant de assetnaam in het vet op het moment dat je met de muis over de afbeelding van de server gaat.

Met behulp van image replacements en visio-templates, ben ik er in geslaagd onderstaande overzichtpagina te genereren: