class LoginForm(forms.Form):
  username = forms.EmailField(max_length=200, required=True)
  password = forms.CharField(max_length=200, widget=forms.PasswordInput(), required=True) class AddUserForm(forms.Form):
  email = forms.EmailField(max_length=200, required=True)
  email_check = forms.EmailField(max_length=200, required=True, label="Verify Email") class UserInitForm(forms.Form):
  keep_password = forms.BooleanField(required=False, label="Keep randomly generated password") class UserNameForm(forms.Form):
  first_name = forms.CharField(max_length=200, required=True)
  last_name = forms.CharField(max_length=200, required=True) class UserPasswordForm(forms.Form):
  password = forms.CharField(max_length=200, widget=forms.PasswordInput(), required=True)
  password_check = forms.CharField(max_length=200, widget=forms.PasswordInput(), required=True) class UserLogin(models.Model):
  user = models.ForeignKey(User)
  time = models.DateTimeField(auto_now_add=True)
  address = models.GenericIPAddressField()
  browser = models.ForeignKey(UserBrowser)

  def __unicode__(self):
    return "Login: %s @ %s [%s][%s]" % (self.user, self.time, self.address, \
      self.browser)

  def __str__(self):
    return unicode(self).encode('utf-8') class InvalidLogin(models.Model):
  user = models.CharField(max_length=200)
  time = models.DateTimeField(auto_now_add=True)
  browser = models.ForeignKey(UserBrowser)
  address = models.GenericIPAddressField()

  def __unicode__(self):
    return "Invalid Login: %s @ %s [%s][%s]" % (self.user, self.time, self.address, \
      self.browser)

  def __str__(self):
    return unicode(self).encode('utf-8') class UserBrowser(models.Model):
  name = models.CharField(max_length=255, unique=True)

  def __unicode__(self):
    return self.name

  def __str__(self):
    return unicode(self).encode('utf-8') class UserProfile(models.Model):
  user = models.ForeignKey(User, unique=True)
  init = models.BooleanField(default=False)
 
  def __unicode__(self):
    return "%s's Profile" % (self.user.username)
 
  def __str__(self):
    return unicode(self).encode('utf-8')

  def audit(self):
    return UserAudit.objects.get(user=self.user)

  def instance_count(self):
    return Instance.objects.filter(user=self.user).count()

  def vnc_session_count(self):
    return Session.objects.filter(user=self.user, active=True).count() class Hypervisor(models.Model):
  name = models.CharField(max_length=100)
  location = models.CharField(max_length=100)
  address = models.CharField(max_length=255)
  libvirt_port = models.IntegerField(default=16509)
  node_port = models.IntegerField(default=5000)
  timeout = models.IntegerField(max_length=2, default=10)
  # status choices
  ONLINE = 'UP'
  TIMEOUT = 'TO'
  OFFLINE = 'DN'
  INIT = 'IN'
  STATUS_CHOICES = (
    (ONLINE, 'Online'),
    (TIMEOUT, 'Timeout'),
    (OFFLINE, 'Offline'),
    (INIT, 'Initalize'),
  )
  status = models.CharField(max_length=2, choices=STATUS_CHOICES, 
    default=INIT)
  # install medium path
  install_medium_path = models.CharField(max_length=255)
  # limits
  maximum_memory = models.ForeignKey(Size, related_name="hypervisor_max_memory")
  maximum_vcpus = models.IntegerField()
  maximum_hdd = models.ForeignKey(Size, related_name="hypervisor_max_hdd")

  def __str__(self):
    return unicode(self).encode('utf-8')

  def __unicode__(self):
    return '%s [%s][%s]' % (self.name, self.location, self.get_status_display())

  def get_status_html(self):
    if self.status == 'UP':
      return '<span class="label label-success">%s</span>' % (self.get_status_display())
    return '<span class="label label-warning">%s</span>' % (self.get_status_display())

  def get_libvirt_address(self):
    return "qemu+tcp://%s:%d/system" % (self.address, self.libvirt_port)

  def get_node_address(self):
    return "http://%s:%d" % (self.address, self.node_port)

  def get_libvirt_status_html(self):
    conn = self.get_connection()
    if conn:
      return '<span class="label label-success">Responding</span>'
    return '<span class="label label-error">Not Responding</span>'

  def get_node_status_html(self):
    if send_command(self, 'check', {}):
      return '<span class="label label-success">Responding</span>'
    return '<span class="label label-error">Not Responding</span>'

  def get_connection(self, update=False):
    conn = None
    if self.status != 'UP' and update or self.status == 'UP':
      try:
        conn = libvirt.open(self.get_libvirt_address())
        if not conn:
          if self.status == 'UP': self.status = 'TO'
        else: self.status = 'UP'
        self.save()
      except libvirt.libvirtError as e:
        self.status = 'DN'
        self.save()
    return conn 

  def start(self):
    self.status = self.ONLINE
    self.save()

  def stop(self):
    self.status = self.OFFLINE
    self.save() class StoragePool(models.Model):
  name = models.CharField(max_length=100)
  hypervisor = models.ForeignKey(Hypervisor)
  path = models.CharField(max_length=255)
  # status choices
  INACTIVE = 0
  BUILDING = 1
  RUNNING = 2
  DEGRADED = 3
  INACCESSIBLE = 4
  LAST = 5
  NONE = 6
  STATUS_CHOICES = (
    (INACTIVE, 'Inactive'),
    (BUILDING, 'Buidling'),
    (RUNNING, 'Running'),
    (DEGRADED, 'Degraded'),
    (INACCESSIBLE, 'Inaccessible'),
    (LAST, 'Last'),
    (NONE, 'None'),
  )
  status = models.IntegerField(max_length=1, choices=STATUS_CHOICES, default=NONE)
  # more details
  capacity = models.BigIntegerField(default=0)
  allocated = models.BigIntegerField(default=0)
  percent = models.IntegerField(default=0)
  available = models.BigIntegerField(default=0)
  percent = models.DecimalField(max_digits=5, decimal_places=2, default=0.0)
  # updated
  updated = models.DateTimeField(auto_now=True)
  
  class Meta:
    unique_together = ('name', 'hypervisor')

  def __str__(self):
    return unicode(self).encode('utf-8')
  
  def __unicode__(self):
    return "%s [%s][%s]" % (self.name, self.hypervisor, self.get_status_display())

  def get_status_html(self):
    if self.status == 2:
      return '<span class="label label-success">%s</span>' % (self.get_status_display())
    return '<span class="label label-warning">%s</span>' % (self.get_status_display())

  def get_storagepool(self):
    storagepool = None
    try:
      if self.hypervisor.status == 'UP':
        conn = self.hypervisor.get_connection()
        if conn: storagepool = conn.storagePoolLookupByName(self.name)
          
    except libvirt.libvirtError:
      pass
    return storagepool

  def delete(self, request=None):
    storagepool = self.get_storagepool()
    if storagepool:
      if storagepool.info()[0] == 2:
        # delete any associated volumes
        for vol in storagepool.listVolumes():
          try:
            vol = storagepool.storageVolLookupByName(vol)
            vol.delete(0)
          except libvirt.libvirtError as e:
            if request:
              messages.add_message(request, persistent_messages.ERROR, 'Unable to delete Storage Pool Volume: %s' % (e))
            # try and continue
        # set pool to inactive
        try:
          storagepool.destroy()
        except libvirt.libvirtError as e:
          if request:
            messages.add_message(request, persistent_messages.ERROR, 
              'Unable to destroy Storage Pool: %s' % (e))
            return
      # delete and undefine the pool
      try:
        storagepool.delete(0)
        storagepool.undefine()
      except libvirt.libvirtError as e:
        if request:
          messages.add_message(request, persistent_messages.ERROR, 'Unable to delete Storage Pool: %s' % (e))
        return
      if request:
        messages.add_message(request, persistent_messages.SUCCESS,
          'Deleted Storage Pool: %s [%s][%s]' % (self.name, self.path, self.hypervisor))
      # delete the model
      super(StoragePool, self).delete()
    elif request:
      messages.add_message(request, persistent_messages.ERROR, 'Unable to delete Storage Pool: Unable to get Storage Pool %s' % (self))
    

  def update(self, force=False):
    # check if we have checked in the last minute
    if not force and (timezone.now() - self.updated) < timedelta(minutes=1): return
    storagepool = self.get_storagepool()
    if storagepool:
      
      (status, capacity, allocated, available) = storagepool.info()
      self.status = status
      self.capacity = capacity
      self.allocated = allocated
      self.available = available
      self.percent = ((float(allocated)/float(capacity))*100)
      self.save() class Volume(models.Model):
  name = models.CharField(max_length=100, unique=True)
  device_name = models.CharField(max_length=20, null=True, blank=True)
  storagepool = models.ForeignKey(StoragePool)
  capacity = models.ForeignKey(Size)
  allocated = models.BigIntegerField(default=0)
  # updated
  updated = models.DateTimeField(auto_now=True)

  def path(self):
    return "%s.qcow2" % (os.path.join(self.storagepool.path, self.name))

  def __str__(self):
    return unicode(self).encode('utf-8')

  def __unicode__(self):
    return '%s on %s' % (self.name, self.storagepool)
  
  def get_volume(self):
    pool = self.storagepool.get_storagepool()
    if pool:
      try:
        vol = pool.storageVolLookupByName('%s.qcow2' % (self.name))
        return vol
      except libvirt.libvirtError as e:
        pass
      
    return None

  def delete(self, request=None):
    vol = self.get_volume()
    if vol:
      try:
        vol.delete(0)
        if request:
          persistent_messages.add_message(request, persistent_messages.SUCCESS, 'Deleted %s Volume' % (self))
        super(Volume, self).delete()
        return True
      except libvirt.libvirtError as e:
        if request:
          persistent_messages.add_message(request, persistent_messages.ERROR, 'Unable to delete %s Volume: %s' % (self, e))

    elif request:
      persistent_messages.add_message(request, persistent_messages.ERROR, 'Unable to delete Volume: Unable to get Volume %s' % (self))
    return False 

  def update(self):
    if (timezone.now() - self.updated) < timedelta(minutes=1): return
    volume = self.get_volume()
    if volume:
      (vol_type, capacity, allocated) = volume.info()
      self.allocated = allocated
      self.save()

  def create(self, request=None):
    pool = self.storagepool.get_storagepool()
    if pool:
      xml = VOLUME_TEMPLATE % (self.name, self.capacity.size)
      try:
        pool.createXML(xml, 0)
        return True
      except libvirt.libvirtError as e:
        if request:
          persistent_messages.add_message(request, persistent_messages.ERROR, 'Unable to create Volume %s: %s' % (self.name, e))
        return False

    else:
      persistent_messages.add_message(request, persistent_messages.ERROR, 'Unable to create Volume %s (Unable to connect to Storage Pool)' % (self.name))
      return False

  def clone(self):
    pool = self.storagepool.get_storagepool()
    if pool:
      try:
        new_name = self.create_random_name()
        xml = VOLUME_TEMPLATE % (new_name, self.capacity.size)
        base_vol = pool.storageVolLookupByName('%s.qcow2' % (self.name))
        pool.createXMLFrom(xml, base_vol, 0)
        volume = Volume(
          name=new_name,
          storagepool=self.storagepool,
          capacity=self.capacity
        )
        volume.save()
        return volume
      except libvirt.libvirtError as e:
        print e
    return None

  """
    Used to create a random name.
  """
  @staticmethod
  def create_random_name():
    while True:
      name = hexlify(os.urandom(16))
      try:
        volume = Volume.objects.get(name=name)
      except Volume.DoesNotExist:
        return name class Network(models.Model):
  hypervisor = models.ForeignKey(Hypervisor)
  device = models.CharField(max_length=20, default='br0')
  netmask = models.GenericIPAddressField()
  gateway = models.GenericIPAddressField()
  broadcast = models.GenericIPAddressField()
  network = models.GenericIPAddressField()
  start = models.GenericIPAddressField()
  end = models.GenericIPAddressField()

  def __unicode__(self):
    return "%s %s - %s :: %s / %s / %s / %s" % (self.hypervisor, self.start, self.end, self.gateway,\
      self.broadcast, self.network, self.netmask)

  def __str__(self):
    return unicode(self).encode('utf-8')

  """
    Warning, does not save address
  """
  def create_address_from_ip(self, ip):
    ranges = self.get_all_addresses()
    for i in ranges:
      if i == ip:
        if InstanceNetwork.objects.filter(ip=ip).count() == 0:
          return InstanceNetwork(ip=ip, network=self)

    return None
  """
    Warning, does not save address
  """
  def create_unique_address(self):
    ranges = self.get_all_addresses()

    addresses = InstanceNetwork.objects.all()
    
    ip = None
    for i in ranges:
      used = False
      for j in addresses:
        if i == j.ip:
          used = True
          break
      if not used:
        ip = i
        break
    if not ip: raise NoUniqueAddress()

    address = InstanceNetwork(ip=ip, network=self)
    return address

  def get_all_addresses(self):
    start = list(map(int, self.start.split(".")))
    end = list(map(int, self.end.split(".")))
    temp = start
    ranges = []
    ranges.append('%s' % (self.start))
    while temp != end:
      start[3] += 1
      for i in (3, 2, 1):
        if temp[i] == 256:
          temp[i] = 0
          temp[i-1] += 1
      ranges.append(".".join(map(str, temp)))
    return ranges

  def get_available_addresses(self):
    ranges = self.get_all_addresses()
    addresses = InstanceNetwork.objects.all()
    available = []
    for i in ranges:
      used = False
      for j in addresses:
        if i == j.ip:
          used = True
          break
      if not used:
        available.append(i)

    return available
    

  def get_number_of_instances(self):
    return InstanceNetwork.objects.filter(network=self).count() class InstallationDisk(models.Model):
  name = models.CharField(max_length=100)
  hypervisor = models.ForeignKey(Hypervisor)
  url = models.URLField()
  filename = models.CharField(max_length=100)
  total_bytes = models.IntegerField()
  user = models.ForeignKey(User)

  class Meta:
    unique_together = ('filename', 'hypervisor',)

  def path(self):
    return "%s" % (os.path.join(self.hypervisor.install_medium_path, self.filename))

  def __str__(self):
    return unicode(self).encode('utf-8')

  def __unicode__(self):
    return self.name

  """
    Cleanup disk on node.
  """
  def delete(self, request=None):
    task_id = node.send_command(self.hypervisor, 'installationdisk_delete', {
      'path': os.path.join(self.hypervisor.install_medium_path, self.filename)})
    now = time.time()
    while True:
      time.sleep(2.5)
      status = node.check_command(self.hypervisor, task_id)
      print status
      if status['state'] == 'SUCCESS':
        if request:
          messages.add_message(request, persistent_messages.SUCCESS, 'Deleted Installation Disk %s on %s' % (self.name, self.hypervisor))
        super(InstallationDisk, self).delete()
        break
      elif status['state'] == 'FAILED' or status['state'] == 'ERROR':
        if request:
          msg = "N/A"
          if 'args' in status:
            msg = status['args']['msg']
          messages.add_message(request, persistent_messages.ERROR, 'Unable to delete Installation Disk %s on %s: %s' % (self.name, self.hypervisor, msg))
        break class InstallationDiskTask(models.Model):
  name = models.CharField(max_length=100)
  hypervisor = models.ForeignKey(Hypervisor)
  url = models.URLField()
  filename = models.CharField(max_length=100)
  task_id = models.CharField(max_length=100, default='dummy')
  total_bytes_dl = models.IntegerField(default=0)
  total_bytes = models.IntegerField(default=0)
  percent = models.DecimalField(max_digits=5, decimal_places=2, default=0.0)
  state = models.CharField(max_length=50)
  user = models.ForeignKey(User)
  

  def __str__(self):
    return unicode(self).encode('utf-8')

  def __unicode__(self):
    return "Downloading: %s [%s]" % (self.name, self.hypervisor)

  def start(self):
    self.total_bytes_dl = 0
    self.total_bytes = 0
    self.percent = 0
    self.task_id = node.send_command(self.hypervisor, 'installationdisk_download', 
    {
      'url': self.url, 
      'path': self.hypervisor.install_medium_path
    })
    if self.task_id: self.save()

  def abort(self):
    ret = node.abort_command(self.hypervisor, self.task_id)
    if 'state' in ret:
      self.state = ret['state']
      self.save()

  def get_status(self):
    status = node.check_command(self.hypervisor, self.task_id)
    print status
    if 'args' in status:
      args = status['args']
      if args:
        if 'total_bytes_dl' in args:
          self.total_bytes_dl = args['total_bytes_dl']
        if 'total_bytes' in args:
          self.total_bytes = args['total_bytes']
        if 'percent' in args:
          self.percent = args['percent']

    self.state = status['state']
    self.save() class Instance(models.Model):
  name = models.CharField(max_length=100)
  alias = models.CharField(max_length=100, default="My Instance", null=True, blank=True)
  volume = models.OneToOneField(Volume)
  user = models.ForeignKey(User, related_name="instance_user")
  creator = models.ForeignKey(User)
  # virtual attributes
  vcpu = models.IntegerField(max_length=2, default=1)
  memory = models.ForeignKey(Size, related_name="instance_memory")
  disk = models.ForeignKey(InstallationDisk, null=True, blank=True)
  # time fields
  updated = models.DateTimeField(auto_now=True)
  created = models.DateTimeField(auto_now_add=True)
  initialised = models.BooleanField(default=False)
  # status
  NOSTATE = 0
  RUNNING = 1
  BLOCKED = 2
  PAUSED = 3
  SHUTTINGDOWN = 4
  SHUTDOWN = 5
  CRASHED = 6
  SUSPENDED = 7
  LAST = 8
  NONE = 9
  STATUS_CHOICES = (
    (NOSTATE, 'No State - Hypervisor may be down'),
    (RUNNING, 'Running'),
    (BLOCKED, 'Blocked'),
    (PAUSED, 'Paused'),
    (SHUTTINGDOWN, 'Shutting Down'),
    (SHUTDOWN, 'Shutdown'),
    (CRASHED, 'Crashed'),
    (SUSPENDED, 'Suspended'),
    (LAST, 'Last'),
    (NONE, 'None'),
  )
  status = models.IntegerField(max_length=1, choices=STATUS_CHOICES, default=NONE)
  base = models.BooleanField(default=False, editable=False)

  def __str__(self):
    return unicode(self).encode('utf-8')

  def __unicode__(self):
    return "%s / %d VCPUs / %s RAM / %s HDD / %s" % (self.alias, self.vcpu, self.memory.name, self.volume.capacity.name, self.name)

  def get_xml(self):
    dom = self.get_instance()
    if dom: 
      try:
        return dom.XMLDesc(0)
      except libvirt.libvirtError as e:
        return e
    return  "Error"

  def get_vnc_port(self):
    instance = self.get_instance()
    if not instance: return 0
    tree = ElementTree.fromstring(instance.XMLDesc(0))
    graphics = tree.findall('devices/graphics')
    return int(graphics[0].get('port'))

  def get_status_html(self):
    if self.status == 1:
      return '<span class="label label-success">%s</span>' % (self.get_status_display())
    return '<span class="label label-warning">%s</span>' % (self.get_status_display())

  def get_instance(self):
    hypervisor = self.volume.storagepool.hypervisor.get_connection()
    instance = None
    if hypervisor:
      try:
        instance = hypervisor.lookupByName(self.name)
      except libvirt.libvirtError:
        pass
    if not instance:
      self.status = self.NOSTATE
      self.save()
    return instance

  def update(self, force=False):
    if not force and (timezone.now() - self.updated) < timedelta(seconds=15): return
    instance = self.get_instance()
    if instance:
      (status, na, memory, vcpu, na) = instance.info()
      self.status = status
      self.save()

  def delete(self, request=None):
    instance = self.get_instance()
    if instance:
      try:
        try:
          # shutdown/destroy the vm if it's still up and running. 
          instance.destroy()
        except libvirt.libvirtError as e:
          if str(e) != 'Requested operation is not valid: domain is not running': raise e
        instance.undefine()
        self.volume.delete(request)
        if request:
          persistent_messages.add_message(request, persistent_messages.SUCCESS, 'Deleted Instance %s' % (self))
          if request.user != self.user:
            persistent_messages.add_message(request, persistent_messages.SUCCESS, 'Deleted Instance %s' % (self), user=self.user)
        super(Instance, self).delete()
      except libvirt.libvirtError as e:
        print e
        print type(e)
        if request:
          persistent_messages.add_message(request, persistent_messages.ERROR, 'Unable to delete Instance %s: %s' % (self, e))
          if request.user != self.user:
            persistent_messages.add_message(request, persistent_messages.ERROR, 'Unable to delete Instance %s' % (self), user=self.user)
  
    elif request:
      persistent_messages.add_message(request, persistent_messages.ERROR, 'Unable to get instance object inorder to delete Instance %s' % (self))
      if request.user != self.user:
        persistent_messages.add_message(request, persistent_messages.ERROR, 'Unable to delete Instance %s' % (self), user=self.user)

  def detach_disk(self, request=None):
    dom = self.get_instance()
    if dom:
      try:
        dom.updateDeviceFlags(DETACH_DISK_TEMPLATE, 0)
        self.disk = None
        self.save()
        if request:
          messages.add_message(request, persistent_messages.SUCCESS, 'Unmounted disk on %s' % (self.name))
      except libvirt.libvirtError as e:
        if request and request.user.is_staff:
          messages.add_message(request, persistent_messages.ERROR, 'Unable to unmount disk on %s, unable to get dom: %s' % (self.name, e))
        elif request:
          messages.add_message(request, persistent_messages.ERROR, 'Unable to unmount diskon %s' % (self.name))

    elif request and request.user.is_staff:
      messages.add_message(request, persistent_messages.ERROR, 'Unable to unmount disk on %s, unable to get dom' % (self.name))
    elif request:
      messages.add_message(request, persistent_messages.ERROR, 'Unable to unmount disk on %s' % (self.name))

  def attach_network(self, address, request=None, first=False):
    dom = self.get_instance()
    if dom:
      template = ATTACH_NETWORK_TEMPLATE.format(
        ip=address.ip,
        device=address.network.device,
        alias=address.ip
      )
      try:
        dom.attachDeviceFlags(template, 0)
        tree = ElementTree.fromstring(dom.XMLDesc(0))
        for i in tree.findall('devices/interface'):
          for p in i.findall('filterref/parameter'):
            if p.get('value') == address.ip:
              mac = i.find('mac').get('address').upper()
              address.mac = mac
              address.save()
        resp = node.send_command(address.network.hypervisor, "network_track_ip", {'ip': address.ip})
        if resp:
          print resp
      except libvirt.libvirtError as e:
        print e

  def detach_network(self, address, request=None):
    dom = self.get_instance()
    if dom:
      template = DETACH_NETWORK_TEMPLATE.format(alias=address.ip, device=address.network.device, mac=address.mac)
      try:
        dom.detachDeviceFlags(template, 0)
        address.delete()
        resp = node.send_command(address.network.hypervisor, "network_remove_ip", {'ip': address.ip})
        if resp:
          print resp
      except libvirt.libvirtError as e:
        print e 

  def attach_disk(self, disk, request=None):
    if disk == None:
      self.detach_disk(request)
      return
    dom = self.get_instance()
    if dom:
      template = ATTACH_DISK_TEMPLATE.format(path=disk.path())
      print template
      try:
        dom.updateDeviceFlags(template, 0)
        self.disk = disk
        self.save()
        messages.add_message(request, persistent_messages.SUCCESS, 'Mounted Disk %s on %s' % (disk, self.name))
      except libvirt.libvirtError as e:
        if request and request.user.is_staff:
          messages.add_message(request, persistent_messages.ERROR, 'Unable to mount %s on %s, unable to get dom: %s' % (disk, self.name, e))
        elif request:
          messages.add_message(request, persistent_messages.ERROR, 'Unable to mount %s on %s' % (disk, self.name))

    elif request and request.user.is_staff:
      messages.add_message(request, persistent_messages.ERROR, 'Unable to mount %s on %s, unable to get dom' % (disk, self.name))
    elif request:
      messages.add_message(request, persistent_messages.ERROR, 'Unable to mount %s on %s' % (disk, self.name))

  def create_random_vnc_password(self, request=None):
    instance = self.get_instance()
    if instance == None:
      if request:
        messages.add_message(request, persistent_messages.ERRPR, 'Unable to get instance in order to create a random VNC password')
      return

    xml = ElementTree.fromstring(instance.XMLDesc(0))
    graphic_element = xml.find('.//graphics')
    passwd = ''.join(choice(string.letters + string.digits) for _ in xrange(8)) 
    graphic_element.attrib['passwd'] = passwd
    try:
      instance.updateDeviceFlags(ElementTree.tostring(graphic_element), 0)
    except libvirt.libvirtError as e:
      if request and request.user.is_staff:
        messages.add_message(request, persistent_messages.ERROR, 'Unable to create random VNC password on %s, error: %s' % (self.name, e))
      elif request:
        messages.add_message(request, persistent_messages.ERROR, 'Unable to create random VNC password on %s' % (self.name))
      return ""
    return passwd
    
  def get_vnc_password(self, request=None):
    return self.create_random_vnc_password(request) class InstanceTask(models.Model):
  name = models.CharField(max_length=100)
  user = models.ForeignKey(User, related_name="instancetask_user")
  storagepool = models.ForeignKey(StoragePool)
  creator = models.ForeignKey(User)
  vcpu = models.IntegerField(max_length=2, default=1)
  memory = models.ForeignKey(Size, related_name="instancetask_memory")
  capacity = models.ForeignKey(Size, related_name="instancetask_capacity")
  disk = models.ForeignKey(InstallationDisk, null=True, blank=True)
  volume = models.OneToOneField(Volume, null=True, blank=True)
  network = models.ForeignKey('network.Network')
  # time fields
  updated = models.DateTimeField(auto_now=True)
  created = models.DateTimeField(auto_now_add=True)
  # task attributes
  task_id = models.CharField(max_length=100, default='dummy')
  percent = models.DecimalField(max_digits=5, decimal_places=2, default=0.0)
  message = models.CharField(max_length=255, default='N/A')
  state = models.CharField(max_length=50, default='STARTING')

  def __str__(self):
    return unicode(self).encode('utf-8')

  def __unicode__(self):
    return "Creating: %s [%d CPU/%s RAM/%s HDD][%s]" % \
      (self.user, self.vcpu, (self.memory.name), (self.capacity.name), self.state)

  def abort(self, request=None):
    pass

  def delete(self, purge=True):
    if self.volume and purge:
      if self.volume.delete():
        super(InstanceTask, self).delete()
    else:
      super(InstanceTask, self).delete()

  def update(self):
    task = AsyncResult(self.task_id)
    status = task.result
    if not status: return
    self.state = task.state
    if 'custom_state' in status:
      self.state = status['custom_state']
    if 'msg' in status:
      self.message = status['msg']
    if 'percent' in status:
      self.percent = int(status['percent'])
    self.save()

  """
    Used to create a random name.
  """
  @staticmethod
  def get_random_name():
    while True:
      name = hexlify(os.urandom(16))
      try:
        volume = InstanceTask.objects.get(name=name)
      except InstanceTask.DoesNotExist:
        try:
          volume = Instance.objects.get(name=name)
        except Instance.DoesNotExist:
          return name class Session(models.Model):
  user = models.ForeignKey(User)
  instance = models.ForeignKey(Instance)
  started = models.DateTimeField(auto_now_add=True)
  updated = models.DateTimeField(auto_now=True)
  port = models.IntegerField()
  active = models.BooleanField(default=True)

  def __str__(self):
    return unicode(self).encode('utf-8')

  def __unicode__(self):
    return "%s (%s) %s (%s)" % (self.user, self.instance, self.started, self.active)

  """
    Get a random port, should be able to change the range somewhere
  """
  @staticmethod
  def get_random_port():
    while True:
      port = random.randrange(10000,20000)
      try:
        session = Session.objects.get(port=port, active=True)
      except Session.DoesNotExist:
        return port class VNCSessions(Thread):
  __metaclass__ = SingletonType
  
  def __init__(self):
    Thread.__init__(self)
    self.setDaemon(True)
    self.sessions = {}

  def count(self):
    return len(self.sessions)
  
  def get(self, key):
    if key in self.sessions:
      return self.sessions[key]
    return None

  def set(self, key, proxy):
    self.sessions[key] = proxy

  def heartbeat(self, key):
    proxy = self.get(key)
    if proxy:
      proxy.heartbeat()

  def stop(self, key):
    proxy = self.get(key)
    if proxy:
      proxy.stop()
      del self.sessions[key]
      del proxy
