def setUp(self): self.setup_zookeeper() self.sandbox = "/tests/sr-%s" % uuid.uuid4().hex self.server = 'localhost:20000' self.ndsr = KazooServiceRegistry(server=self.server, rate_limit_calls=0, rate_limit_time=0)
def setUp(self): self.setup_zookeeper() self.server = 'localhost:20000' self.sandbox = "/tests/registration-%s" % uuid.uuid4().hex nd = KazooServiceRegistry(server=self.server, rate_limit_calls=0, rate_limit_time=0) self.zk = nd._zk
def setUp(self): self.setup_zookeeper() self.sandbox = "/tests/sr-%s" % uuid.uuid4().hex self.server = 'localhost:20000' self.username = '******' self.password = '******' self.ndsr = KazooServiceRegistry(server=self.server, username=self.username, password=self.password, rate_limit_calls=0, rate_limit_time=0) self._zk = self.ndsr._zk
class ZKAdapter(BaseStoreAdapter): # TODO: move the logic to the logical layer # TODO: separate the reader and the writer to different classes, since # they're using different clients # nd object handles all of the connection states # there is no need to start/stop or monitor the connection state at all. nd = KazooServiceRegistry(server=settings.ZK_HOSTS, timeout=settings.ZK_CONNECTION_TIMEOUT, rate_limit_calls=None) @property def key_separator(self): return "/" def get_key(self, *suffixes): """ @suffixes: anything to be added after the prefix and version e.g. application name, key, segments ... etc. """ suffixes = map(lambda s: s.lower(), suffixes) path = super(ZKAdapter, self).get_key(*suffixes) # append a preceeding slash in the beginning, ZK specific format path = "/%s" % path return path def _check_data(self, node): try: data = node["data"] stat = node["stat"] except (TypeError, KeyError) as e: # node is False or malformed # getting the node details from ZK failed. raise ZKConnectionTimeoutError(e) # if stat is None, the node does not exist if stat is None: raise KeyDoesNotExistError return data def _get_children(self, key): node = self.nd.get(key) # check if the node exists self._check_data(node) return node["children"] def connect(self): self.zk = KazooClient(hosts=settings.ZK_HOSTS) try: self.zk.start(timeout=settings.ZK_CONNECTION_TIMEOUT) except TimeoutError: raise ZKConnectionTimeoutError def disconnect(self): self.zk.stop() self.zk.close() def get_applications(self): try: # self.get_key() without params will get the root node path # i.e. "/flags/v1/" apps = self._get_children(self.get_key()) except KeyDoesNotExistError: return [] return apps def get_all_keys(self, *path): return self._get_children(self.get_key(*path)) def get_all_features(self, application): keys = self.get_all_keys(application, settings.FEATURES_KEY) items = dict() for key in keys: items[key] = self.read_feature(application, key) return items def get_all_segments(self, application): segments = self.get_all_keys(application, settings.SEGMENTS_KEY) items = dict() for segment in segments: # Read the options in each segment items[segment] = self.get_all_keys( application, settings.SEGMENTS_KEY, segment ) return items def create_feature(self, application, key, value=None): # Ensure a path, create if necessary app_path = self.get_key(application, settings.FEATURES_KEY) self.zk.ensure_path(app_path) node_path = self.get_key(application, settings.FEATURES_KEY, key) # default segmentation if value is None: value = self._prepare_default_feature_dict(application) try: # Create a node with data self.zk.create(node_path, json.dumps(value)) except NodeExistsError: raise KeyExistsError def _prepare_default_feature_dict(self, application): # Create the segmentation segments = self._get_children(self.get_key( application, settings.SEGMENTS_KEY )) segmentation = { segment: { "toggled": settings.DEFAULT_VALUE, "options": { option: settings.DEFAULT_VALUE for option in self._get_children( self.get_key( application, settings.SEGMENTS_KEY, segment ) ) } } for segment in segments } return { "segmentation": segmentation, "feature_toggled": settings.DEFAULT_VALUE } def create_application(self, application): # ensure that /flags/v1 path exists root_path = self.get_key() self.zk.ensure_path(root_path) node_path = self.get_key(application) try: # Create the application node self.zk.create(node_path) # add the features and segmentation paths to the newly created app self.zk.ensure_path( self.get_key(application, settings.FEATURES_KEY) ) self.zk.ensure_path( self.get_key(application, settings.SEGMENTS_KEY) ) except NodeExistsError: raise KeyExistsError def create_segment(self, application, segment): # Ensure a path, create if necessary app_path = self.get_key(application, settings.SEGMENTS_KEY) self.zk.ensure_path(app_path) node_path = self.get_key(application, settings.SEGMENTS_KEY, segment) try: self.zk.create(node_path) # Update the segmentation of the existing features self._update_new_segment(application, segment) except NodeExistsError: raise KeyExistsError def _update_new_segment(self, application, segment): segment = segment.lower() features = self.get_all_keys(application, settings.FEATURES_KEY) for feature in features: feature_dict = self.read_feature(application, feature) feature_dict["segmentation"][segment] = { "toggled": settings.DEFAULT_VALUE, "options": dict() } self.update_feature(application, feature, feature_dict) def _update_new_segment_option(self, application, segment, option): segment = segment.lower() option = option.lower() features = self.get_all_keys(application, settings.FEATURES_KEY) for feature in features: feature_dict = self.read_feature(application, feature) feature_dict["segmentation"][segment]["options"][option] = settings.DEFAULT_VALUE self.update_feature(application, feature, feature_dict) def _update_deleted_segment_option(self, application, segment, option): segment = segment.lower() option = option.lower() features = self.get_all_keys(application, settings.FEATURES_KEY) for feature in features: feature_dict = self.read_feature(application, feature) del feature_dict["segmentation"][segment]["options"][option] self.update_feature(application, feature, feature_dict) def _update_deleted_segment(self, application, segment): segment = segment.lower() features = self.get_all_keys(application, settings.FEATURES_KEY) for feature in features: feature_dict = self.read_feature(application, feature) del feature_dict["segmentation"][segment] self.update_feature(application, feature, feature_dict) def create_segment_option(self, application, segment, option): # Ensure a path, create if necessary app_path = self.get_key(application, settings.SEGMENTS_KEY, segment) self.zk.ensure_path(app_path) node_path = self.get_key(application, settings.SEGMENTS_KEY, segment, option) try: self.zk.create(node_path) self._update_new_segment_option(application, segment, option) except NodeExistsError: raise KeyExistsError def read_feature(self, application, key): return self.read(application, settings.FEATURES_KEY, key) def read_segment(self, application, key): # TODO: is this needed? return self.read(application, settings.SEGMENTS_KEY, key) def read(self, *key_path): node = self.nd.get(path=self.get_key(*key_path)) data = self._check_data(node) return data def update_feature(self, application, key, value): node_path = self.get_key(application, settings.FEATURES_KEY, key) try: self.zk.set(node_path, json.dumps(value)) except NoNodeError: raise KeyDoesNotExistError def delete_feature(self, application, key): node_path = self.get_key(application, settings.FEATURES_KEY, key) try: self.zk.delete(node_path) except NoNodeError: raise KeyDoesNotExistError