Skip to content
Snippets Groups Projects
Select Git revision
  • dd235b83cdae4fff2374b27bed1aac76f230db39
  • main default protected
2 results

handlers.go

Blame
  • Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    orchestrator.py 6.08 KiB
    import openstack
    import random
    import time
    from customLogger import *
    
    class Orchestrator:
        
        def __init__(self):
            # Initialize and turn on debug logging if wanted
            openstack.enable_logging(debug=False)
            # Initialize connection
            self.conn = openstack.connect()
    
    
        # Creates a random name
        # creates the project stack based on the templates in the HEAT folder
        # Sends the owner of the project as a tag if it exits
        # and client count as a parameter if it is within limit
        def createProject(self, members, owner, publicKey):
            name = self.createRandomName()
            
            # ensures client count is positive
            # stops user from making more than 15 clients
            clientCount = len(members)
            if clientCount > 15:
                clientCount = 15
    
            RDPMembers = self.allowRDP(members)
            
            try:
                self.conn.create_stack(name, template_file='orchestrationLogic/HEAT/project.yaml', rollback = False, project_name = name, key_name = 'mankey', windows_count = clientCount, project_owner = owner, public_key = publicKey, RDP_members = RDPMembers, tags = owner)
            except:
                logger.exception("Stack create API call failed", extra={"tags": {"owner": owner}})
                return None
    
            
            logger.info("Project create api call succeeded" , extra={"tags": {"owner": owner, "project": name}})
            logger.info(RDPMembers)
            return name
    
        # Checks continously if the project creation is in progress
        # In not true is returned if status is create complete
        # Else false is returned
        def ensureProjectCreation(self, nameOrID):
            status = self.getStackStatus(nameOrID)
    
            wait = 20
            while status == 'CREATE_IN_PROGRESS':
                time.sleep(wait)
                wait +=5
                status = self.getStackStatus(nameOrID)
            if status == 'CREATE_COMPLETE':
                logger.info("Project creation completed", extra={"tags": {"project": nameOrID}} )
                return True
            else:
                logger.error("Project creaation failed. Status: {}, Reason: {}".format(status, self.getStatusReason(nameOrID)) , extra={"tags": {"project": nameOrID}})
                if self.deleteProject(nameOrID):
                    self.ensureProjectDeletion(nameOrID)
                return False
            
            
        # returns false if something went wrong during the api call or if the project does not exist
        # else true 
        def deleteProject(self, nameOrID):
            try: 
                result = self.conn.delete_stack(nameOrID)
            except:
                logger.exception("Stack delete API call failed.", extra={"tags": {"project": nameOrID}})
                return False
    
            if result:
                logger.info("Project delete api call succeeded", extra={"tags": {"project": nameOrID}})
                return True
            else:
                logger.error("Attempted to delete project that does not exist", extra={"tags": {"project": nameOrID}})
                return False
    
        
        # checks continiously if delition is in progress
        # returns true if the project does not exist (delete sucessfull)
        # else false
        def ensureProjectDeletion(self, nameOrID):
            status = self.getStackStatus(nameOrID)        
            wait = 5
            while status and status != "DELETE_FAILED":
                time.sleep(wait)
                wait +=2
                status = self.getStackStatus(nameOrID)
            
            # Stack no longer exists
            if not status:
                logger.info("Project was successfully deleted", extra={"tags": {"project": nameOrID}})
                return True
            else:
                logger.error("Failed to delete project. Status: {}, Reason: {}".format(status, self.getStatusReason(nameOrID)), extra={"tags": {"project": nameOrID}})
                return False
    
        # returns the status of the stack if it exists
        # returns None if the stack does not exist
        # returns "UNKNOWN" if something goes wrong in the query
        def getStackStatus(self, nameOrID):
            try:
                stack = self.conn.get_stack(nameOrID, resolve_outputs=False)
            except:
                logger.exception("api call on get_stack raised an exeption" , extra={"tags": {"project": nameOrID}})
                return "UNKNOWN"
            if stack:
                return stack.stack_status
            else:
                return None
    
    
        # returns the status of the stack if it exists
        # returns None if the stack does not exist
        # returns "UNKNOWN" if something goes wrong in the query
        def getStatusReason(self, nameOrID):
            try:
                stack = self.conn.get_stack(nameOrID, resolve_outputs=False)
            except:
                logger
                return "UNKNOWN"
            if stack:
                return stack.stack_status_reason
            else:
                return "UNKNOWN"
    
    
        # returns None if something goes wrong in the query or if the stack does not exist
        # Else the IP is returned
        def getLBIP(self, nameOrID):
            try:
                stack = self.conn.get_stack(nameOrID, resolve_outputs=True)
            except:
                logger.exception("Api call on get_LBIP for raised an exeption", extra={"tags": {"project": nameOrID}})
                return None
    
            if stack:
                logger.info("Loadbalancer IP {} was collected".format(stack.outputs[0]["output_value"]), extra={"tags": {"project": nameOrID}})
                return (stack.outputs[0]["output_value"])
            else:
                logger.error("Attempted to get ip of loadbalancer that does not exist", extra={"tags": {"project": nameOrID}})
                return None
    
        # Returns a random name in the format "adjective_animal"
        def createRandomName(self):
            lines = open('orchestrationLogic/wordlists/adjectives.txt').read().splitlines()
            adjective =random.choice(lines)
            
            lines = open('orchestrationLogic/wordlists/animals.txt').read().splitlines()
            animal =random.choice(lines)
    
            name = adjective + '_' + animal
            return name
    
        
    
    
        def allowRDP(self, members):
            result = ''
            for member in members:
                result += "Add-LocalGroupMember -Group 'Remote Desktop Users' -Member '{}' -ErrorAction Stop;".format(member)
            return result