{"id":15372987,"url":"https://github.com/rs/zkfarmer","last_synced_at":"2025-04-15T11:31:52.448Z","repository":{"id":65031733,"uuid":"3175676","full_name":"rs/zkfarmer","owner":"rs","description":"ZkFarmer is a set of tools to easily manage distributed server farms using Apache ZooKeeper","archived":false,"fork":false,"pushed_at":"2023-06-15T10:08:58.000Z","size":138,"stargazers_count":74,"open_issues_count":0,"forks_count":15,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-03-28T21:03:06.281Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2012-01-14T01:09:15.000Z","updated_at":"2024-02-11T15:29:47.000Z","dependencies_parsed_at":"2024-10-16T12:41:34.154Z","dependency_job_id":"34a6fe73-4535-4651-ba35-57c644ded531","html_url":"https://github.com/rs/zkfarmer","commit_stats":{"total_commits":96,"total_committers":12,"mean_commits":8.0,"dds":0.6354166666666667,"last_synced_commit":"8dc6895540260a83355f0d644ded42b2331e5994"},"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rs%2Fzkfarmer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rs%2Fzkfarmer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rs%2Fzkfarmer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rs%2Fzkfarmer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rs","download_url":"https://codeload.github.com/rs/zkfarmer/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249061065,"owners_count":21206446,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-01T13:53:53.347Z","updated_at":"2025-04-15T11:31:52.173Z","avatar_url":"https://github.com/rs.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"ZooKeeper Farmer\n================\n\nZkFarmer is a set of tools to easily manage distributed server farms using [Apache ZooKeeper](http://zookeeper.apache.org/).\n\nWith ZkFarmer, each server registers itself in one or several farms. Thru this registration, hosts can expose arbitrary information about their status.\n\nOn the other end, ZkFarmer helps consumers of the farm to maintain a configuration file in sync with the list of hosts registered in the farm with their respective configuration.\n\nIn the middle, ZkFarmer helps monitoring and administrative services to easily read and change the configuration of each host.\n\nConnecting to Zookeeper\n-----------------------\n\nAll subcommands of `zkfarmer` needs the full list of your ZooKeeper cluster hosts. You can either pass the list of ZooKeeper hosts via the `ZKHOST` environment variable or via the `--host` parameter. Hosts are host:port pairs separated by commas. All examples in this documentation assume you have your ZooKeeper hosts configured in your environment.\n\nJoining a Farm\n--------------\n\nThe `zkfarmer join` command is used on each host to register itself in a farm. The command will create an `ephemeral` znode in ZooKeeper that will live until the program is killed. As this command will never return, you should start it as a service using something like `upstart`, `daemontools` or `launchd`. If the host crash or if you kill `zkfarmer`, the host's znode will be automatically removed by ZooKeeper.\n\nThis command takes two arguments, `farm path` and `conf path`. The `farm path` is the path to an existing znode on the ZooKeeper server used to store the hosts of a given farm.\n\nThe `conf path` is the path to the local configuration to be associated with the host. This configuration can be a JSON file or a DJB like directory configuration. DJB directory is the preferred format for this configuration as it offers better flexibility. With a DJB like directory configuration format, each directory is a dictionary and each file is a key with its contents as value.\n\nOnce started, the content of the local configuration is transformed into JSON and stored in an `ephemeral` znode on ZooKeeper. The znode is named after the IP of the host assigned to the default route.\n\nLets start the following command from the 1.2.3.4 host:\n\n    zkfarmer join /services/db /var/service/db\n\nLets assume `/var/service/db` is a directory containing the following structure:\n\n    hostname\n    enabled\n    mysql/\n      replication_delay\n\nThe `zkfarmer join` command transformed it to the following JSON object and stored it the `/services/db/1.2.3.4` znode:\n\n    {\n      \"hostname\": \"db-01.example.com\",\n      \"enabled\": \"0\",\n      \"mysql\": {\"replication_delay\": \"0\"}\n    }\n\nWhile the `zkfarmer join` command is running, this znode will be maintained up to date with local configuration and vis versa. For instance if you do an `echo 1 \u003e /var/service/db/enabled` from the host, the change will be immediately reflected into the znode JSON content. Any change on the content of the znode will also update the local configuration on the host.\n\nWhile this is not the primary goal of zkfarmer, you can also use it to synchronize a common configuration among a set of nodes. In this case, each node will use the same znode. You need to use the `--common` option when running `zkfarmer join` in this case. The JSON object will be stored in `/services/db/common` znode.\n\nUsage for the `zkfarmer join` command:\n\n    usage: zkfarmer join [-h] [-f {json,yaml,php,dir}] [-c] zknode conf\n\n    Make the current host to join a farm.\n\n    positional arguments:\n      zknode                the ZooKeeper node path of the farm\n      conf                  Path to the node configuration\n\n    optional arguments:\n      -h, --help            show this help message and exit\n      -f {json,yaml,php,dir}, --format {json,yaml,php,dir}\n                            set the configuration format\n      --changed-cmd CMD     a command to be executed each time the configuration\n                            change\n      -c, --common          use a common zookeeper node instead of a dedicated node\n\nSyncing Farm Configuration\n--------------------------\n\nOn the other end, consumers of the service provided by a farm may not have the ability to keep a permanent connection to ZooKeeper in order to maintain an up-to-date view of the farm state. ZkFarmer can do this for you by maintaining local configuration file reflecting the current status of the farm. PHP and JSON formats are currently supported, more formats may come in the future.\n\nTo do this, use the `zkfarmer export` command. As for the `join` command, it will run forever so you may launch it as a service. While the command is running, the destination configuration file will be synchronized with the content of the farm in real time.\n\nLets take our previous `/services/db` farm. Running the `zkfarm export /services/db /data/web/conf/database.php` will export and maintain the `/data/web/conf/database.php` file with the followoing content:\n\n    \u003c?php\n    return array\n    (\n        \"1.2.3.4\" =\u003e array\n        (\n            \"hostname\" =\u003e \"db-01.example.com\",\n            \"enabled\" =\u003e \"0\",\n            \"mysql\" =\u003e array(\"replication_delay\" =\u003e \"0\"),\n        ),\n        \"1.2.3.5\" =\u003e array\n        (\n            \"hostname\" =\u003e \"db-02.example.com\",\n            \"enabled\" =\u003e \"1\",\n            \"mysql\" =\u003e array(\"replication_delay\" =\u003e \"1\"),\n        ),\n        ...\n    );\n\nAdditionnaly, you can ask ZkFarmer to execute a command each time the configuration is updated. This command can, for instance, flush some cache, reload the conf file in your application etc.\n\nIt's possible to filter out some nodes from the exported configuration if it matches certain criteria so you don't have to filter them out at reading. The `--filters` parameter can be used to the that. A filter predicate is a field path followed by a comparison operator and a valud. Supported operator are one of `=`, `!=`, `\u003e`, `\u003c`, `\u003e=`, `\u003c=`. A predicate containing only a field path can be used to ensure the field is present whatever its value. A field path prefixed by a `!` means the oposite.\n\nLets take our previous `/services/db` farm. Running the `zkfarm export --filters enabled=1 /services/db /data/web/conf/database.php` will export and maintain the `/data/web/conf/database.php` file with the followoing content:\n\n    \u003c?php\n    return array\n    (\n        \"1.2.3.5\" =\u003e array\n        (\n            \"hostname\" =\u003e \"db-02.example.com\",\n            \"enabled\" =\u003e \"1\",\n            \"mysql\" =\u003e array(\"replication_delay\" =\u003e \"1\"),\n        ),\n        ...\n    );\n\nUsage for the `zkfarmer export` command:\n\n    usage: zkfarmer export [-h] [-f {json,yaml,php,dir}] [-c CMD] [-F FILTERS]\n                           zknode conf\n\n    Export and maintain a representation of the current farm' nodes' list with\n    configuration to a local configuration file.\n\n    positional arguments:\n      zknode                the ZooKeeper node path to the farm\n      conf                  path to the local configuration\n\n    optional arguments:\n      -h, --help            show this help message and exit\n      -f {json,yaml,php,dir}, --format {json,yaml,php,dir}\n                            set the configuration format\n      -c CMD, --changed-cmd CMD\n                            a command to be executed each time the configuration\n                            change\n      -F FILTERS, --filters FILTERS\n                            filter out nodes which doesn't match supplied\n                            predicates separeted by commas (ex:\n                            enabled=0,replication_delay\u003c10,!maintenance)\n\nOne-way Sync to Zookeeper\n-------------------------\n\n`zkfarmer export` will copy the configuration from zookeeper to the local filesystem while `zkfarmer join` will keep a znode in sync with a part of the local filesystem. In certain case, the bidirectional sync of `zkfarmer join` may be undesirable. In this case, you can use `zkfarmer import` which acts like `zkfarmer join` but does not react to remote changes. Only a local change will trigger a synchronisation to ZooKeeper. The most common use-case for this command is the use of `--common` flag.\n\nUsage for the `zkfarmer import` command:\n\n    usage: zkfarmer import [-h] [-f {json,yaml,php,dir}] [-c] zknode conf\n\n    Import the current host configuration to a farm.\n\n    positional arguments:\n      zknode                the ZooKeeper node path of the farm\n      conf                  Path to the node configuration\n\n    optional arguments:\n      -h, --help            show this help message and exit\n      -f {json,yaml,php,dir}, --format {json,yaml,php,dir}\n                            set the configuration format\n      -c, --common          use a common zookeeper node instead of a dedicated node\n\nManaging Farms\n--------------\n\nZkFarmer comes with some other commands to list, read and write farms content.\n\n### List farms and hosts\n\nThe `zkfarm ls` command let you list znodes in ZooKeeper. If the listed znode contains ZkFarmer maintained host information, it can also show some fields associated to each listed host:\n\nYou can list all the farms you stored in `/services`:\n\n    $ zkfarmer ls /services\n    db\n    cache\n    search\n    soft\n\nYou can explore the status of hosts in a farm:\n\n    $ zkfarmer ls /services/db --fields hostname,enabled\n    1.2.3.4          hostname=db-01.example.com, enabled=0\n    1.2.3.5          hostname=db-02.example.com, enabled=1\n    ...\n\nTo dump sub-fields, use dotted notation (ex: mysql.replication_delay).\n\n### Retrieve an host field\n\nThe `zkfarm get` can return the value of a given field for a host:\n\n    $ zkfarmer get /services/db/1.2.3.4 enabled\n    0\n\n### Edit an host field\n\nYou can also change the value of field for a given host from anywhere on your network like this:\n\n    $ zkfarmer set /services/db/1.2.3.4 enabled 1\n\nThe local configuration on the host will immediately get updated as well as all consumers currently exporting this farm.\n\n### Unset a field\n\nYou can remove a field from a given host like this:\n    \n    $ zkfarmer unset /services/db/1.2.3.4 enabled\n\n### Farm properties\n\nThe `zkfarmer set/unset` and `zkfarmer get` commands can be used to store and read properties of a farm. This can be useful for monitoring tools for instance. You could store the minimum number of working nodes required before to throw an alert. To do that, you need two properties, `min_nodes` and `running_filter` for instance:\n\n    $ zkfarmer set /services/db min_node 30\n    $ zkfarmer set /services/db running_filter enabled=1\n\nThen to check the health of a service, run the following nagios compatible script:\n\n    #!/bin/sh\n\n    farm=$1\n    min_node=$(zkfarmer get $farm min_node)\n    running_filter=$(zkfarmer get $farm running_filter)\n    if [ $(zkfarmer ls --filters $working_filters $farm | wc -l) -gt $min_node ]\n    then\n        echo \"OK\"\n    else\n        echo \"CRITICAL\"\n        exit 2\n    fi\n\nRun it as follow:\n\n    $ zkfarmer_check /services/db\n\n\nUsage for the `zkfarmer set` command:\n\n    usage: zkfarmer set [-h] zknode field value\n\n    Set the value of a field of a given node or farm.\n\n    positional arguments:\n      zknode      the ZooKeeper node path to the farm or node\n      field       the path of the field to set\n      value       the new value\n\n    optional arguments:\n      -h, --help  show this help message and exit\n\nUsage for the `zkfarmer unset` command:\n\n    usage: zkfarmer unset [-h] zknode field\n\n    Unset a field of a given node or farm.\n\n    positional arguments:\n      zknode      the ZooKeeper node path to the farm or node\n      field       the path of the field to unset\n\n    optional arguments:\n      -h, --help  show this help message and exit\n\nUsage for the `zkfarmer get` command:\n\n    usage: zkfarmer get [-h] [-f {json,yaml,php}] zknode [field]\n\n    Get node or farm information. If the optional \u003cfield\u003e is specified, return the\n    field's value. Otherwise, dump the whole configuration using the specified\n    format.\n\n    positional arguments:\n      zknode                the ZooKeeper node path to the farm or node\n      field                 the path of the field to return\n\n    optional arguments:\n      -h, --help            show this help message and exit\n      -f {json,yaml,php}, --format {json,yaml,php}\n                            set the configuration format (default is yaml)\n\nFarm Monitoring\n---------------\n\nFortunately, you don't have to write the above script by yourself, zkfarmer implements it own monitoring system thru the `check` command. Instead of `min_node` property, zkfarmer maintain a `size` property representing the maximum ever seen number of node in the cluster. You don't have to maintain this property by hand as zkfarmer will raise it each time a node is added to the farm. You may need to update it if you shrink your farm though.\n\nThe `zkfarmer check` command takes a maximum number of failed node as argument. This number could be an absolute number or a percentage of the farm. The default value is 10%. By default, all node which joined the farm will be counted as `running` nodes, but this is certainly not what you want. To inform zkfarmer how to detect running nodes, you may set the `running_filter` farm property with any number of predicates you need.\n\nHere is an example of usage:\n\n    $ zkfarmer get /services/db\n    size: 17\n    running_filter: 'enabled=1,running=1,mysql.replication_delay\u003c60'\n\n    $ zkfarmer check /services/db\n    OK: 16/17 nodes running, 1 nodes failing, max allowed 10%\n\nUsage for the `zkfarmer check` command:\n\n    usage: zkfarmer check [-h] [-c MAX_FAILED_NODE] [-w WARN_FAILED_NODE] zknode\n\n    Check a farm health regarding the number of failed node and return nagios\n    compatible output. Failed node are max farm node - currently healthy nodes.\n    Healthy nodes are by default all nodes currently in the farm. You may edit the\n    `running_filter' farm property to filter out nodes maching criteria to counter\n    as healthy node. The farm max node is stored in the `size' farm property and\n    is raised by the `join' command with the farm is extended.If you shrink the\n    farm, you may edit this property by hand.\n\n    positional arguments:\n      zknode                the ZooKeeper node path to the farm\n\n    optional arguments:\n      -h, --help            show this help message and exit\n      -c MAX_FAILED_NODE, --max-failed-node MAX_FAILED_NODE\n                            the max allowed number of failed nodes, can be a\n                            number or a percentage (default 10%)\n      -w WARN_FAILED_NODE, --warn-failed-node WARN_FAILED_NODE\n                            if defined, number of failed node at which a warning\n                            will be returned (must be lower than MAX_FAILED_NODE)\n\nFarm State Aware Command Execution\n----------------------------------\n\nNot implemented yet\n\nUsage for the `zkfarmer exec` command:\n\n    usage: zkfarmer exec [-h] [-l LOCK_NAME] [-c CONCURRENCY] [-s SET]\n                         [-a ALLOWED_HOUR_RANGES] [-r DELAY]\n                         zknode\n\n    This sub-command executes a local command in respect to various farm\n    conditions and block until all conditions aren't met (will block forever if\n    `--repeat' option is used). A lock can be acquired before to execute the\n    command and can require that no more than N other clients acquired the lock\n    before the local command is executed. A node property can be changed as soon\n    as the command is executed, and restored to its previous value as soon command\n    exit. The command can be prevented from being launched until the farm isn't\n    healthy (see the `check' sub-command). Black hours can be set to prevent the\n    command from being executed during peak hours. The command can be executed\n    repetidely with given minimum delay between executions with respect to all\n    other defined constraints.\n\n    positional arguments:\n      zknode                the ZooKeeper node path to the farm\n\n    optional arguments:\n      -h, --help            show this help message and exit\n      -l LOCK_NAME, --lock LOCK_NAME\n                            acquires a lock before to execute the command\n      -c CONCURRENCY, --concurrency CONCURRENCY\n                            allow N other concurrent clients to acquire the same\n                            lock (default 1)\n      -s SET, --set SET     set a node field just before execution and restore it\n                            once done (foramt field.path=value\n      -a ALLOWED_HOUR_RANGES, --allowed-hour-ranges ALLOWED_HOUR_RANGES\n                            Ranges of hours between when the command can be\n                            launched, outside of those range, this command will\n                            block until next allowed range.\n      -r DELAY, --repeat DELAY\n                            repeat the command with a minimum delay of DELAY in\n                            respect of other conditions (this option makes the\n                            command to block forever, you should use something\n                            like upstart to launch it\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frs%2Fzkfarmer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frs%2Fzkfarmer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frs%2Fzkfarmer/lists"}