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)