Commits

Frank Becker committed ceb7757

1st version where all data from the hardwaredb is loaded

Comments (0)

Files changed (12)

install/requirements.txt

 pyScss==1.1.3
 pytz==2012b
 milkman
+easy_thumbnails
+git+http://github.com/justinlilly/django-gencal.git#egg=django_gencal

src/booker/models.py

+# -*- coding: utf-8 -*-
+
+"""models of myhost app, holds the Django models
+"""
+
 from django.db import models
+from datetime import datetime
+from django.utils.translation import ugettext_lazy as _
+from hosts.models import Host, MyHostUser
 
-# Create your models here.
+
+class HostSchedule(models.Model):
+    """schedule host per user"""
+
+    PRIORITIES = (
+        ('1', 'highest'),
+        ('2', 'high'),
+        ('3', 'normal'),
+        ('4', 'low'),
+        ('5', 'lowest'),
+    )
+
+    time_from = models.DateTimeField(
+        verbose_name=_("Time from"),
+        help_text=_(u"Timestamp until the host will be scheduled."),
+    )
+
+    time_to = models.DateTimeField(
+        verbose_name=_("Time to"),
+        help_text=_(u"Timestamp until the host will be scheduled.")
+
+    )
+
+    host = models.ForeignKey(
+        Host,
+        verbose_name=_("Host"),
+        help_text=_(u"Host to schedule.")
+    )
+
+    user = models.ForeignKey(
+        MyHostUser,
+        verbose_name=_("Host User"),
+        help_text=_(u"User that books the host.")
+    )
+
+    comment = models.TextField(
+        verbose_name=_("Comment"),
+        help_text=_(u"Why is the host scheduled?")
+    )
+
+    priority = models.CharField(
+        verbose_name=_("Priority"),
+        help_text=_(u"Booking priority from 1(highest) to 5(lowest). Not used "
+                    u"for now."),
+        choices=PRIORITIES,
+        max_length=1,
+    )
+
+    booked = models.BooleanField(
+        verbose_name=_("Booked"),
+        help_text=_(u"True if the host is booked."),
+        default=False,
+        editable=False,
+    )
+
+    time_scheduled = models.DateTimeField(
+        verbose_name=_("timestamp of first save"),
+        editable=False,
+        )
+
+    time_last_update = models.DateTimeField(
+        verbose_name=_("last update"),
+        editable=False,
+    )
+
+    class Meta:
+        ordering = ("time_from",)
+
+    def __unicode__(self):
+        return u"{0}: {1}, {2}-{3}-{4} - {5}-{6}-{7}".format(
+            self.user.user.ldap,
+            self.host.name,
+            self.time_from.year,
+            self.time_from.month,
+            self.time_from.day,
+            self.time_to.year,
+            self.time_to.month,
+            self.time_to.day,
+        )
+
+    def save(self, **kwargs):
+        """save, check etc.
+        """
+        # FIXME (a8): needs to be implemented
+        if not self.time_scheduled:
+            self.time_scheduled = datetime.now()
+        self.time_last_update = datetime.now()
+        super(HostSchedule, self).save(**kwargs)
+

src/djweb/settings.py

 # Django settings for djweb project.
 import os