from django.template import RequestContext, loader
from django.shortcuts import redirect, render_to_response, render
from django.contrib.auth.decorators import login_required
from django.contrib.auth import authenticate, login, logout
from django.contrib.admin.views.decorators import staff_member_required
from django.core.mail import send_mail
from django.contrib import messages
from django.db.models import Q
from django.forms.util import ErrorList
from django.template.loader import get_template
from django.template import Context
from django.conf import settings
from emailusernames.utils import get_user
from django.contrib.auth.models import User
from apps.account.forms import LoginForm, AddUserForm, UserInitForm, UserNameForm, UserPasswordForm
from apps.account.models import UserLogin, InvalidLogin, UserBrowser, UserProfile
from apps.hypervisor.models import Hypervisor
from apps.storagepool.models import StoragePool
from apps.volume.models import Volume
from apps.network.models import Network
from apps.installationdisk.models import InstallationDisk, InstallationDiskTask
from apps.instance.models import Instance, InstanceTask
from apps.vnc.models import Session
from utils.vnc import VNCSessions
import persistent_messages

def get_client_ip (request):
    x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
    if x_forwarded_for:
        ip = x_forwarded_for.split(',')[0]
    else:
        ip = request.META.get('REMOTE_ADDR')
    return ip

def initalize(request):
  name_form = UserNameForm()
  user_init_form = UserInitForm()
  password_form = UserPasswordForm()

  success = False

  if request.method == 'POST':
    name_form = UserNameForm(request.POST)
    user_init_form = UserInitForm(request.POST)
    if name_form.is_valid():
      # update user details
      request.user.first_name = name_form.cleaned_data['first_name']
      request.user.last_name = name_form.cleaned_data['last_name']
      request.user.save()
      if user_init_form.is_valid():
        if not user_init_form.cleaned_data['keep_password']:
          password_form = UserPasswordForm(request.POST)
          if password_form.is_valid():
            password = password_form.cleaned_data['password']
            if password != password_form.cleaned_data['password_check']:
              error = ErrorList([u'Password\'s do not match!'])
              password_form._errors.setdefault('password', error)
              password_form._errors.setdefault('password_check', error)
            else:
              request.user.set_password(password)
              request.user.save()
              success = True
        else: success = True

  if success:
    request.user.get_profile().init = True
    request.user.get_profile().save()
    return redirect('/')

  return render_to_response('account/initalize.html', {
    'name_form': name_form,
    'user_init_form': user_init_form,
    'password_form': password_form,
  },
  context_instance=RequestContext(request))

