Example #1
0
def show_hardware(context):
    hrdlist = Hardware.objects({})
    if hrdlist.first():
        for hrd in hrdlist:
            if context.admin_rights:
                print(
                    f"Harware Server Name: {hrd.phySerName} Rack assigned: {hrd.rackAssigned.rackName} Available Memory size:{hrd.avMem} Available no of disks: {hrd.avNumDisks} Available no of cores : {hrd.avNumCores}"
                )
            else:
                print(
                    f"Harware Server Name: {hrd.phySerName} Rack assigned: {hrd.rackAssigned.rackName} Total Memory size:{hrd.mem} Total no of disks: {hrd.numDisks} Total no of cores : {hrd.numCores}"
                )
        if context.admin_rights:
            logger.info(
                "COMMAND: aggiestack admin show hardware - SUCCESS - printed configuration on console"
            )
        else:
            logger.info(
                "COMMAND: aggiestack show hardware - SUCCESS - printed configuration on console"
            )
    else:
        print("no hardware servers found")
        if context.admin_rights:
            logger.info(
                "COMMAND: aggiestack admin show hardware - No Stored machine Configurations Found"
            )
        else:
            logger.info(
                "COMMAND: aggiestack show hardware - No Stored machine Configurations Found"
            )
Example #2
0
def show_image_caches(context, rack_name):
    print(f'Request to show image caches in a seperate files')
    if not context.admin_rights:
        logger.error('show imagecaches allowed only in ADMIN mode')
        logger.info(
            "COMMAND: aggiestack show imagechaces - INVALID COMMAND - add admin"
        )
    else:
        rk = Rack.objects(rackName=rack_name).first()
        if rk:
            imageCacheList = rk.imgCache
            if imageCacheList:
                print("Images cached: ")
                for img in imageCacheList:
                    print(img.imageName)
                logger.info(
                    "COMMAND: aggiestack admin show imagechaces - SUCCESS")
                print(
                    f"Available Storage on Rack to cache images: {rk.avStorage}"
                )
            else:
                print("No Image caches found")
                print(f"Available Storage on Rack: {rk.avStorage}")
                logger.info(
                    "COMMAND: aggiestack admin show imagechaces - No images caches found"
                )
        else:
            print("Invalid rack name. Enter valid rack name")
            logger.info(
                "COMMAND: aggiestack show imagechaces - FAILED. Invalid rack name. Re-enter a valid rack name"
            )
Example #3
0
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"
        )
Example #4
0
def show_all_configs(context):
    print(
        "\n*************************HARDWARE CONFIGURATION********************************"
    )
    show_hardware(context)
    print(
        "\n*************************IMAGES CONFIGURATION********************************"
    )
    show_images(context)
    print(
        "\n*************************FLAVOR CONFIGURATION********************************"
    )
    show_flavors(context)
    logger.info(
        "COMMAND: aggiestack show all - SUCCESS - printed configurations on console"
    )
Example #5
0
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")
Example #6
0
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}")
Example #7
0
def cli(context, command_args):
    """
    Display the available configurations

    Sub commands allowed:
        all:        Show all the arguments
        hardware:   Show all the hardware servers configured
        instances:  Show all the instances
        flavors:    Show all the flavors
        images:     Show all the images configured
        imagecaches Show the image cacehes on a rack
                    Argument:
                        rack_name name of the rack names
    """
    cmd = "aggiestack show"
    if context.admin_rights:
        my_logger.info("Enter the ADMIN!")
        cmd = "aggiestack admin show"

    if len(command_args) == 0:
        logger.error(f'no sub command added after show, $> {cmd}')
        logger.info(f"FAILED: COMMAND: {cmd}")

    if command_args[0] == 'images':
        show_images(context)
    elif command_args[0] == 'flavors':
        show_flavors(context)
    elif command_args[0] == 'hardware':
        show_hardware(context)
    elif command_args[0] == 'instances':
        show_instances(context)
    elif command_args[0] == 'imagecaches' and len(command_args) == 2:
        show_image_caches(context, command_args[1])
    elif command_args[0] == 'all':
        show_all_configs(context)
    else:
        logger.error('Unknown command signature, $> {cmd} {command_args[0]}')
        logger.info(f"FAILED: COMMAND: {cmd} {command_args[0]}")
Example #8
0
def show_images(context):
    imageList = Image.objects({})

    if imageList.first():
        for img in imageList:
            r = []
            for rc in Rack.objects(imgCache__in=[img.imageName]):
                r.append(rc.rackName)
            if r:
                print(
                    f"Image Name: {img.imageName}  Size : {img.imageSize}  location {img.imageLocation} Racks image cached on: {r}"
                )
            else:
                print(
                    f"Image Name: {img.imageName}  Size : {img.imageSize}  location {img.imageLocation} Racks image cached on: No racks cached on"
                )
        logger.info(
            "COMMAND: aggiestack show images - SUCCESS - printed configuration on console"
        )
    else:
        print("No images found")
        logger.info(
            "COMMAND: aggiestack show images - No Stored image Configurations Found"
        )
Example #9
0
def list_servers():
    logger.info(f"Got request to list all servers")
    instanceList = Instance.objects({})
    if instanceList.first():
        for inst in instanceList:
            logger.info(
                f"Instance Name: {inst.instanceName} Image Name: {inst.imageName} Flavor Name: {inst.flavorName}"
            )

    else:
        logger.error("no instances found")
    logger.info("SUCCESS: COMMAND:  aggiestack server list")