+import pytz
 
 DEBUG = True
 TEMPLATE_DEBUG = DEBUG
 DATABASES = {
     'default': {
         'ENGINE': 'django.db.backends.sqlite3',  # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
-        'NAME': 'database/db.sqlte3',           # Or path to database file if using sqlite3.
+        'NAME': 'database/db.sqlite3',           # Or path to database file if using sqlite3.
         'USER': '',                      # Not used with sqlite3.
         'PASSWORD': '',                  # Not used with sqlite3.
         'HOST': '',                      # Set to empty string for localhost. Not used with sqlite3.
     'south',
     'compressor',
     'haystack',
+    'widget_tweaks',
+    'easy_thumbnails',
+    'gencal',
+    'taggit',
     # myhosts modules
     'hosts',
+    'booker',
 )
 
 # A sample logging configuration. The only tangible logging
 HAYSTACK_SEARCH_ENGINE = 'whoosh'
 HAYSTACK_WHOOSH_PATH = BASEDIR + '/whoosh'
 HAYSTACK_SEARCH_RESULTS_PER_PAGE = 8
+
+THUMBNAIL_ALIASES = {
+    '': {
+        'avatar': {'size': (50, 50), 'crop': True},
+    },
+}
+
+DEFAULT_TIMEZONE = pytz.timezone('Europe/Berlin')

src/djweb/urls.py

 
 # Uncomment the next two lines to enable the admin:
 from django.contrib import admin
-from djweb.views import StartView
+from django.conf import settings
+from django.conf.urls import include, patterns, url
+from django.conf.urls.static import static
+from django.contrib.staticfiles.urls import staticfiles_urlpatterns
+
+from djweb.views import StartView, home
 
 admin.autodiscover()
+urlpatterns = static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
+urlpatterns += staticfiles_urlpatterns()
 
-urlpatterns = patterns('',
+urlpatterns += patterns('',
     # Examples:
-    url(r'^$', StartView.as_view(), name='home'),
+    #url(r'^$', StartView.as_view(), name='home'),
+    url(r'^$', home, name='home'),
     # url(r'^djweb/', include('djweb.foo.urls')),
 
     # Uncomment the admin/doc line below to enable admin documentation:
 
     url(r'^hosts/', include('hosts.urls')),
 )
+
+if settings.DEBUG:
+    pass
+    #urlpatterns += patterns('',
+        #(r'^' + settings.MEDIA_URL.lstrip('/'), include('appmedia.urls')),
+    #) + urlpatterns

src/djweb/views.py

 # -*- coding: utf-8 -*-
 
 """views"""
+from django.core.urlresolvers import reverse
+from django.http import HttpResponseRedirect
+from django.template.context import RequestContext
+from django.shortcuts import render_to_response, get_object_or_404
 from django.utils import timezone
 from hosts.models import Host
 
 __author__ = 'a8'
 
 from django.views.generic import TemplateView
+from hosts.forms import SearchForm
 
 class StartView(TemplateView):
     template_name = "start.html"
         context['now'] = timezone.now()
         context['hosts'] = [e[0] for e in Host.objects.all().values_list('name')]
         return context
+
+def home(request):
+    """look up the main search form
+
+        for the moment only hosts are looked up. More to come
+    """
+    host_found = True   # flag if host was found
+    form = SearchForm(request.POST or None)
+    if form.is_valid():
+        name = form.cleaned_data['search_string']
+        try:
+            host = Host.objects.get(name=name)
+        except Host.DoesNotExist:
+            host_found = False
+
+        if host_found:
+            return HttpResponseRedirect(
+                reverse('host-detail', kwargs={'slug': name}))
+
+    hosts = [e[0] for e in Host.objects.all().values_list('name')]
+
+    return render_to_response(
+        'start.html',
+        locals(),
+        context_instance=RequestContext(request),
+        )
+

src/hosts/models.py

 
 """models of myhost app, holds the Django models
 """
+from django.conf import settings
 from django.core.urlresolvers import reverse
 from django.db import models
 from datetime import datetime
 from django.utils.translation import ugettext_lazy as _
 from django.contrib.auth.models import User
+from taggit.managers import TaggableManager
 
-# Create your models here.
+
+class Vendor(models.Model):
+    """Generic Hardware vendor."""
+
+    name = models.CharField(
+        verbose_name=_(u"Name"),
+        max_length=100,
+        )
+
+    logo = models.ImageField(
+        verbose_name=_(u"Logo picture"),
+        upload_to='logos/%Y/%m/',
+        blank=True,
+        null=True,
+        )
+
+    def __unicode__(self):
+        return u"%s" % (self.name)
+
+
+class CPU(models.Model):
+    """CPU model and properties"""
+
+    TYPES = (
+        ('A', 'APU'),
+        ('C', 'CPU'),
+        )
+
+    name = models.CharField(
+        verbose_name=_(u"Name"),
+        max_length=100,
+        )
+
+    vendor = models.ForeignKey(
+        Vendor,
+        verbose_name=_(u"Vendor"),
+        null=True,
+        blank=True,
+        )
+
+    type = models.CharField(
+        max_length=1,
+        choices=TYPES,
+        )
+
+    def __unicode__(self):
+        "no comment"
+        return "{0}".format(self.name,)
+
+
+class RAM(models.Model):
+    """The host.
+    """
+    TYPES = (
+        ('1', 'DDR1'),
+        ('2', 'DDR2'),
+        ('3', 'DDR3'),
+        )
+
+    name = models.CharField(
+        verbose_name=_(u"Module name"),
+        max_length=100,
+        )
+
+    vendor = models.ForeignKey(
+        Vendor,
+        verbose_name=_(u"Vendor"),
+        null=True,
+        )
+
+    size = models.PositiveIntegerField(
+        verbose_name=_(u"size in byte"),
+        null=True,
+        )
+
+    type = models.CharField(
+        verbose_name=_(u"Type"),
+        max_length=3,
+        blank=True,
+        null=True,
+        )
+
+    def size_in_mb(self):
+        return self.size / (2**20)
+
+    def size_in_gb(self):
+        return self.size / (2**30)
+
+
 
 class MyHostUser(models.Model):
     """Details of the user
     ldap = models.CharField(
         verbose_name=_(u"LDAP user name"),
         max_length=25,
+        unique=True,
+    )
+
+    avatar = models.ImageField(
+        verbose_name=_(u"Avatar picture"),
+        upload_to='avatars/%Y/%m/',
+        blank=True,
+        null=True,
     )
 
     date_created = models.DateTimeField(
 
     def save(self, **kwargs):
         if not self.date_created:
-            self.date_created = datetime.now()
-        self.date_last_update = datetime.now()
+            self.date_created = datetime.now(tz=settings.DEFAULT_TIMEZONE)
+        self.date_last_update = datetime.now(tz=settings.DEFAULT_TIMEZONE)
         super(MyHostUser, self).save(**kwargs)
 
 
-class Vendor(models.Model):
-    """Generic Hardware vendor."""
-
-    name = models.CharField(
-        verbose_name=_(u"Hostname"),
-        max_length=100,
-        )
-
-    def __unicode__(self):
-        return u"%s" % (self.name)
-
-
 class Tapper(models.Model):
     """Tapper data."""
 
 class Host(models.Model):
     """The Host itself. Kinda the main model."""
 
+    PURPOSES = (
+        ('D', 'Develop'),
+        ('W', 'Workstation'),
+        ('T', 'Test'),
+        ('I', 'Infrastructure'),
+    )
+
     name = models.CharField(
         verbose_name=_(u"Hostname"),
         max_length=100,
         null=True,
         )
 
+    purpose = models.CharField(
+        verbose_name=_(u"Purpose"),
+        help_text=_(u"main use of this machine"),
+        max_length=2,
+        blank=True,
+        null=True,
+    )
+
     in_tapper = models.BooleanField(
         verbose_name=_("used by Tapper"),
         help_text=_(u"Is the system used by Tapper at the moment?"),
         blank=True,
     )
 
+    cpu_type = models.ForeignKey(
+        CPU,
+        verbose_name=_(u"CPU type"),
+        related_name="cpu_type",
+        help_text=_(u"The build in cpu type. Also see cpu number!"),
+        blank=True,
+        null=True,
+    )
+
+    cpu_number = models.PositiveIntegerField(
+        verbose_name=_(u"CPU number"),
+        help_text=_(u"Number of CPUs"),
+        blank=True,
+        null=True,
+        )
+
+    ram_size = models.PositiveIntegerField(
+        verbose_name=_(u"RAM size"),
+        help_text=_(u"RAM size in bytes."),
+        blank=True,
+        null=True,
+        )
+
+    ram_types = models.ManyToManyField(
+        RAM,
+        verbose_name=_(u"RAM types"),
+        related_name="ram_types",
+        help_text=_(u"Types of RAM modules."),
+        blank=True,
+        null=True,
+        editable=False,
+        )
+
+    harddisk_size = models.PositiveIntegerField(
+        verbose_name=_(u"H/D size"),
+        help_text=_(u"Harddisk size in bytes."),
+        blank=True,
+        null=True,
+        )
+
     location = models.CharField(
-        verbose_name=_(u"Location in rack"),
+        verbose_name=_(u"physical location"),
         max_length=100,
         blank=True,
     )
         blank=True,
         )
 
+    tags = TaggableManager(
+        blank=True,
+    )
+
     couch_id = models.CharField(
         verbose_name=_(u"Couch DB ID"),
         max_length=50,
 
     def save(self, **kwargs):
         if not self.time_added:
-            self.time_added = datetime.now()
-        self.time_change = datetime.now()
+            self.time_added = datetime.now(tz=settings.DEFAULT_TIMEZONE)
+        self.time_change = datetime.now(tz=settings.DEFAULT_TIMEZONE)
         super(Host, self).save(**kwargs)
 
     @models.permalink
         max_length=100,
         )
 
-    vendor = models.ForeignKey(
-        Vendor,
-        verbose_name=_(u"Vendor"),
+    mac = models.CharField(
+        verbose_name=_(u"MAC address"),
+        max_length=12,
+        blank=True,
         null=True,
         )
 
-
-class RAM(models.Model):
-    """The host.
-    """
-    name = models.CharField(
-        verbose_name=_(u"Name"),
-        max_length=100,
-        )
-
     vendor = models.ForeignKey(
         Vendor,
         verbose_name=_(u"Vendor"),
     )
 
 
-class CPU(models.Model):
-    """CPU model and properties"""
-    pass
-
-
-class Vendor(models.Model):
-    """Vendor details """
-    name = models.CharField(
-        verbose_name=_(u"Name"),
-        max_length=100,
-    )
-
-
-class Vendor(models.Model):
-    """Vendor details """
-    name = models.CharField(
-        verbose_name=_(u"Name"),
-        max_length=100,
-    )
-
-
 class BIOS(models.Model):
     """Vendor details """
     vendor = models.CharField(

src/hosts/urls.py

 
 urlpatterns = patterns(
     '',
-    url(r'host/(?P<slug>[-\w]+)/$', HostDetails.as_view(), name='host-detail'),
-    url(r'names/$', get_host_names_as_json, name='host-names-as-json')
+    url(r'name/(?P<slug>[-\w]+)/$', HostDetails.as_view(), name='host-detail'),
+    url(r'names/$', get_host_names_as_json, name='host-names-as-json'),
     )
 

src/hosts/views.py

 
 """views"""
 import json
-from django.http import HttpResponse
+from django.http import HttpResponse, HttpResponseRedirect
+from django.template.context import RequestContext
 from django.utils import timezone
+from django.shortcuts import render_to_response, get_object_or_404
 
 from django.views.generic import DetailView
 from hosts.models import (Host, CPU, MyHostUser, Vendor, RAM, NetworkCard,
 class HostDetails(DetailView):
     """generic view for Host"""
     model = Host
+    context_object_name = 'host'
 
     def get_slug_field(self):
         return 'name'
     #]
 
     return HttpResponse(json.dumps(hosts), mimetype="application/json")
+

src/hwdb_scraper.py

 #from django.db import models
 from datetime import datetime
 #from django.utils.translation import ugettext_lazy as _
-from hosts.models import Host, MyHostUser
+import pytz
+from django.contrib.auth.models import User
+from hosts.models import Host, MyHostUser, Vendor, CPU, RAM
 from BeautifulSoup import BeautifulSoup
 import re
 
 
 class System(object):
 
+    cpus_test = re.compile('\d+x(\s+|\S+)\S')
+    number_match = re.compile('^\d+')
+    unit_match = re.compile('\D+$')
     def __init__(self, system):
         (self.hardwaredb_id,
         self.name,
         self.purpose,
         self.keyword,
         self.owner) = system
+        self.__split_cpus()
+        self.ram = self.__convert_to_bytes(self.ram)
+        self.harddrive = self.__convert_to_bytes(self.harddrive)
+
+    def __split_cpus(self):
+        """
+        split cpus into type and number
+        """
+        if self.cpus_test.match(self.cpus):
+            (number, type) = self.cpus.split('x', 1)
+        else:
+            (number, type) = ('0', 'error in http://hardwaredb')
+        assert isinstance(int(number.strip()), int)
+        self.cpus = (number.strip(), type.strip())
+
+    def __convert_to_bytes(self, value_and_unit):
+        def get_covertion_rate(unit):
+            return {
+                'null': 0,
+                'KB': 2**10,
+                'MB': 2**20,
+                'GB': 2**30,
+                'TB': 2**40,
+            }.get(unit, 'null')
+
+        value = self.number_match.findall(value_and_unit)
+        if value:
+            value = value[0].strip()
+        else:
+            return 0
+
+        unit = self.unit_match.findall(value_and_unit)
+        if unit:
+            unit = unit[0].strip()
+        else:
+            return 0
+
+        return get_covertion_rate(unit.upper()) * int(value)
+
+
+def check_default_values():
+    """
+
+    Args:
+
+
+    Returns:
+
+    """
+    user = User.objects.get(username='admin')
+    if not user.first_name:
+        user.first_name = 'Frank'
+    if not user.last_name:
+        user.last_name = 'Becker'
+    user.save()
+    if not MyHostUser.objects.filter(ldap='fbecker'):
+        user = MyHostUser(user=User.objects.get(username='admin'), ldap='fbecker')
+        user.save()
+
+    if not Vendor.objects.filter(name='AMD'):
+        vendor = Vendor(name='AMD')
+        vendor.save()
+
+    if not Vendor.objects.filter(name='unknown'):
+        vendor = Vendor(name='unknown')
+        vendor.save()
+
+def get_or_create_owner(ldap_name, user='admin'):
+    """
+    create or return owner as given as owner_name.
+    If owner does not exist and user is not given, the Django user 'admin'
+    will be used.
+    """
+
+    try:
+        owner = MyHostUser.objects.get(ldap=ldap_name)
+    except MyHostUser.DoesNotExist:
+        owner = MyHostUser(user=User.objects.get(username='admin'),
+                           ldap=ldap_name)
+        owner.save()
+
+    return owner
+
+def get_or_create_cpu(name, vendor='AMD'):
+    """
+    create or return cpu as by name.
+    If owner does not exist and user is not given, the Django user 'admin'
+    will be used.
+    """
+
+    try:
+        cpu = CPU.objects.get(name=name)
+    except CPU.DoesNotExist:
+        cpu = CPU(name=name)
+        cpu.save()
+
+    return cpu
+
+def get_or_create_ram(size, vendor='unknown'):
+    """
+    return the size of RAM in bytes.
+    Later it will figure out the module type etc. However, that is
+    not registered in the http://hostdatabase.
+    """
+
+    return ram
+
+def update_host_instance(host, system):
+    """
+    Update a given host instance
+    """
+    assert isinstance(host, Host)
+    host.hardware_db_id = system.hardwaredb_id
+    host.location = system.location
+    host.owner = get_or_create_owner('fbecker', user='admin')
+    host.user = get_or_create_owner(system.owner, user='admin')
+    host.cpu_type = get_or_create_cpu(system.cpus[1], vendor='AMD')
+    host.cpu_number = int(system.cpus[0])
+    host.ram_size = system.ram
+    host.harddisk_size = system.harddrive
+    host.purpose = system.purpose
+    host.hardware_db_id=system.hardwaredb_id
+    host.tags.clear()
+    if system.keyword:
+        host.tags.add(system.keyword,)
+
+    return host
+
 
 def update_system(system):
    """update system in myhost db"""
+   admin = User.objects.get(username='admin')
    user = MyHostUser.objects.get(id=1)
    host = Host.objects.get(name=system.name)
 
-   host.hardware_db_id = system.hardwaredb_id
-   host.location = system.location
-   #host.save()
+   host = update_host_instance(host, system)
+   host.save()
 
 def create_system(system):
     """create system in myhost db
     host = Host(
         hardware_db_id=system.hardwaredb_id,
         name=system.name,
-        owner=user,
         user=user,
-        location=system.location,
+        owner=MyHostUser.objects.get(ldap="fbecker"),
     )
     host.save()
+    host = update_host_instance(host, system)
+    host.save()
 
 def get_systems_from_hardwaredb():
     user_agent = 'Mozilla/5 (Linux 3.5) MyHost'
 
 def main():
     """main()"""
+    check_default_values()
     systems_hwdb = get_systems_from_hardwaredb()
     systems_myhost = [e[0] for e in Host.objects.all().values_list('name')]
 
     for system in systems_hwdb:
+        print "Updating: {0}".format(system[1])
         if system[1] in systems_myhost:
             update_system(System(system))
         else:

src/templates/base.html

         <div class="btn-group pull-right">
           <a class="btn dropdown-toggle" data-toggle="dropdown" href="#">
             <i class="icon-user"></i>
-              {% if user.username == "" %}
+              {% if user.is_authenticated %}
                   {{ user.username }}
               {% else %}
                   <span class="alert-error">please log in</span>
         </div>
         <div class="nav-collapse">
           <ul class="nav">
-            <li class="active"><a href="#">Home</a></li>
+            <li class="active"><a href="/">Home</a></li>
             <li><a href="#about">About</a></li>
             <li><a href="#contact">Contact</a></li>
           </ul>

src/templates/css/custom.scss

+body {
+  padding-top: 60px;
+  padding-bottom: 40px;
+}
+.sidebar-nav {
+  padding: 9px 0;
+}
 
 .search-query {
-  width: 70%;
+  width: 93%;
+}
+
+.clear {
+  clear: both;
+}
+
+table.month {
+  border-collapse: separate;
+  border-spacing: 2px;
 }

src/templates/start.html

 {% extends "base.html" %}
 {% load i18n %}
+{% load widget_tweaks %}
 
 
 {% block main_content %}
-    <div class="row-fluid">
         <div class="span3">
             <div class="well sidebar-nav">
                 <ul class="nav nav-list">
         </div><!--/span-->
         <div class="span9">
             <div class="hero-unit">
-                <h1>MyHost - the OSRC host booker</h1>
-                <p>This is a template for a simple marketing or informational website. It includes a large callout called the hero unit and three supporting pieces of content. Use it as a starting point to create something more unique.</p>
-                <form class="well form-search">
-                  <input type="text" id="main-search" class="input-medium search-query" data-provide="typeahead" >
-                  <button type="submit" class="btn btn-primary">Search</button>
+                <h1>MyHost</h1>
+                <h3>
+                     The OSRC host booking system.
+                </h3>
+                <p></p>
+                <form class="well form-search{% if not host_found %} control-group error{% endif %}" action="{% url home %}" method="post">{% csrf_token %}
+                        {{ form.search_string|attr:"type:search"|attr:"autofocus"|add_class:"input-medium search-query"|attr:"data-provide:typeahead" }}
+                  <!-- input type="text" id="main-search" class="input-medium search-query" data-provide="typeahead" -->
+                  <button type="submit" class="btn btn-primary btn-success"><i class="icon-search icon-white"></i></button>
                 </form>
 
+
             </div>
         </div><!--/span-->
-    </div><!--/row-->
 {% endblock %}
 
 {% block js_bottom %}
     <script>
             var hosts = [{% for host in hosts %}'{{ host }}', {% endfor %}];
                 // 'aaa', 'bbb', 'ccc'];
-            $('#main-search').typeahead({
+            $('#id_search_string').typeahead({
                 source: hosts
             })
     </script>