class RatchetHubService: def __init__(self, req_port, log_pub_port, config, qplan_instance_hash): self.req_port = req_port self.log_pub_port = log_pub_port self.config = config self.name = "%s/RatchetHubService" % config.get('Ratchet Hub', 'org_name') self.qplan_instance_hash = qplan_instance_hash host = "127.0.0.1" self.responder = HubResponder(host, self.req_port, self.get_response) self.log_publisher = Publisher(host, self.log_pub_port) return def run(self): self.responder.run() return def get_qplan_web_apps(self): instance_names = self.qplan_instance_hash.keys() instance_names.sort() items = [] for name in instance_names: item = self.qplan_instance_hash[name] items.append("%s\t%s\t%d" % (name, item['host'], item['web_port'])) result = "\n".join(items) return result def get_qplan_instance_config(self, args): team = args[0] item = None if team in self.qplan_instance_hash: item = self.qplan_instance_hash[team] if not item: # TODO: Log error here return "" result = "%s\t%d\t%d\t%d" % (item['host'], item['web_port'], item['req_port'], item['sub_port']) return result def get_ratchet_hub_info(self): result = self.stringify_config_section("Ratchet Hub") return result def get_src_root(self): result = config.get('Ratchet Hub', 'src_root') return result def get_header_file_map(self, args): # Need to join args in case section consists of multiple words section_name = " ".join(args) result = self.stringify_config_section(section_name) return result def log(self, level, msg): self.log_publisher.publish("%s: %s" % (level, msg)) return # ========================================================================= # Private functions def get_response(self, request): try: args = request.split(' ') func = args[0] result = "" if func == "get_qplan_web_apps": result = self.get_qplan_web_apps() elif func == "get_qplan_instance_config": result = self.get_qplan_instance_config(args[1:]) elif func == "get_src_root": result = self.get_src_root() elif func == "get_header_file_map": result = self.get_header_file_map(args[1:]) elif func == "get_update_periods": result = self.stringify_config_section("Update Periods") elif func == "get_vacationator_config": result = self.stringify_config_section("Vacationator Config") elif func == "get_qplan_config": result = self.stringify_config_section("QPlan Config") elif func == "get_vantage_config": result = self.stringify_config_section("Vantage Config") elif func == "get_external_access_params": result = self.stringify_config_section("External Access") elif func == "get_team_instances_info": result = self.stringify_config_section("Teams Config") elif func == "get_ratchet_hub_info": result = self.get_ratchet_hub_info() elif func == "log": level = args[1] msg = ' '.join(args[2:]) self.log(level, msg) else: self.log("WARN", "Don't know how to handle: %s" % func) result = "Huh?" except Exception as e: # TODO: Add name of hub service self.log("ERRR", str(e)) return result def stringify_config_section(self, section_name): items = [] for item in self.config.items(section_name): items.append("%s\t%s" % (item[0], item[1])) result = "\n".join(items) return result
class SnapshotService(Responder): """Manages snapshotting data files""" #=========================================================================== # Public API # #--------------------------------------------------------------------------- # Sets up 0mq sockets and repo to use for snapshot data. # # ratchet_hub is a services.ratchet_hub.RatchetHub # def __init__(self, name, header_file_map, repo_dir, reply_port, publish_port, ratchet_hub=None): Responder.__init__(self, '127.0.0.1', reply_port) self.name = name self.header_file_map = header_file_map self.publisher = Publisher('127.0.0.1', publish_port) self.ratchet_hub = ratchet_hub # Set working directory to the repo os.chdir(repo_dir) self.log_info("Ready") return def log_info(self, message): ''' Logs informational message. If a ratchet hub has been specified, use that. Otherwise, just write to stderr. ''' if self.ratchet_hub: self.ratchet_hub.log_info(self.name, message) else: sys.stderr.write("%s\n" % message); return def log_error(self, message): ''' Logs error message. If a ratchet hub has been specified, use that. Otherwise, just write to stderr. ''' if self.ratchet_hub: self.ratchet_hub.log_error(self.name, message) else: sys.stderr.write("ERROR: %s\n" % message); return # @Override def get_response(self, request): result = "OK" header = "" message = io.StringIO(request) sections = sectionize(message) try: for h in sections.keys(): header = h if re.match("PUT", header): result = self.put_resource(header, sections[header], self.header_file_map) self.ratchet_hub.log_info(self.name, "Done with '%s'" % header) elif re.match("GET", header): result = self.get_resource(header, sections[header], self.header_file_map) self.ratchet_hub.log_info(self.name, "Done with '%s'" % header) else: self.log_error("Unrecognized header: %s" % header) result = "TODO: Handle %s" % header except Exception as e: self.log_error("Problem with request: " % message) error_message = "Couldn't find header (%s) in snapshot service" % (header) self.log_error(error_message) result = error_message return result #=========================================================================== # Internal functions # #--------------------------------------------------------------------------- # Wraps git to commit data to repo. # def commit_file(self, file): # Add file git_result = subprocess.call("git add %s" % file, shell=True) if git_result != 0: raise CommitError("Problem adding %s" % file) # Commit file git_result = subprocess.call("git commit -m 'Update %s'" % file, shell=True) #--------------------------------------------------------------------------- # Writes a new data snapshot to database. # def put_resource(self, header, data, header_map): resource = header.split("PUT ")[1] filename = header_map[resource] dirname = os.path.dirname(filename) # TODO: Test this at least once if not (os.path.exists(dirname) or dirname == ""): os.makedirs(dirname) # Write data to file file = open(filename, "w") file.write(data); file.close() # Check file in and publish to subscribers try: self.commit_file(filename) self.publisher.publish("=====%s" % resource) return "OK" except CommitError: error_msg = "ERROR: Couldn't commit PUT %s" % resource self.log_error(error_message) return error_msg #--------------------------------------------------------------------------- # Retrieves data snapshot. # def get_resource(self, header, data, header_map): try: resource = header.split("GET ")[1] filename = header_map[resource] version = data.split("\t")[0] if not version: version = "HEAD" print("Getting data for %s, %s" % (header, version)) p = subprocess.Popen("git show %s:%s" % (version, filename), stdout=subprocess.PIPE, shell=True) contents = io.StringIO(p.communicate()[0]) if p.returncode != 0: rev = '' else: p = subprocess.Popen("git rev-parse %s" % version, stdout=subprocess.PIPE, shell=True) rev = p.communicate()[0][0:5] data = [] for l in contents.readlines(): data.append("\t%s" % l) new_contents = "".join(data) message = make_sections([[resource, "\t%s\n" % rev], ["data", new_contents]]) return message except: error_message = "ERROR: Couldn't GET %s @ %s, filename: %s" % (resource, version, filename) self.log_error(error_message)