Example #10
0
def show_instances(context):
    if not context.admin_rights:
        print(" add admin to see instances or use server list command")
        logger.info(
            "COMMAND: aggiestack show instances - INVALID COMMAND - add admin")
        return
    instanceList = Instance.objects({})
    if instanceList.first():
        for inst in instanceList:
            print(
                f"Instance Name: {inst.instanceName} Physical Server Running on:{inst.phySerName} Rack assigned to: {inst.rackAssigned}"
            )
        logger.info(
            "COMMAND: aggiestack admin show instances - SUCCESS - printed configuration on console"
        )
    else:
        print("no instances found")
        logger.info(
            "COMMAND: aggiestack show instances - FAILED - no instances found")
Example #11
0
def cli(context, subcommand, command_args):
    """
    \b
    Works with the following subcommands:
    create: creates the instance
        Argument: INSTANCE_NAME
        Options:
            --flavor Name of the flavor to be configured with the server
            --image  Name of the image  to be configured with the server
    delete: Deletes the instance
        Argument: INSTANCE_NAME
    list: Lists all the servers configured
    """
    if len(command_args) == 0 and subcommand == "list":
        list_servers()
    elif len(command_args) >= 1 and subcommand == "create":
        try:
            instance_name, flavor, image = parse_command_args_for_values(
                command_args)
            if not instance_name:
                logger.error(
                    "Instance name not provided with the server create command"
                )
                logger.info(
                    f"FAILED: COMMAND:  aggiestack server {subcommand} {command_args}"
                )
                return
            create_server_instance(instance_name, flavor, image)
        except IOError:
            logger.error('Incorrect format of args passed')
            logger.info(
                f"FAILED: COMMAND:  aggiestack server {subcommand} {command_args}"
            )
            return
    elif len(command_args) == 1 and subcommand == "delete":
        instance_name = command_args[0]
        delete_server_instance(instance_name)
    else:
        logger.error(f"Command '$> server {subcommand}' not defined")
        logger.info(
            f"FAILED: COMMAND:  aggiestack server {subcommand} {command_args}")
Example #12
0
def cli(context, mem, disk, vcpus, ip, rack, machine_name):
    """Add the machine to the system so that it may receive new instances.
    This is usually invoked when a "sick" server was fixed, and it is ready to work again.
    Argument: MACHINE_NAME"""

    if (not context.admin_rights):
        logger.error('Can allow this operation only in admin mode')
        logger.info(
            f'FAILED: COMMAND: aggiestack adming add --mem  {mem} --disk {disk} --vcpus {vcpus} --ip {ip} --rack {rack} {machine_name}'
        )
        return

    logger.info("Machine to be added with configuration: \n")
    logger.info(f"Name: {machine_name}")
    logger.info(f"Mem: {mem}")
    logger.info(f"Disk: {disk}")
    logger.info(f"Vpus: {vcpus}")
    logger.info(f"Ip: {ip}")
    logger.info(f"Rack Name: {rack}")

    rack = Rack.objects(rackName=rack).first()
    if not rack:
        logger.error(f"Rack '{rack}' doesn't exist")
        logger.info(
            f'FAILED: COMMAND: aggiestack adming add --mem  {mem} --disk {disk} --vcpus {vcpus} --ip {ip} --rack {rack} {machine_name}'
        )
        return
    else:
        hardware = Hardware.objects(ipAddress=ip).first()
        if hardware:
            logger.error(f"IP '{ip}' is already taken. Use different IP")
            logger.info(
                f'FAILED: COMMAND: aggiestack adming add --mem  {mem} --disk {disk} --vcpus {vcpus} --ip {ip} --rack {rack} {machine_name}'
            )
            return

        hardware = Hardware.objects(phySerName=machine_name).first()
        if hardware:
            logger.error(f"Machine '{machine_name}' already exists.")
            logger.info(
                f'FAILED: COMMAND: aggiestack adming add --mem  {mem} --disk {disk} --vcpus {vcpus} --ip {ip} --rack {rack} {machine_name}'
            )
            return

        hardware = Hardware(phySerName=machine_name,
                            rackAssigned=rack,
                            ipAddress=ip,
                            mem=mem,
                            numDisks=disk,
                            numCores=vcpus,
                            avMem=mem,
                            avNumDisks=disk,
                            avNumCores=vcpus)
        hardware.save()
        logger.info(
            f"Inserted Server: '{machine_name}' into rack '{rack.rackName}'")
        logger.info(
            f'SUCCESS: COMMAND: aggiestack adming add --mem  {mem} --disk {disk} --vcpus {vcpus} --ip {ip} --rack {rack} {machine_name}'
        )
Example #13
0
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}')
Example #14
0
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}"
        )
Example #15
0
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'
        )
Example #16
0
def cli(context, machine_name):
    """ Remove the machine name from the view of the datacenter """

    if (not context.admin_rights):
        logger.error('Can allow this operation only in admin mode')
        logger.info(f'FAILED: COMMAND:  aggiestack remove {machine_name}')
        return

    logger.info(f"Got request to evacuate machine: {machine_name}")
    server = Hardware.objects(phySerName=machine_name).first()
    if len(server.instances) == 0:
        server.delete()
        logger.info(f"Removed machine {machine_name}")
        logger.info(f"Removed machine {machine_name}")
        logger.info(
            f'SUCCESS: COMMAND:  aggiestack admin remove {machine_name}')
    else:
        logger.error(
            f"Can't remove machine '{machine_name}', it has {len(server.instances)} instances associated with it."
        )
        logger.info(
            f'FAILED: COMMAND:  aggiestack admin remove {machine_name}')