def insertInstanceOnServer(instance_name, flavor_name, image_name, server_name): alcServer = Hardware.objects(phySerName=server_name).first() selFlavor = Flavor.objects(flavorName=flavor_name).first() reqRam = selFlavor.ram reqDisks = selFlavor.numDisks reqvcpus = selFlavor.vcpus newInstance = Instance.objects(instanceName=instance_name).first() rckname = alcServer.rackAssigned.rackName if newInstance: newInstance.phySerName = alcServer.phySerName newInstance.imageName = image_name newInstance.flavorName = flavor_name newInstance.rackAssigned = rckname newInstance.save() print(f"instance '{instance_name}' updated") else: newInstance = Instance(instanceName=instance_name) newInstance.phySerName = alcServer.phySerName newInstance.imageName = image_name newInstance.flavorName = flavor_name newInstance.rackAssigned = rckname newInstance.save() print(f"instance '{instance_name}' created") alcServer.avMem = alcServer.avMem - reqRam alcServer.avNumDisks = alcServer.avNumDisks - reqDisks alcServer.avNumCores = alcServer.avNumCores - reqvcpus alcServer.instances = [newInstance] alcServer.save() print( f"hardware '{server_name}' on rack: '{alcServer.rackAssigned.rackName}' updated" )
def create_server_instance(instance_name, flavor, image): """Creates an instance named INSTANCE_NAME to be boot from IMAGE and configured as indicated in FLAVOR_NAME """ logger.info(f"Got request to create a server with configuration:") logger.info(f"Instance name: {instance_name}") logger.info(f"Flavor name: {flavor}") logger.info(f"Image name: {image}") alcServer = getPhyServerAllocation(instance_name, image, flavor) if alcServer: selFlavor = Flavor.objects(flavorName=flavor).first() selImage = Image.objects(imageName=image).first() reqRam = selFlavor.ram reqDisks = selFlavor.numDisks reqvcpus = selFlavor.vcpus newInstance = Instance.objects(instanceName=instance_name).first() rckname = alcServer.rackAssigned.rackName if newInstance: newInstance.phySerName = alcServer.phySerName newInstance.imageName = image newInstance.flavorName = flavor newInstance.rackAssigned = rckname newInstance.save() logger.info(f"instance {instance_name} updated") else: newInstance = Instance(instanceName=instance_name) newInstance.phySerName = alcServer.phySerName newInstance.imageName = image newInstance.flavorName = flavor newInstance.rackAssigned = rckname newInstance.save() logger.info(f"instance {instance_name} created") alcServer.avMem = alcServer.avMem - reqRam alcServer.avNumDisks = alcServer.avNumDisks - reqDisks alcServer.avNumCores = alcServer.avNumCores - reqvcpus alcServer.save() alcServer.update(push__instances=newInstance) if selImage not in alcServer.rackAssigned.imgCache: alcServer.rackAssigned.update(push__imgCache=selImage) alcServer.rackAssigned.update(dec__avStorage=selImage.imageSize) print( f"Added to server {alcServer.phySerName} (on rack {alcServer.rackAssigned.rackName}) current memmory {alcServer.mem} availble memory {alcServer.avMem})" ) logger.info( f"Added to server {alcServer.phySerName} (on rack {alcServer.rackAssigned.rackName}) current memmory {alcServer.mem} availble memory {alcServer.avMem})" ) logger.info( f"SUCCESS: COMMAND: aggiestack server create --image {image} --flavor {flavor} {instance_name}" ) else: logger.info( f"FAILED: COMMAND: aggiestack server create --image {image} --flavor {flavor} {instance_name}" )
def getPhyServerAllocation(instancename, image, flavor): mimage = Image.objects(imageName=image).first() mflavor = Flavor.objects(flavorName=flavor).first() if (mimage and mflavor): reqDisks = mflavor.numDisks reqRam = mflavor.ram reqvcpus = mflavor.vcpus # reqImagesize = mimage.imageSize # update later based on prof input avServers = Hardware.objects( avMem__gte=reqRam, avNumDisks__gte=reqDisks, avNumCores__gte=reqvcpus, ) if avServers.count() == 0: logger.error( f"Insufficient storage on servers to host instance {instancename} with image {image} and flavor {flavor}" ) for hrd in avServers: if (mimage in hrd.rackAssigned.imgCache): return hrd max_size = 0 hw_with_max_size = None for hrd in avServers: if hrd.rackAssigned.avStorage >= max_size: max_size = hrd.rackAssigned.avStorage hw_with_max_size = hrd #logger.info(f"max_size: {max_size}, hw_with_max_size: {hw_with_max_size.rackAssigned.avStorage}") if hw_with_max_size: if max_size < mimage.imageSize: imagelist = hw_with_max_size.rackAssigned.imgCache logger.info( f"evicting images from rack {hw_with_max_size.rackAssigned.rackName}" ) #evict logger.info("evicting images: [ ") for image in imagelist: logger.info(image.imageName, end=" ") max_size += image.imageSize hw_with_max_size.rackAssigned.avStorage += image.imageSize hw_with_max_size.rackAssigned.imgCache.remove(image) if max_size >= mimage.imageSize: break logger.info("]") hw_with_max_size.rackAssigned.save() return hw_with_max_size #return avServers elif not mimage and not mflavor: logger.error(f"image {image} and flavor {flavor} doesn't exist") elif not mimage: logger.error(f"image {image} doesn't exist") else: logger.error(f"flavor {flavor} doesn't exist")
def show_flavors(context): flvList = Flavor.objects({}) if flvList.first(): for flv in flvList: print( f"Flavor Name: {flv.flavorName} Memory size:{flv.ram} No of disks: {flv.numDisks} No of cores : {flv.vcpus}" ) logger.info( "COMMAND: aggiestack show flavors - SUCCESS - printed configuration on console" ) else: print("no flavors found") logger.info( "COMMAND: aggiestack show flavors - No Stored Flavor Configurations Found" )
def cli(context, machine_name, flavor): """Check if a machine can be hosted with a particular flavour'. Pass the machine name and flavour to check against as argument.""" if (not context.admin_rights): my_logger.error('Can allow this operation only in admin mode') my_logger.info( f'FAILED: COMMAND: aggiestack can_host {machine_name} {flavor}') return flavor_rep = Flavor.objects(flavorName=flavor).first() if flavor_rep is None: my_logger.error( f'Flavor with name {flavor} not found in configuration') my_logger.info( f'FAILED: COMMAND: aggiestack admin can_host {machine_name} {flavor}' ) return total_hardware_available = Hardware.objects({}) if total_hardware_available is None: my_logger.error('Hardware not configured') my_logger.info( f'FAILED: COMMAND: aggiestack admin can_host {machine_name} {flavor}' ) return reqDisks = flavor_rep.numDisks reqRam = flavor_rep.ram reqvcpus = flavor_rep.vcpus hardware_available = Hardware.objects(avMem__gt=reqRam, avNumDisks__gt=reqDisks, avNumCores__gt=reqvcpus).first() if (hardware_available): print( f'Yes, you can host {machine_name} machine with the {flavor} flavor' ) my_logger.info("SUCCESS: COMMAND : aggiestack admin can_host %s %s", machine_name, flavor) return else: my_logger.error(f'Not enough server capacity to host {flavor}') my_logger.info( f'FAILED: COMMAND: aggiestack admin can_host {machine_name} {flavor}' ) return
def getPhyServerAllocation(image, flavor, rack_name=None): mimage = Image.objects(imageName=image).first() mflavor = Flavor.objects(flavorName=flavor).first() if (mimage and mflavor): reqDisks = mflavor.numDisks reqRam = mflavor.ram reqvcpus = mflavor.vcpus # reqImagesize = mimage.imageSize # update later based on prof input if not rack_name: avServers = Hardware.objects(avMem__gte=reqRam, avNumDisks__gte=reqDisks, avNumCores__gte=reqvcpus).first() else: avServers = Hardware.objects(avMem__gte=reqRam, avNumDisks__gte=reqDisks, avNumCores__gte=reqvcpus, rackAssigned__ne=rack_name).first() return avServers else: print("flavor or image doesnt exist")
def delete_server_instance(instance_name): logger.info(f"got request to delete instance {instance_name}") delInstance = Instance.objects(instanceName=instance_name).first() alcServer = Hardware.objects(phySerName=delInstance.phySerName).first() alcFlav = Flavor.objects(flavorName=delInstance.flavorName).first() if delInstance: logger.info("deleted instance {instance_name}") alcServer.avMem += alcFlav.ram alcServer.avNumDisks += alcFlav.numDisks alcServer.avNumCores += alcFlav.vcpus alcServer.save() alcServer.update(pull__instances=delInstance) delInstance.delete() logger.info(f" hardware server :{alcServer.phySerName} updated") logger.info( f"SUCCESS: COMMAND: aggiestack server delete {instance_name}") else: logger.error( "Instance doesn't exist. Enter a valid instance name to delete. Execute \"aggiestack server list\" for the list of instances " ) logger.info( f"FAILED: COMMAND: aggiestack server delete {instance_name}")
def cli(context, rack_name): """ Evacuates all the machines located on the same rack """ if (not context.admin_rights): logger.error('Can allow this operation only in admin mode') logger.info(f'FAILED: COMMAND: aggiestack evacuate {rack_name}') return logger.info(f"Got request to evacuate rack: {rack_name}") rack = Rack.objects(rackName=rack_name).first() if not rack: logger.error(f"Rack {rack_name} doesn't exist") logger.info(f'FAILED: COMMAND: aggiestack evacuate {rack_name}') return rack_servers = Hardware.objects(rackAssigned=rack_name) logger.info(f"rack servers: '{rack_servers.count()}'") new_server_names = [] old_server_names = [] migrated_instance_names = [] roll_back = False for server in rack_servers: if roll_back: break for instance in server.instances: logger.info( f"migrating instance '{instance.instanceName}' image: '{instance.imageName}' flavor: {instance.flavorName}" ) new_server = utility.getPhyServerAllocation( instance.imageName, instance.flavorName, rack_name) if not new_server: logger.error( f"cannot migrate instance: '{instance.instanceName}' image:'{instance.imageName}'" ) roll_back = True break else: utility.insertInstanceOnServer(instance.instanceName, instance.flavorName, instance.imageName, new_server.phySerName) migrated_instance_names.append(instance.instanceName) old_server_names.append(server.phySerName) new_server_names.append(new_server.phySerName) if roll_back: logger.error(f'Cannot evacuate rack {rack_name}') logger.error("rolling back servers") for i in range(len(migrated_instance_names) - 1, -1, -1): logger.info( f"rolling back server: '{new_server_names[i]}' for instance: '{migrated_instance_names[i]}' to its previous server: '{old_server_names[i]}'" ) # rolling back instance migrated_instance = Instance.objects( instanceName=migrated_instance_names[i]).first() migrated_instance.phySerName = old_server_names[i] migrated_instance.save() flavor = Flavor.objects( flavorName=migrated_instance.flavorName).first() image = Image.objects( imageName=migrated_instance.imageName).first() # rolling back the server to which instance it was assigned new_server = Hardware.objects( phySerName=new_server_names[i]).first() new_server.avMem += flavor.ram new_server.avNumDisks += flavor.numDisks new_server.avNumCores += flavor.vcpus new_server.instances.remove(migrated_instance) new_server.save() logger.info(f'FAILED: COMMAND: aggiestack admin evacuate {rack_name}') else: logger.info(f"migrated #'{len(migrated_instance_names)}' instances") for server in rack_servers: server.delete() logger.info(f"removed all servers from rack {rack_name}") rack = Rack.objects(rackName=rack_name).first() rack.delete() logger.info(f"evicted rack {rack_name}") logger.info(f'SUCCESS: COMMAND: aggiestack admin evacuate {rack_name}') logger.info(f'Successfully evacuated rack {rack_name}')
def cli(context, hardware, images, flavors): if hardware: check = check_hardware_pattern(open(hardware, 'r')) if check: logger.error("COMMAND: aggiestack config --hardware '%s' : %s", hardware, check) logger.info( f"FAILED: COMMAND: aggiestack config --hardware {hardware}") return else: input_content = utility.file_read(hardware) arg_hardware = hardware # reading rack information # handle update or duplicates! for i in range(1, int(input_content[0]) + 1): attrs = input_content[i].split(" ") logger.info("Racks parsed -- '%s'", attrs) rack = Rack.objects(rackName=attrs[0]).first() if not rack: rack = Rack(rackName=attrs[0], storageCapacity=attrs[1], avStorage=attrs[1]).save() logger.info("Inserted Rack: '%s'", attrs) else: rack.avStorage += int(attrs[1]) - rack.storageCapacity rack.storageCapacity = attrs[1] rack.save() logger.info("Updated Rack: '%s'", attrs) # reading hardware information # fails when no hardware is present after rack info for line in input_content[int(input_content[0]) + 2:]: attrs = line.split(" ") logger.info("Hardware parsed -- '%s'", attrs) rack = Rack.objects(rackName=attrs[1]).first() if rack: hardware = Hardware.objects(phySerName=attrs[0]).first() if not hardware: hardware = Hardware( phySerName=attrs[0], rackAssigned=Rack.objects.get(rackName=attrs[1]), ipAddress=attrs[2], mem=attrs[3], numDisks=attrs[4], numCores=attrs[5], avMem=attrs[3], avNumDisks=attrs[4], avNumCores=attrs[5]) hardware.save() logger.info("Inserted Hardware: '%s'", attrs) else: hardware.phySerName = attrs[0] hardware.rackAssigned = Rack.objects.get( rackName=attrs[1]) hardware.avMem += int(attrs[3]) - hardware.mem hardware.avNumDisks += int( attrs[4]) - hardware.numDisks hardware.avNumCores += int( attrs[5]) - hardware.numCores hardware.mem = attrs[3] hardware.numDisks = attrs[4] hardware.numCores = attrs[5] hardware.save() logger.info("Updated Hardware: '%s'", attrs) logger.info("SUCCESS: COMMAND: aggiestack config --hardware %s", arg_hardware) elif images: # todo modify check function # check = check_image_pattern(open(images, 'r')) # remove this and below line after modifying check check = None if check: logger.error("COMMAND: aggiestack config --images '%s' : %s", images, check) logger.info( f"FAILED: COMMAND: aggiestack config --images {image}") else: input_content = utility.file_read(images) arg_image = images # write to mongo # handle update for line in input_content[1:]: attrs = line.split(" ") logger.info("Images parsed -- '%s'", attrs) image = Image.objects(imageName=attrs[0]).first() # confirm with dileep if not image: image = Image(imageName=attrs[0], imageSize=attrs[1], imageLocation=attrs[2]).save() logger.info("Inserted Image: '%s'", attrs) else: image.imageSize = attrs[1] image.imageLocation = attrs[2] image.save() logger.info("Updated Image: '%s'", attrs) logger.info("SUCCESS: COMMAND: aggiestack config --images %s", arg_image) elif flavors: check = check_flavor_pattern(open(flavors, 'r')) if check: logger.error("COMMAND: aggiestack config --flavor '%s' : %s", flavors, check) logger.error( f"FAILED: COMMAND: aggiestack config --flavor {flavor}") else: input_content = utility.file_read(flavors) arg_flavor = flavors # write to mongo # handle update, dont duplicate record for line in input_content[1:]: attrs = line.split(" ") logger.info("Flavor parsed -- '%s'", attrs) flavor = Flavor.objects(flavorName=attrs[0]).first() if not flavor: flavor = Flavor(flavorName=attrs[0], ram=attrs[1], numDisks=attrs[2], vcpus=attrs[3]).save() logger.info("Inserted Flavor: '%s'", attrs) else: flavor.ram = attrs[1] flavor.numDisks = attrs[2] flavor.vcpus = attrs[3] flavor.save() logger.info("Updated Flavor: '%s'", attrs) logger.info("SUCCESS: COMMAND: aggiestack config --flavors %s", arg_flavor) else: my_logger.error( 'You must enter an argument with the config command. Check with --help for available options' )