class ResourceRequests(db.Model): id = db.Column(db.Integer(), primary_key=True) message = db.Column(db.Text, nullable=False) answer = db.Column(db.Text) user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) admin_id = db.Column(db.Integer, db.ForeignKey('user.id')) message_date = db.Column(db.DateTime(timezone=True), server_default=func.now()) answer_date = db.Column(db.DateTime(timezone=True)) admin_rel = db.relationship('User', foreign_keys=[admin_id]) user_rel = db.relationship('User', foreign_keys=[user_id])
class UserPlan(db.Model): id = db.Column(db.Integer, primary_key=True) user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) plan_id = db.Column(db.Integer, db.ForeignKey('plan.id'), nullable=False) server_id = db.Column(db.Integer, db.ForeignKey('server.id')) start_date = db.Column(db.DateTime, default=func.now()) end_date = db.Column(db.DateTime, default=func.now()) plan = db.relationship('Plan', backref=db.backref('user_plan')) user = db.relationship('User', backref=db.backref('user_plan')) server = db.relationship('Server', backref=db.backref('user_plans')) @validates('server') def update_server(self, key, value): """When the user_plans updates, free all resources in the old server.""" if self.server == value: return value plan = Plan.query.filter_by(id=self.plan_id).first() available_server = plan.available_servers(only_one=True, server_id=value.id) if available_server is None: raise ValidationError("Esse servidor não esta disponível.") server, used_gpus, total_ram, total_hd, total_ssd = available_server if self.server_id is not None: self.server.cores_available += plan.cpu.cores self.server.ram_available += total_ram self.server.hd_available += total_hd self.server.ssd_available += total_ssd free_gpus = {} for server_gpu in self.server.server_gpus: # percorre todas as GPUs do plano for plan_gpu in plan.plan_gpus: # verifica se a GPU ja foi liberada antes, se não coloca o valor da utiliazaão dela pra zero if server_gpu.gpu_model not in free_gpus: free_gpus[server_gpu.gpu_model] = 0 # testa se a freq é a mesma e a capacidade é maior ou igual, # levando em consideração se a gpu já foi liberada antes if server_gpu.gpu.frequency == plan_gpu.gpu.frequency and \ server_gpu.total_capacity - free_gpus[server_gpu.gpu_model] >= \ plan_gpu.quantity * plan_gpu.gpu.ram: # incrementa a utilização da gpu do servidor server_gpu.available_capacity += plan_gpu.quantity * plan_gpu.gpu.ram free_gpus[ server_gpu. gpu_model] += plan_gpu.quantity * plan_gpu.gpu.ram return value
class Purchase(db.Model): id = db.Column(db.Integer, primary_key=True) user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) credit_card_id = db.Column(db.Integer, db.ForeignKey('credit_card.id'), nullable=False) plan_id = db.Column(db.Integer, db.ForeignKey('plan.id'), nullable=False) user_plan_id = db.Column(db.Integer, db.ForeignKey('user_plan.id')) date = db.Column(db.DateTime, server_default=func.now()) user = db.relationship('User', backref=db.backref('purchase')) credit_card = db.relationship('CreditCard', backref=db.backref('purchase')) plan = db.relationship( 'Plan', backref=db.backref('purchase'), ) user_plan = db.relationship('UserPlan', backref=db.backref('purchases'), foreign_keys=[user_plan_id])
class UserPlanStats(db.Model): user_plan_id = db.Column(db.Integer, db.ForeignKey('user_plan.id'), nullable=False, primary_key=True) date = db.Column(db.DateTime, primary_key=True, default=func.now()) cpu_usage = db.Column(db.Float) disk_usage = db.Column(db.Float) user_plan = db.relationship('UserPlan', backref=db.backref('user_plan_stats'))
class ServerGpu(db.Model, ServerResource): backref_plan = 'server_gpus' gpu_model = db.Column(db.Text, db.ForeignKey('gpu.model'), primary_key=True) total_capacity = db.Column(db.Integer, default=0) available_capacity = db.Column(db.Integer, default=0) gpu = db.relationship('Gpu', backref=db.backref(backref_plan)) def __str__(self): return '%s x%s(%s/%s)' % (self.gpu.model, self.quantity, self.available_capacity, self.total_capacity) @validates('gpu') def update_gpu(self, key, value): if self.gpu is None or self.gpu == value: return value raise ValidationError("Não é possível alterar o modelo da GPU. " "Delete esse componente e crie outro.") @validates('quantity') def update_quantity(self, key, value): """ When quantity is updated, updates the total_capacity, available_capacity, gpu.available and server.gpu_slot_available. """ if value < 0: raise ValidationError('A quantidade precisa ser maior que zero.') elif self.quantity is None: return value elif self.gpu.available < value - self.quantity: raise ValidationError( "Não existem recursos disponíveis. Tente diminuir a quantidade ou adicionar novos recursos." ) elif self.server.gpu_slot_available < value - self.quantity: raise ValidationError( "Não existem slots disponíveis. Tente diminuir a quantidade de recursos." ) net_capacity = self.gpu.ram * (value - self.quantity) if self.available_capacity + net_capacity < 0: raise ValidationError( "O uso do recurso está maior do que o disponível. Tente diminuir a utilização dos recursos" " ou aumente a quantidade de recursos a serem adicionados.") else: self.total_capacity += net_capacity self.available_capacity += net_capacity self.gpu.available -= value - self.quantity self.server.gpu_slot_available -= value - self.quantity return value
class CreditCard(db.Model): id = db.Column(db.Integer, primary_key=True) number = db.Column(db.BigInteger, nullable=False) user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) name = db.Column(db.Text, nullable=False) exp_date = db.Column(db.DateTime, nullable=False) cvv = db.Column(db.Integer, nullable=False) users = db.relationship('User', backref=db.backref('credit_cards')) def __str__(self): number_str = repr(self.number) return '****' + number_str[len(number_str) - 4:]
class ServerHd(db.Model, ServerResource): backref_plan = 'server_hds' hd_model = db.Column(db.Text, db.ForeignKey('hd.model'), primary_key=True) hd = db.relationship('Hd', backref=db.backref(backref_plan)) def __str__(self): return self.hd.model + ' x ' + str(self.quantity) @validates('hd') def update_hd(self, key, value): if self.hd is None or self.hd == value: return value raise ValidationError("Não é possível alterar o modelo do HD. " "Delete esse componente e crie outro.") @validates('quantity') def update_quantity(self, key, value): """ When quantity is updated, updates the server.hd_total, server.hd_available, server.ssd_total, server.ssd_available, hd.available and server.hd_slot_available. """ if value < 0: raise ValidationError('A quantidade precisa ser maior que zero.') elif self.quantity is None: return value elif self.hd.available < value - self.quantity: raise ValidationError( "Não existem recursos disponíveis. Tente diminuir a quantidade ou adicionar novos recursos." ) elif self.server.hd_slot_available < value - self.quantity: raise ValidationError( "Não existem slots disponíveis. Tente diminuir a quantidade de recursos." ) net_capacity = self.hd.capacity * value - self.hd.capacity * self.quantity if (self.hd.is_ssd is True and self.server.ssd_available + net_capacity < 0) or \ (self.hd.is_ssd is False and self.server.hd_available + net_capacity < 0): raise ValidationError( "O uso do recurso está maior do que o disponível. Tente diminuir a utilização dos recursos" " ou aumente a quantidade de recursos a serem adicionados.") else: if self.hd.is_ssd is True: self.server.ssd_total += net_capacity self.server.ssd_available += net_capacity else: self.server.hd_total += net_capacity self.server.hd_available += net_capacity self.hd.available -= value - self.quantity self.server.hd_slot_available -= value - self.quantity return value
class ServerRam(db.Model, ServerResource): backref_plan = 'server_rams' ram_model = db.Column(db.Text, db.ForeignKey('ram.model'), primary_key=True) ram = db.relationship('Ram', backref=db.backref(backref_plan)) def __str__(self): return self.ram.model + ' x ' + str(self.quantity) @validates('ram') def update_ram(self, key, value): if self.ram is None or self.ram == value: return value raise ValidationError("Não é possível alterar o modelo da RAM. " "Delete esse componente e crie outro.") @validates('quantity') def update_quantity(self, key, value): """When quantity is updated, updates the server.ram_total, server.ram_available, ram.available and server.ram_slot_available. """ if value < 0: raise ValidationError('A quantidade precisa ser maior que zero.') elif self.quantity is None: return value elif self.ram.available < value - self.quantity: raise ValidationError( "Não existem recursos disponíveis. Tente diminuir a quantidade ou adicionar novos recursos." ) elif self.server.ram_slot_available < value - self.quantity: raise ValidationError( "Não existem slots disponíveis. Tente diminuir a quantidade de recursos." ) net_capacity = self.ram.capacity * value - self.ram.capacity * self.quantity if self.server.ram_available + net_capacity < 0: raise ValidationError( "O uso do recurso está maior do que o disponível. " "Tente diminuir a utilização dos recursos ou aumente " "a quantidade de recursos a serem adicionados.") elif self.server.ram_max < self.server.ram_total + net_capacity: raise ValidationError("RAM máxima do servidor atingida.") else: self.server.ram_total += net_capacity self.server.ram_available += net_capacity self.server.ram_slot_available -= value - self.quantity self.ram.available -= value - self.quantity return value
class PlanHd(db.Model, PlanResource): backref_plan = 'plan_hds' hd_model = db.Column(db.Text, db.ForeignKey('hd.model'), primary_key=True) hd = db.relationship('Hd', backref=db.backref('plan_hd')) def __str__(self): return self.hd.model + ' x ' + str(self.quantity) @validates('hd') def update_hd(self, key, value): if self.hd is None or self.hd == value: return value raise ValidationError("Não é possível alterar o modelo do HD. " "Delete esse componente e crie outro.")
class PlanRam(db.Model, PlanResource): backref_plan = 'plan_rams' ram_model = db.Column(db.Text, db.ForeignKey('ram.model'), primary_key=True) ram = db.relationship('Ram', backref=db.backref('plan_ram')) def __str__(self): return self.ram.model + ' x ' + str(self.quantity) @validates('ram') def update_ram(self, key, value): if self.ram is None or self.ram == value: return value raise ValidationError("Não é possível alterar o modelo da RAM. " "Delete esse componente e crie outro.")
class PlanGpu(db.Model, PlanResource): backref_plan = 'plan_gpus' gpu_model = db.Column(db.Text, db.ForeignKey('gpu.model'), primary_key=True) gpu = db.relationship('Gpu', backref=db.backref('plan_gpu')) def __str__(self): return self.gpu.model + ' x ' + str(self.quantity) @validates('gpu') def update_gpu(self, key, value): if self.gpu is None or self.gpu == value: return value raise ValidationError("Não é possível alterar o modelo da GPU. " "Delete esse componente e crie outro.")
class Plan(db.Model): id = db.Column(db.Integer, primary_key=True) title = db.Column(db.Text, unique=True, default='Customizado') price = db.Column(db.Float(), default=0, nullable=False) duration_months = db.Column(db.Integer, nullable=False) cpu_model = db.Column(db.Text, db.ForeignKey('cpu.model'), nullable=False) os_name = db.Column(db.Text, db.ForeignKey('os.name'), nullable=False) shop_description = db.Column(db.Text) slug_url = db.Column(db.Text, unique=True) thumbnail = db.Column(db.Text, default='http://placehold.it/700x400') hero_image = db.Column(db.Text, default='http://placehold.it/900x400') is_public = db.Column(db.Boolean, default='false') auto_price = db.Column(db.Boolean, default=True) os = db.relationship('Os', backref=db.backref('plans')) cpu = db.relationship('Cpu', backref=db.backref('plans')) gpu = db.relationship('Gpu', secondary='plan_gpu') ram = db.relationship('Ram', secondary='plan_ram') hd = db.relationship('Hd', secondary='plan_hd') @validates('title') def update_slug(self, key, value): """Creates the slug url, used on the item detail page.""" self.slug_url = slugify(value) return value def __str__(self): return self.title @validates('auto_price') def auto_price_update(self, key, value): if value is True: self.price = -1 return value @validates('price') def price_update(self, key, value): if self.auto_price is True: if self.cpu_model is not None: return self.calculate_price() return value @validates('cpu') def cpu_update(self, key, value): if self.auto_price is True: self.price = -1 return value def calculate_price(self): price = Cpu.query.filter_by( model=self.cpu_model).first().price * self.duration_months for plan_hd in PlanHd.query.filter_by(plan_id=self.id): price += plan_hd.quantity * plan_hd.hd.price * self.duration_months for plan_ram in PlanRam.query.filter_by(plan_id=self.id): price += plan_ram.quantity * plan_ram.ram.price * self.duration_months for plan_gpu in PlanGpu.query.filter_by(plan_id=self.id): price += plan_gpu.quantity * plan_gpu.gpu.price * self.duration_months return price def get_total_ram(self): total_ram = 0 for ram in self.plan_rams: total_ram += ram.quantity * ram.ram.capacity return total_ram def get_total_hd_ssd(self): total_hd = 0 total_ssd = 0 for hd in self.plan_hds: if hd.hd.is_ssd is True: total_ssd += hd.quantity * hd.hd.capacity else: total_hd += hd.quantity * hd.hd.capacity return total_hd, total_ssd def available_servers(self, only_one=False, server_id=None): """ :param only_one: when True finds only one server. :param server_id: search only the specified server :return: when only_one is True returns the server found and the used resources(used_gpus, total_ram, total_hd, total_ssd) when only_one is False returns a list of available servers when there is no server available, returns None. """ total_ram = self.get_total_ram() total_hd, total_ssd = self.get_total_hd_ssd() if server_id is None: servers = Server.query.filter( Server.cores_available >= self.cpu.cores, Server.ram_available >= total_ram, Server.hd_available >= total_hd, Server.ssd_available >= total_ssd, Server.os_name == self.os_name) else: servers = Server.query.filter( Server.cores_available >= self.cpu.cores, Server.ram_available >= total_ram, Server.hd_available >= total_hd, Server.ssd_available >= total_ssd, Server.os_name == self.os_name, Server.id == server_id) available_servers = [] # percorre todos os servidores for server in servers: plan_gpus = list(self.plan_gpus) used_gpus = {} # percorre todas as GPUs do servidor for server_gpu in server.server_gpus: # percorre todas as GPUs do plano for plan_gpu in self.plan_gpus: # verifica se a GPU ja foi usada antes, se não coloca o valor da utiliazaão dela pra zero if server_gpu.gpu_model not in used_gpus: used_gpus[server_gpu.gpu_model] = 0 # testa se a freq é a mesma e a capacidade é maior ou igual, # levando em consideração se a gpu já foi usada antes if server_gpu.gpu.frequency == plan_gpu.gpu.frequency and \ server_gpu.available_capacity >= plan_gpu.quantity * plan_gpu.gpu.ram + used_gpus[ server_gpu.gpu_model]: # remove a gpu da lista para nao passar na proxima gpu do servidor plan_gpus.remove(plan_gpu) # incrementa a utilização da gpu do servidor used_gpus[ server_gpu. gpu_model] += plan_gpu.quantity * plan_gpu.gpu.ram if len(plan_gpus) == 0 and only_one is True: return server, used_gpus, total_ram, total_hd, total_ssd elif len(plan_gpus) == 0: available_servers.append(server) if len(available_servers) == 0: return None return available_servers
def server_id(self): return db.Column(db.Integer, db.ForeignKey('server.id'), primary_key=True)
class Server(db.Model): id = db.Column(db.Integer, primary_key=True) cpu_model = db.Column(db.Text, db.ForeignKey('cpu.model'), nullable=False) cores_available = db.Column(db.Integer, default=0) os_name = db.Column(db.Text, db.ForeignKey('os.name')) ram_slot_total = db.Column(db.Integer, nullable=False) ram_slot_available = db.Column(db.Integer) ram_max = db.Column(db.Integer, nullable=False) ram_total = db.Column(db.Integer, default=0) ram_available = db.Column(db.Integer, default=0) gpu_slot_total = db.Column(db.Integer, nullable=False) gpu_slot_available = db.Column(db.Integer) gpu_total = db.Column(db.Integer, default=0) gpu_available = db.Column(db.Integer, default=0) hd_slot_total = db.Column(db.Integer, nullable=False) hd_slot_available = db.Column(db.Integer) hd_total = db.Column(db.Integer, default=0) hd_available = db.Column(db.Integer, default=0) ssd_total = db.Column(db.Integer, default=0) ssd_available = db.Column(db.Integer, default=0) os = db.relationship('Os', backref=db.backref('server')) cpu = db.relationship('Cpu', backref=db.backref('server')) gpus = db.relationship('Gpu', secondary='server_gpu') rams = db.relationship('Ram', secondary='server_ram') hds = db.relationship('Hd', secondary='server_hd') @validates('cpu_model') def cpu_model_update(self, key, value): """Update the cores_available when the cpu_model updates.""" new_cpu = Cpu.query.filter_by(model=value).first() if self.cpu_model is None: cores_available = new_cpu.cores elif self.cpu.available < 1: raise ValidationError("Não existe CPU disponível.") else: cores_available = new_cpu.cores + self.cores_available - self.cpu.cores if cores_available < 0: if key != -1: raise ValidationError( "O uso de cores está maior do que o disponível. " "Tente diminuir a utilização de cores ou aumente " "os cores do cpu a ser adicionado.") else: self.cores_available = cores_available new_cpu.available -= 1 return value @validates('ram_slot_total', 'gpu_slot_total', 'hd_slot_total') def update_ram_slot_total(self, key, value): available = key[:-5] + 'available' available_value = self.__getattribute__(available) old_value = self.__getattribute__(key) if available_value is None: self.__setattr__(available, value) elif available_value + value - old_value < 0: raise ValidationError( "Falha ao remover os slots. Tente remover os componentes antes." ) else: self.__setattr__(available, available_value + value - old_value) return value @validates('user_plans') def user_plans_update(self, key, value): """When a user_plan is updated(server_id is changed), set all plan resources in use.""" usage = value.plan.available_servers(only_one=True, server_id=self.id) if usage is None: raise ValidationError( "Esse servidor não é compativel com esse plano.") server, used_gpus, total_ram, total_hd, total_ssd = usage self.cores_available -= value.plan.cpu.cores self.ram_available -= total_ram self.hd_available -= total_hd self.ssd_available -= total_ssd for gpu in self.server_gpus: if gpu.gpu_model in used_gpus and used_gpus[gpu.gpu_model] > 0: gpu.available_capacity -= used_gpus[gpu.gpu_model] return value
def plan_id(self): return db.Column(db.Integer, db.ForeignKey('plan.id'), primary_key=True)
import datetime from slugify import slugify from wtforms import ValidationError from flask_security import RoleMixin, UserMixin from sqlalchemy import func, event from sqlalchemy.ext.declarative import declared_attr from sqlalchemy.orm import validates, Session from cloud_computing.model.database import db from cloud_computing.utils.form_utils import add_months # Create a table to support many-to-many relationship between Users and Roles roles_users = db.Table( 'roles_users', db.Column('user_id', db.Integer(), db.ForeignKey('user.id')), db.Column('role_id', db.Integer(), db.ForeignKey('role.id'))) class Role(db.Model, RoleMixin): id = db.Column(db.Integer(), primary_key=True) name = db.Column(db.String(80), unique=True) description = db.Column(db.String(255)) # Human-readable values for the Role when editing a User def __str__(self): return self.name # Required to avoid the exception TypeError: unhashable type: # 'Role' when saving a User def __hash__(self):