def delete(self, id): # make this more dynamic and check the parameters instancename = str(id) jobID = 27 jobURL = "api/v1/activities/27" # call the deletion of a instance appname = "get instance JSON from the instance controler, which simply reads the instance.json file in the instance directory" fh = FileHandler() instanceToBeDeleted = fh.getInstanceJSONContent(instancename) message = { "task": { "href": jobURL, "id": jobID }, "instance": instanceToBeDeleted, } deleteInstance.delay(instancename) return message, 202
def get(self): # should we put in an own class ?, maybe yes ... fh = FileHandler() # TODO - error if file does not exist try: fh.writeInstancesJsonFile() result = json.loads(fh.getInstancesJSONFile()) except: result = [] return result, 200
def get(self, name_to_check): name_to_check = str(name_to_check).lower() fh = FileHandler() res = 'false' try: names = fh.getInstanceNames() if name_to_check in names: res = 'true' except Exception as ex: print(ex) res = [str(ex)] return res, 200
def __replacePlaceholders (self, compose_dict): comp_str = self.template_str comp_str = comp_str.replace('§§INSTANCE', compose_dict['instancename']) # Replace BASEURL with bibbox baseurl fh = FileHandler() config = fh.getBIBBOXconfig () comp_str = comp_str.replace('§§BASEURL', config['baseurl']) # only applicable if §§KEY in docker-compose.yml.template == KEY in instanceDescr['instanceDescr'] (without §§ Prefix) # for key, value in self.instanceDescr.items(): # if not isinstance(value, dict): # str = str.replace('§§' + key, value) for key, value in self.instanceDescr['parameters'].items(): comp_str = comp_str.replace('§§' + key, value) return comp_str
def generateProxyFile (self): fh = FileHandler() config = fh.getBIBBOXconfig () proxy_infomation = self.getProxyInformation () proxyfile_content = "" for pi in proxy_infomation: if (pi['TEMPLATE'] == 'default'): defaultTemplate = fh.getConfigFile ('proxy-default.template') proxy = defaultTemplate.replace('§§BASEURL', config['baseurl']) proxy = proxy.replace('§§INSTANCEID', pi['URLPREFIX']) proxy = proxy.replace('§§CONTAINERNAME', pi['CONTAINER']) proxyfile_content += proxy + '\n\n' elif (pi['TEMPLATE'] == 'websocket'): wsTemplate = fh.getConfigFile('proxy-websocket.template') proxy = wsTemplate.replace('§§BASEURL', config['baseurl']) proxy = proxy.replace('§§INSTANCEID', pi['URLPREFIX']) proxy = proxy.replace('§§CONTAINERNAME', pi['CONTAINER']) proxy = proxy.replace('§§PATH_TO_SOCKET', pi['PATH_TO_SOCKET']) proxyfile_content += proxy + '\n\n' else: # TODO # other dynamic templates pass filename = '005-' + self.instanceDescr['instancename'] + '.conf' fh.writeProxyFile (filename, proxyfile_content)
def patch(self, id): instance_name = str(id) payload = request.json jobID = 27 jobURL = "api/v1/activities/27" fh = FileHandler() instanceToBeUpdated = fh.getInstanceJSONContent(instance_name) message = { "task": { "href": jobURL, "id": jobID }, "instance": instanceToBeUpdated, } updateInstanceInfos.delay(instance_name, payload) return message, 202
def restartInstance(self, instance_name): dh = DockerHandler() fh = FileHandler() # activity service for db-stuff with activity entries activity_service = ActivityService() # create activity entry in db -> returns ID of created entry activity_id = activity_service.create(f"Restart Instance: {instance_name}", "RESTART_INSTANCE") logger = DBLoggerService(activity_id, f"[RESTART] {instance_name}").getLogger() logger.info("restarting containers of {}.".format(instance_name)) fh.updateInstanceJsonState(instance_name, 'RESTARTING') emitInstanceRefresh() dh.docker_restartInstance(instance_name) fh.updateInstanceJsonState(instance_name, 'RUNNING') logger.info("restarted containers of {}".format(instance_name)) activity_service.update(activity_id, "FINISHED", "SUCCESS") emitInstanceRefresh()
def stopInstance(self, instance_name, called_from_deleteInstance=False): dh = DockerHandler() fh = FileHandler() # activity service for db-stuff with activity entries if not called_from_deleteInstance: activity_service = ActivityService() # create activity entry in db -> returns ID of created entry activity_id = activity_service.create( f"Stop Instance: {instance_name}", "STOP_INSTANCE") logger = DBLoggerService(activity_id, f"[STOP] {instance_name}").getLogger() logger.info("stopping containers of {}.".format(instance_name)) fh.updateInstanceJsonState(instance_name, 'STOPPING') emitInstanceRefresh() dh.docker_stopInstance(instance_name) fh.updateInstanceJsonState(instance_name, 'STOPPED') if not called_from_deleteInstance: logger.info("stopped containers of {}.".format(instance_name)) activity_service.update(activity_id, "FINISHED", "SUCCESS") emitInstanceRefresh()
def updateInstanceInfos(self, instance_name, payload): fh = FileHandler() # logger service for creating custom logger fh = FileHandler() try: fh.updateInstanceJsonInfo(instance_name, payload) emitInstanceRefresh() except Exception as ex: print(ex)
def deleteInstance(self, instance_name): dh = DockerHandler() fh = FileHandler() instance_path = fh.INSTANCEPATH + instance_name # activity service for db-stuff with activity entries activity_service = ActivityService() # create activity entry in db -> returns ID of created entry activity_id = activity_service.create(f"Delete instance: {instance_name}", "DELETE_INSTANCE") # logger service for creating custom logger logger_serv = DBLoggerService(activity_id, f"[DELETE] {instance_name}") # get custom logger from logger service logger = logger_serv.getLogger() try: fh.updateInstanceJsonState(instance_name, "DELETING") except Exception as ex: print(ex) try: try: stopInstance(instance_name, called_from_deleteInstance=True) except Exception as ex: print("Stopping {} containers failed. Exception: {}".format( instance_name, ex)) logger.error("Stopping {} containers failed. Exception: {}".format( instance_name, ex)) raise else: print( "Successfully stopped the {} containers".format(instance_name)) logger.info("Successfully stopped the {} containers.".format( instance_name)) finally: fh.updateInstanceJsonState(instance_name, "DELETING") try: dh.docker_deleteStoppedInstance(instance_name) except Exception as ex: print("Deletion of stopped {} containers failed. Exception: {}". format(instance_name, ex)) logger.error( "Deletion of stopped {} containers failed. Exception: {}". format(instance_name, ex)) raise else: print( "Successfully deleted the {} containers".format(instance_name)) logger.info( "Successfully deleted the {} containers".format(instance_name)) try: fh.removeProxyConfigFile(instance_name) except Exception as ex: print("Deletion of the proxy file of {} failed. Exception: {}". format(instance_name, ex)) logger.error( "Deletion of the proxy file of {} failed. Exception: {}". format(instance_name, ex)) raise else: print("Successfully deleted the proxy file of {}.".format( instance_name)) logger.info("Successfully deleted the proxy file of {}.".format( instance_name)) try: fh.removeAllFilesInDir(instance_path) except Exception as ex: print("Deletion of the directory {} failed. Exception: {}".format( instance_name, ex)) logger.error( "Deletion of the directory {} failed. Exception: {}".format( instance_name, ex)) raise else: print( "Successfully deleted the directory {}.".format(instance_name)) logger.info( "Successfully deleted the directory {}.".format(instance_name)) # write the instances.json file try: fh.writeInstancesJsonFile() except Exception as ex: #print (" ERROR in the generation of the instances.json File") logger.error( "Updating the instances.json file failed. Exception: {}". format(ex)) raise else: #print ("Successfully created the instances.json File") logger.info("Successfully updated the instances.json file.") except Exception as ex: logger.error("Deleting instance {} failed: {}.".format( instance_name, ex)) activity_service.update(activity_id, "ERROR", "FAILURE") else: logger.info("Successfully deleted instance {}.".format(instance_name)) activity_service.update(activity_id, "FINISHED", "SUCCESS") emitInstanceDeleted(instance_name) finally: emitInstanceRefresh()
def installInstance(self, instanceDescr): path_dir = INSTANCEPATH + instanceDescr['instancename'] # appinfo.json, fileinfo.json, docker-compose.yml.template, file_handler = FileHandler() # check if directory structure is valid, fixes structure if invalid # needs to be called sooner, but where/when? file_handler.checkDirectoryStructure() # activity service for db-stuff with activity entries activity_service = ActivityService() # create activity entry in db -> returns ID of created entry activity_id = activity_service.create( f"Installing Instance: {instanceDescr['instancename']}", "INSTALL_INSTANCE") # logger service for creating custom logger logger_serv = DBLoggerService( activity_id, f"[INSTALL] {instanceDescr['instancename']}") logger = logger_serv.getLogger() # generate the instance directory try: try: os.mkdir(path_dir) path = INSTANCEPATH + instanceDescr[ 'instancename'] + "/instance.json" with open(path, 'w') as f: instanceDescr['state'] = 'INSTALLING' instanceDescrInTheFile = copy.deepcopy(instanceDescr) del instanceDescrInTheFile['parameters'] simplejson.dump(instanceDescrInTheFile, f) except OSError as ex: #print ("Creation of the directory %s failed" % path) logger.error( "Creation of the directory {} failed. Exception: {}".format( instanceDescr['instancename'] + "/instance.json", ex)) raise else: #print ("Successfully created the directory %s " % path) logger.info("Successfully created the directory {}.".format( instanceDescr['instancename'] + "/instance.json")) emitInstanceRefresh() try: # copy all file from the APP repository to the instance Directory logger.info("Trying to download github files...") file_handler.downloadGithubZip(instanceDescr, logger) except Exception as ex: logger.error( f"Copying files from github-repository to instance directory failed: {ex}" ) raise else: logger.info( "Successfully downloaded files from github-repository to instance directory." ) try: objects_to_set_permissions = file_handler.getPermissionsFromFileinfo( instanceDescr['instancename']) logger.info("Trying to set permissions now...") for object, permission in objects_to_set_permissions.items(): current_path = os.path.join(file_handler.INSTANCEPATH, instanceDescr['instancename'], object) if int(permission) not in range(0, 778): logger.warning( f'Numeric Permission Value not valid! Value: {permission}, valid range: 000-777. Skipping ...' ) continue if os.path.exists(current_path): res_code = os.system( f'chmod -R {permission} {current_path}') logger.info( f"Setting permissions for object {object} to {permission}. Result code: {res_code}" ) else: logger.warning( f"Setting permissions for object {object} failed. Path {os.path.join(file_handler.INSTANCEPATH, object)} does not exist. Skipping..." ) except Exception as ex: logger.error( "Setting permissions for {} failed. Exception: {}".format( instanceDescr['instancename'], ex)) raise else: logger.info("Successfully set permissions") instance = None try: # now we can generate an Instance object instance = Instance(instanceDescr['instancename']) except Exception as ex: logger.error(f"Creating instance object failed: {ex}") raise # add the container names to the instance.json file try: template_str = instance.composeTemplate() instance_handler = InstanceHandler(template_str, instanceDescr) container_names = instance_handler.getContainerNames() file_handler.updateInstanceJsonContainerNames( instanceDescr['instancename'], container_names) except Exception as ex: logger.error( "Updating {} instance.json file with container_names failed. Exception: {}" .format(instanceDescr['instancename'], ex)) raise else: logger.info( "Successfully updated the {} instance.json file with container_names." .format(instanceDescr['instancename'])) emitInstanceRefresh() compose_file_name = INSTANCEPATH + instanceDescr[ 'instancename'] + "/docker-compose.yml" proxy_file_name = PROXYPATH + '005-' + instanceDescr[ 'instancename'] + ".conf" # generate the docker-compose file try: template_str = instance.composeTemplate() instance_handler = InstanceHandler(template_str, instanceDescr) docker_compose = yaml.dump(instance_handler.getCompose(), default_flow_style=False) with open(compose_file_name, 'w') as f: f.write(docker_compose) except Exception as ex: #print ("ERROR in the generation of the Docker Compose" ) logger.error( "Creation of the {} docker-compose file failed. Exception: {}". format(instanceDescr['instancename'] + "/docker-compose.yml", ex)) raise else: #print ("Successfully created the docker-compose" ) logger.info( "Successfully created the {} docker-compose file.".format( instanceDescr['instancename'] + "/docker-compose.yml")) # generate the docker-compose local file try: template_str = instance.composeTemplate() instance_handler = InstanceHandler(template_str, instanceDescr) docker_compose = yaml.dump(instance_handler.getComposeLocal(), default_flow_style=False) compose_file_name_local = compose_file_name + '.local' with open(compose_file_name_local, 'w') as f: f.write(docker_compose) except Exception as ex: #print ("ERROR in the generation of the Docker Compose" ) logger.error( "Creation of the {} docker-compose-local file failed. Exception: {}" .format( instanceDescr['instancename'] + "/docker-compose.yml.local", ex)) raise else: #print ("Successfully created the docker-compose" ) logger.info( "Successfully created the {} docker-compose file.".format( instanceDescr['instancename'] + "/docker-compose.yml.local")) # write the proxy file try: template_str = instance.composeTemplate() instance_handler = InstanceHandler(template_str, instanceDescr) instance_handler.generateProxyFile() except Exception as ex: #print ("ERROR in the generation of the Proxy File" ) logger.error( "Creation of the {} proxy file failed. Exception: {}".format( '005-' + instanceDescr['instancename'] + ".conf", ex)) raise else: #print ("Successfully created the proxy file" ) logger.info("Successfully created the {} proxy file.".format( '005-' + instanceDescr['instancename'] + ".conf")) emitInstanceRefresh() # write the instances.json file try: file_handler.writeInstancesJsonFile() except Exception as ex: #print (" ERROR in the generation of the instances.json File") logger.error( "Creation of the instances.json file failed. Exception: {}". format(ex)) raise else: #print ("Successfully created the instances.json File") logger.info("Successfully created the instances.json file.") # testing to update instance json file_handler.updateInstanceJsonState(instanceDescr['instancename'], "INSTALLING") file_handler.updateInstanceJsonProxy( instanceDescr['instancename'], instance_handler.getProxyInformation()) emitInstanceRefresh() # call docker-compose up print(compose_file_name) # process = subprocess.Popen(['ls', '-la', '/opt/bibbox/instances'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding="utf8") logger.info("Running docker-compose up.") process = subprocess.Popen( ['docker-compose', '-f', compose_file_name, 'up', '-d'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding="utf8") # TOOO # put this in a helper function for calling system commands ansi_regex = r'\x1b+\[+\d+\d+;+\d+\d+[m]|' \ r'\x1b(' \ r'(\[\??\d+[hl])|' \ r'([=<>a-kzmNM78])|' \ r'([\(\)][a-b0-2])|' \ r'(\[\d{0,2}[ma-dgkjqi])|' \ r'(\[\d+;\d+[hfy]?)|' \ r'(\[;?[hf])|' \ r'(#[3-68])|' \ r'([01356]n)|' \ r'(O[mlnp-z]?)|' \ r'(/Z)|' \ r'(\d+)|' \ r'(\[\?\d;\d0c)|' \ r'(\d;\dR)|' \ r'(\[*\d*\d*;*\d*\d*[m]))' ansi_escape = re.compile(ansi_regex, flags=re.IGNORECASE) while True: line = process.stdout.readline() lineerror = process.stderr.readline() if not line and not lineerror: break #the real code does filtering here if line: # look what we have to strip # if there are some escape code, that the öine is overwritten, the last line in the log should be replaced result = ansi_escape.sub('', line).rstrip() print(line.rstrip()) print(result) if lineerror: # same stuff here, also write this in the log file print(lineerror.rstrip()) ####### ####### setting permissions again afterwards is not needed afaik, as the permission handling code was just not working correctly, ####### as the os.system chmod command wants the absolute path, not the relative path. Should be fixed now - Lukas ####### # try: # objects_to_set_permissions = file_handler.getPermissionsFromFileinfo(instanceDescr['instancename']) # logger.info("Trying to set permissions now...") # for folder, permission in objects_to_set_permissions.items(): # current_path = os.path.join(file_handler.INSTANCEPATH, instanceDescr['instancename'], folder) # if int(permission) not in range(0, 778): # logger.warning(f'Numeric Permission Value not valid! Value: {permission}, valid range: 000-777. Skipping ...') # continue # if os.path.exists(current_path): # logger.info(f"Setting permissions for object {folder} to {permission}.") # os.system(f'chmod -R {permission} {folder}') # else: # logger.warning(f"Setting permissions for object {folder} failed. Path {os.path.join(file_handler.INSTANCEPATH, folder)} does not exist.") # except Exception as ex: # logger.error("Setting permissions for {} failed. Exception: {}".format(instanceDescr['instancename'], ex)) # raise # else: # logger.info("Successfully set permissions") # try: # objects_to_set_permissions = file_handler.getPermissionsFromFileinfo(instanceDescr['instancename']) # logger.info("Trying to set permissions now...") # for folder, permission in objects_to_set_permissions.items(): # current_path = os.path.join(file_handler.INSTANCEPATH, instanceDescr['instancename'], folder) # if int(permission) not in range(0, 778): # logger.warning(f'Numeric Permission Value not valid! Value: {permission}, valid range: 000-777. Skipping ...') # continue # if os.path.exists(current_path): # logger.info(f"Setting permissions for object {folder} to {permission}.") # os.system(f'chmod -R {permission} {folder}') # else: # logger.warning(f"Setting permissions for object {folder} failed. Path {os.path.join(file_handler.INSTANCEPATH, folder)} does not exist.") # except Exception as ex: # logger.error("Setting permissions for {} failed. Exception: {}".format(instanceDescr['instancename'], ex)) # raise # else: # logger.info("Successfully set permissions") logger.info("Graceful reloading bibbox-sys-commander-apacheproxy...") process = subprocess.Popen([ 'docker', 'exec', 'bibbox-sys-commander-apacheproxy', 'httpd', '-k', 'graceful' ], shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding="utf8") while True: line = process.stdout.readline() lineerror = process.stderr.readline() if not line and not lineerror: break #the real code does filtering here if line: # look what we have to strip # if there are some escape code, that the line is overwritten, the last line in the log should be replaced result = ansi_escape.sub('', line).rstrip() print(line.rstrip()) print(result) if lineerror: # same stuff here, also write this in the log file print(lineerror.rstrip()) except Exception as ex: print(ex) logger.error("Installing instance {} failed: {}.".format( instanceDescr['instancename'], ex)) file_handler.updateInstanceJsonState(instanceDescr['instancename'], "ERROR") activity_service.update(activity_id, "ERROR", "FAILURE") else: logger.info("Successfully installed instance {}.".format( instanceDescr['instancename'])) file_handler.updateInstanceJsonState(instanceDescr['instancename'], "RUNNING") activity_service.update(activity_id, "FINISHED", "SUCCESS") finally: emitInstanceRefresh()
def get(self, id): fh = FileHandler() idescr = fh.getInstanceJSONContent(str(id)) return idescr, 200