@login_required
def index(request):

  if not request.user.get_profile().init:
    # initalize user
    return initalize(request)

  unread_messages = persistent_messages.models.Message.objects.filter(user=request.user,
    read=False).order_by('-pk')
  read_messages = persistent_messages.models.Message.objects.filter(user=request.user,
    read=True).order_by('-pk')

  my_instances_online = Instance.objects.filter(status=1, user=request.user)
  my_instances_offline = Instance.objects.filter(~Q(status=1), user=request.user)
  for i in my_instances_online:
    network = i.instancenetwork_set.all()[0]
    (rx, tx) = network.get_rx_tx()
    i.rx = rx
    i.tx = tx

  response = {
      'unread_messages': unread_messages,
      'read_messages': read_messages,
      'my_instances_online': my_instances_online,
      'my_instances_offline': my_instances_offline
  }

  if request.user.is_staff:
    hypervisors_online = Hypervisor.objects.filter(status='UP').count()
    hypervisors_offline = Hypervisor.objects.filter(~Q(status='UP')).count()
    storagepools_online = StoragePool.objects.filter(status=2).count()
    storagepools_offline = StoragePool.objects.filter(~Q(status=2)).count()
    volumes_online = Volume.objects.filter(storagepool__status=2).count()
    volumes_offline = Volume.objects.filter(~Q(storagepool__status=2)).count()
    instances_online = Instance.objects.filter(status=1).count()
    instances_offline = Instance.objects.filter(~Q(status=1)).count()

    instancetasks = InstanceTask.objects.all().count()