class Task(djongo_models.Model): """Unit of work to be done for the sprint.""" STATUS_TODO = 1 STATUS_IN_PROGRESS = 2 STATUS_TESTING = 3 STATUS_DONE = 4 STATUS_CHOICES = ( (STATUS_TODO, _('Not Started')), (STATUS_IN_PROGRESS, _('In Progress')), (STATUS_TESTING, _('Testing')), (STATUS_DONE, _('Done')), ) name = djongo_models.CharField(max_length=100) description = djongo_models.TextField(blank=True, default='') sprint = djongo_models.ForeignKey(Sprint, blank=True, null=True, on_delete=djongo_models.CASCADE) status = djongo_models.SmallIntegerField(choices=STATUS_CHOICES, default=STATUS_TODO) order = djongo_models.SmallIntegerField(default=0) assigned = djongo_models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True, on_delete=djongo_models.SET_NULL) started = djongo_models.DateField(blank=True, null=True) due = djongo_models.DateField(blank=True, null=True) completed = djongo_models.DateField(blank=True, null=True) def __str__(self): return self.name
class GenericModel(models.Model): big_int = models.BigIntegerField() bool = models.BooleanField() char = models.CharField(max_length=20) comma_int = models.CommaSeparatedIntegerField() date = models.DateField() date_time = models.DateTimeField() decimal = models.DecimalField(max_digits=10, decimal_places=5) email = models.EmailField() float = models.FloatField() integer = models.IntegerField() null_bool = models.NullBooleanField() pos_int = models.PositiveIntegerField() pos_small_int = models.PositiveSmallIntegerField() slug = models.SlugField() small_int = models.SmallIntegerField() text = models.TextField() time = models.TimeField() url = models.URLField() ip = models.GenericIPAddressField() uuid = models.UUIDField() # TODO: add these # basic_file = models.FileField() # image = models.ImageField() objects = models.DjongoManager()
class WeatherData(models.Model): dt = models.IntegerField() temp = models.FloatField() feels_like = models.FloatField() pressure = models.IntegerField() humidity = models.IntegerField() dew_point = models.FloatField() uvi = models.SmallIntegerField() clouds = models.SmallIntegerField() visibility = models.IntegerField() wind_speed = models.FloatField() wind_deg = models.SmallIntegerField() weather = models.ArrayField(model_container=Weather) class Meta: abstract = True
class Game(models.Model): _id = models.ObjectIdField() genre = models.ForeignKey('api.Genre', on_delete=models.CASCADE) round_time = models.SmallIntegerField(default=10, validators=min_max_validator(10, 60), help_text='seconds') rounds = models.SmallIntegerField(default=1, validators=min_max_validator(-1, 5)) num_players = models.PositiveSmallIntegerField( validators=min_max_validator(3, 8)) status = models.CharField(max_length=3, choices=game_status, default='GAP') created_at = models.DateTimeField(default=timezone.now, editable=False) updated_at = AutoDateTimeField(auto_now=True) objects = models.DjongoManager() def __str__(self): return 'Game {0}'.format(self._id)
class Calculate(modelsDjongo.Model): number1 = modelsDjongo.SmallIntegerField() number2 = modelsDjongo.SmallIntegerField() total = modelsDjongo.SmallIntegerField() # class CalculateCreateForm(forms.ModelForm): # number1 = forms.IntegerField() # number2 = forms.IntegerField() # class Meta: # model = Calculate # fields = ('number1', 'number2') # class CalculateResult(forms.ModelForm): # total = forms.IntegerField() # class Meta: # model = Calculate # fields = ('total',)
class NetworkAddressNIC(models.Model): nic = models.ForeignKey(NetworkInterfaceCard, on_delete=models.CASCADE) network_address = models.ForeignKey(NetworkAddress, on_delete=models.CASCADE) # CARP Related stuff carp_priority = models.SmallIntegerField(default=0) carp_passwd = models.TextField(default='-')
class BaseDataset(TimestampedModel): user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=False) name = models.CharField(max_length=100) description = models.TextField(blank=True, default='') total_samples = models.PositiveIntegerField(default=0) total_classes = models.PositiveIntegerField(default=1) status = models.SmallIntegerField(choices=CHOICES_DS_STATUS, default=DEFAULT_DS_STATUS) labels = models.ListField(default=[]) class Meta: abstract = True
class CRUDEvent(PrimaryUUIDTimestampModel): _DATABASE = "mongo" CREATE = 1 UPDATE = 2 DELETE = 3 M2M_CHANGE = 4 M2M_CHANGE_REV = 5 TYPES = ( (CREATE, "Create"), (UPDATE, "Update"), (DELETE, "Delete"), (M2M_CHANGE, "Many-to-Many Change"), (M2M_CHANGE_REV, "Reverse Many-to-Many Change"), ) event_type = models.SmallIntegerField(choices=TYPES) object_id = models.CharField(max_length=255) object_repr = models.TextField(null=True, blank=True) object_json_repr = models.TextField(null=True, blank=True) changed_fields = models.TextField(null=True, blank=True) user = models.ForeignKey( settings.AUTH_USER_MODEL, null=True, blank=True, on_delete=models.SET_NULL, db_constraint=False, ) user_pk_as_string = models.CharField( max_length=255, null=True, blank=True, help_text="String version of the user pk") def is_create(self): return self.CREATE == self.event_type def is_update(self): return self.UPDATE == self.event_type def is_delete(self): return self.DELETE == self.event_type
class LoginEvent(PrimaryUUIDTimestampModel): _DATABASE = "mongo" LOGIN = 0 LOGOUT = 1 FAILED = 2 TYPES = ( (LOGIN, "Login"), (LOGOUT, "Logout"), (FAILED, "Failed login"), ) login_type = models.SmallIntegerField(choices=TYPES) username = models.CharField(max_length=255, null=True, blank=True) user = models.ForeignKey( settings.AUTH_USER_MODEL, null=True, blank=True, on_delete=models.SET_NULL, db_constraint=False, ) remote_ip = models.CharField(max_length=50, null=True, db_index=True) created = models.DateTimeField(auto_now_add=True)
class Student(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE) firstName = models.CharField(default='', max_length=50) lastName = models.CharField(default='', max_length=50) enrollmentNumber = models.CharField(default='', max_length=20) picture = models.ImageField(default='default.png', upload_to='profile_pics', blank=True, null=True) wtMarks = models.SmallIntegerField(default='0') androidMarks = models.SmallIntegerField(default='0') iosMarks = models.SmallIntegerField(default='0') javaMarks = models.SmallIntegerField(default='0') pythonMarks = models.SmallIntegerField(default='0') cpi = models.FloatField(default='0') aptitude = models.SmallIntegerField(default='0') fieldsOfInterest = models.CharField(default='', max_length=200) profileCompleted = models.BooleanField(default=False) def __str__(self): return self.firstName + " " + self.lastName
class ManyToManyRelatedModel(models.Model): _id = models.ObjectIdField() boolean = models.BooleanField(default=True) smol_int = models.SmallIntegerField() objects = models.DjongoManager()
class X509Certificate(models.Model): """ SSL Certificate model representation name: name gave to the certificate cert: Certificate file key: Key file chain : certification chain """ name = models.TextField() """ Serial is ONLY used for internal PKI For external certificate, it is forced to zero """ serial = models.SmallIntegerField(default=1) status = models.TextField(blank=True, default='V') cert = models.TextField(blank=True) key = models.TextField(blank=True) chain = models.TextField(blank=True) csr = models.TextField(blank=True) crl = models.TextField(blank=True) # Is the certificate a Certificate Authority is_ca = models.BooleanField(default=False) # If True: This is the Internal Vulture ROOT CA is_vulture_ca = models.BooleanField(default=False) # This is for external certificate, not managed by us is_external = models.BooleanField(default=False) crl_uri = models.TextField(blank=True, default='') rev_date = models.TextField(blank=True) def __init__(self, *args, **kwargs): super(X509Certificate, self).__init__(*args, **kwargs) def get_base_filename(self): return "{}/{}-{}".format(CERT_PATH, self.name, self.id) def gen_letsencrypt(self, cn, name): """ Create a Let's encrypt certificate and save it into mongoDB. These certificate are automatically renewed: A crontab job maintains the expiration date and the status :param cn: CN attribute of the certificate :param name: Friendly name :return: the bundled certificate, or False in case of a failure """ # Abort if there is an existing certificate with this name (can occur during bootstrap failure) try: pki = X509Certificate.objects.get(is_vulture_ca=False, name=name) return {'cert': pki.cert, 'key': pki.key} except Exception as e: pass # Call let's encrypt to issue a certificate. # This may take some time try: proc = subprocess.Popen([ '/usr/local/sbin/acme.sh', '--issue', '-d', cn, '--webroot', '/var/db/acme/' ], stdout=subprocess.PIPE, stderr=subprocess.PIPE) success, error = proc.communicate() if error: logger.error("X509Certificate::gen_letsencrypt(): {}".format( error.decode('utf-8'))) return False except Exception as e: logger.error("X509Certificate::gen_letsencrypt(): {}".format(e)) return False # Read certificate, private key and chain file with open("/var/db/acme/.acme.sh/{}/{}.cer".format(cn, cn)) as pem_cert: with open("/var/db/acme/.acme.sh/{}/{}.key".format(cn, cn)) as pem_key: with open("/var/db/acme/.acme.sh/{}/fullchain.cer".format( cn)) as pem_chain: try: tmp_crt = X509.load_cert_string(pem_cert) except Exception as e: logger.error( "X509Certificate::gen_letsencrypt(): {}".format(e)) return False # Store the certificate try: self.name = name self.cert = pem_cert.decode('utf-8') self.key = pem_key.decode('utf-8') self.status = 'V' self.is_vulture_ca = False self.is_external = True self.serial = tmp_crt.get_serial_number().decode( 'utf-8') self.chain = pem_chain.decode('utf-8') self.save() except Exception as e: logger.error( "X509Certificate::gen_letsencrypt: {}".format(e)) return False return {'cert': self.cert, 'key': self.key} def gen_cert(self, cn, name): """ Create a Vulture internal certificate and save it into mongoDB. :param cn: CN attribute of the certificate :param name: Friendly name :return: the bundled certificate, or False in case of a failure """ # Abort if there is an existing certificate with this name (can occur during bootstrap failure) try: pki = X509Certificate.objects.get(is_vulture_ca=False, name=name) return {'cert': pki.cert, 'key': pki.key} except X509Certificate.DoesNotExist: pass internal_ca = X509Certificate.objects.get( is_vulture_ca=True, name__startswith="Vulture_PKI") next_serial = internal_ca.get_next_serial attributes = internal_ca.explose_dn() try: crt, pk2 = mk_signed_cert(cn, attributes['C'], attributes['ST'], attributes['L'], attributes['O'], attributes['OU'], next_serial) # Store the certificate self.name = name self.cert = crt.as_pem().decode('utf-8') self.key = pk2.as_pem(cipher=None).decode('utf-8') self.status = 'V' self.is_vulture_ca = False self.is_external = False self.serial = str(next_serial) self.chain = str(internal_ca.cert) self.save() except Exception as e: logger.error("X509Certificate::gen_cert: {}".format(str(e))) return False return {'cert': self.cert, 'key': self.key} @property def get_next_serial(self): """ :return: An integer for the next serial number of self-signed Vulture certificate """ try: x = X509Certificate.objects.filter( serial__gt=1).order_by('-serial')[0] return x.serial + 1 except Exception: return 2 def to_template(self): """ Dictionary used to create configuration file related to the node :return Dictionnary of configuration parameters """ cert = X509.load_cert_string(str(self.cert)) conf = { 'id': str(self.id), 'name': self.name, 'subject': cert.get_subject().as_text(), 'issuer': cert.get_issuer().as_text(), 'status': self.status, 'validfrom': str(cert.get_not_before()), 'validtill': str(cert.get_not_after()), 'is_vulture_ca': self.is_vulture_ca, 'is_ca': self.is_ca, 'is_external': self.is_external, 'crl': self.crl, 'crl_uri': self.crl_uri } return conf def explose_dn(self): """ :return: A dictionary with the explosed subject """ attributes = dict() cert = X509.load_cert_string(self.cert) for attr in cert.get_subject().as_text().split(", "): k, v = attr.split("=") attributes[k] = v return attributes def get_vulture_ca(self): """ :return: The X509Certificate object related to the internal Vulture ROOT CA """ return X509Certificate.objects.get(is_vulture_ca=True) def is_ca_cert(self): """ :return: True if the certificate is a Certificate Authority """ cert = X509.load_cert_string(self.cert) if cert.check_ca() == 1: return True return False def gen_crl(self): """ Build and return the CRL associated to the Vulture's internal ROOT CA """ if self.is_vulture_ca: logger.debug("PKI::gen_crl: Building Vulture's internal CRL") CRL = OpenSSL.crypto.CRL() certs = X509Certificate.objects.filter( status='R').order_by('serial') for cert in certs: try: rev = OpenSSL.crypto.Revoked() rev.set_rev_date(str(cert.rev_date).encode('ascii')) rev.set_serial(str(cert.serial).encode('ascii')) rev.set_reason(None) CRL.add_revoked(rev) except Exception as e: logger.error("PKI::gen_crl: {}".format(str(e))) return False # Now generate the CRL logger.debug("PKI::gen_crl: Storing the CRL into vulture_ca_cert") vulture_ca_cert = self.get_vulture_ca() ca_key = OpenSSL.crypto.load_privatekey( OpenSSL.crypto.FILETYPE_PEM, str(vulture_ca_cert.key)) ca_cert = OpenSSL.crypto.load_certificate( OpenSSL.crypto.FILETYPE_PEM, str(vulture_ca_cert.cert)) ca_crl = CRL.export(ca_cert, ca_key, OpenSSL.crypto.FILETYPE_PEM, 365, b"sha256") vulture_ca_cert.crl = ca_crl vulture_ca_cert.save() return ca_crl elif self.is_external and self.crl_uri: logger.debug("PKI::gen_crl: Fetching external CRL") self.crl = self.download_crl() logger.debug("PKI::gen_crl: Storing the CRL into database") self.save() return self.crl def download_crl(self): if self.is_external and self.crl_uri: try: response = urllib.request.urlopen(self.crl_uri) data = response.read() return data.decode('utf-8') except Exception as e: logger.error("PKI::getCRL: {}".format(str(e))) return None return None def get_crl(self): """ :return: Return the CRL associated to the certificate """ if self.crl: return self.crl else: return None def revoke(self): """ Revoke a certificate :return: True / False """ if self.is_external: logger.error("PKI::revoke: Trying to revoke external certificate") return False elif self.is_vulture_ca: logger.critical("PKI::revoke: Trying to revoke Vulture's CA !") return False else: self.rev_date = "{:%Y%m%d%H%M%SZ}".format(datetime.datetime.now()) self.status = 'R' self.save() self.gen_crl() def as_bundle(self): """ :return: An all-in-one PEM file with private Key + Certificate + Chain """ rsa_key = self.key rsa_key = rsa_key.replace("-----BEGIN PRIVATE KEY-----", "-----BEGIN RSA PRIVATE KEY-----") rsa_key = rsa_key.replace("-----END PRIVATE KEY-----", "-----END RSA PRIVATE KEY-----") buffer = self.cert + "\n" + rsa_key if self.chain: buffer = buffer + "\n" + self.chain return buffer def get_extensions(self): """ Return the list of extensions of this certificate depending on attributes """ extensions = { '.pem': self.as_bundle(), '.crt': self.cert, '.key': self.key } """ If this is a CA, write the cert as .crt """ if self.is_ca_cert(): extensions['.crt'] = self.cert else: extensions['.chain'] = self.chain return extensions def save_conf(self): """ Write cert as all formats currently supported This function raise VultureSystemConfigError if failure """ from system.cluster.models import Cluster extensions = self.get_extensions() # Retrieve and stock variable to improve loop perf base_filename = self.get_base_filename() """ For each extensions to be written """ for extension, buffer in extensions.items(): params = [ base_filename + extension, buffer, CERT_OWNER, CERT_PERMS ] """ API request """ api_res = Cluster.api_request('system.config.models.write_conf', config=params, internal=True) if not api_res.get('status'): raise VultureSystemConfigError( ". API request failure ", traceback=api_res.get('message')) def delete_conf(self): """ Delete all format of the current certificate :return True if success raise VultureSystemConfigError if failure """ from system.cluster.models import Cluster # Firstly try to delete the conf, if it fails the object will not be deleted extensions = self.get_extensions() for extension in extensions.keys(): api_res = Cluster.api_request("system.config.models.delete_conf", self.get_base_filename() + extension) if not api_res.get('status'): raise VultureSystemConfigError( ". API request failure.", traceback=api_res.get('message')) return True def save(self, **kwargs): """ Override of save method to write cert on disk """ """ First of all, save the object to get an id """ self.is_ca = self.is_ca_cert() super().save(**kwargs) """ Only then, write the file(s) on disk """ self.save_conf() @staticmethod def str_attrs(): """ List of attributes required by __str__ method """ return ['name'] def __str__(self): return "{}".format(self.name)
class NetworkAddress(models.Model): """ This is a generic IPv[4|6] Address """ name = models.TextField(default=_('Friendly name')) nic = models.ManyToManyField(NetworkInterfaceCard, through='NetworkAddressNIC') ip = models.GenericIPAddressField() prefix_or_netmask = models.TextField() is_system = models.BooleanField(default=False) carp_vhid = models.SmallIntegerField(default=0) # Needed to make alambiquate mongodb queries objects = models.DjongoManager() def to_dict(self): return { "id": str(self.id), "name": self.name, 'ip': self.ip, 'is_system': self.is_system, 'prefix_or_netmask': self.prefix_or_netmask, 'carp_vhid': self.carp_vhid } def to_template(self): """ Dictionary used to create configuration file related to the interface :return Dictionnary of configuration parameters """ nic_list = list() addresses_nic = NetworkAddressNIC.objects.filter(network_address=self) for address_nic in addresses_nic: nic = address_nic.nic nic_list.append(str(nic)) conf = { 'id': str(self.id), 'name': self.name, 'nic': ', '.join(nic_list), 'ip': self.ip, 'is_system': self.is_system, 'prefix_or_netmask': self.prefix_or_netmask, 'carp_vhid': self.carp_vhid } return conf @property def is_carp(self): if self.carp_vhid > 0: return True return False @property def version(self): """ Return the version of the Ip address :return: 4 or 6 """ if ":" in self.ip: return 6 else: return 4 @property def ip_cidr(self): """ Return IP/CIDR notation of Listener :return: String with ip/cidr notation """ ip = ipaddress.ip_address(self.ip) if ip.version == 6: prefix = self.prefix_or_netmask else: prefix = netmask2prefix(self.prefix_or_netmask) if prefix == 0: prefix = self.prefix_or_netmask.replace("/", "") return "{}/{}".format(self.ip, prefix) @property def family(self): """ :return: inet or inet6, depending of the IP address """ ip = ipaddress.ip_address(self.ip) if ip.version == 4: return "inet" else: return "inet6" def rc_config(self, force_dev=None, is_system=False): """ :param: force_dev: Optional NIC device. DO NOT USE except you known what you are doing :param: is_system: If True, "alias" keyword is not present :return: The rc.conf configuration line for this Network Address """ dev = None first = True addresses = NetworkAddressNIC.objects.filter(network_address=self) for address_nic in addresses: if first and address_nic.nic.node == Cluster.get_current_node(): if force_dev: dev = force_dev else: dev = address_nic.nic.dev first = False carp_priority = address_nic.carp_priority carp_passwd = address_nic.carp_passwd elif (not force_dev) and (address_nic.nic.node == Cluster.get_current_node()): logger.error( "Node::NetworkAddress: Inconsistent configuration: SAME IP on MULTIPLE NIC !!! {}" .format(self.ip)) if self.is_carp: if is_system: device = "{}".format(dev) else: device = "{}_alias".format(dev) device += '{}' inet = "{} {} vhid {} advskew {} pass {}".format( self.family, self.ip_cidr, self.carp_vhid, carp_priority, carp_passwd) else: if is_system: device = "{}".format(dev) else: device = "{}_alias".format(dev) device += '{}' inet = "{} {}".format(self.family, self.ip_cidr) if self.family == 'inet6': device += "_ipv6" return 'ifconfig_{}="{}"'.format(device, inet) def __str__(self): return "'{}' : {}/{}".format(self.name, self.ip, self.prefix_or_netmask) @staticmethod def str_attrs(): """ Attributes required by __str__ method """ return ['name', 'ip', 'prefix_or_netmask']