{"id":21745161,"url":"https://github.com/zuazo/zookeeper_bridge-cookbook","last_synced_at":"2026-03-15T03:37:55.357Z","repository":{"id":19728261,"uuid":"22984346","full_name":"zuazo/zookeeper_bridge-cookbook","owner":"zuazo","description":"Chef cookbook to help integrating the Chef Run with ZooKeeper.","archived":false,"fork":false,"pushed_at":"2015-09-09T19:27:21.000Z","size":452,"stargazers_count":1,"open_issues_count":2,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-21T01:43:14.698Z","etag":null,"topics":["chef","cookbook","devops","handler","integration","zookeeper","zookeeper-bridge"],"latest_commit_sha":null,"homepage":"https://supermarket.chef.io/cookbooks/zookeeper_bridge","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zuazo.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-08-15T09:02:58.000Z","updated_at":"2015-09-11T12:19:15.000Z","dependencies_parsed_at":"2022-09-02T00:42:06.749Z","dependency_job_id":null,"html_url":"https://github.com/zuazo/zookeeper_bridge-cookbook","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/zuazo/zookeeper_bridge-cookbook","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zuazo%2Fzookeeper_bridge-cookbook","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zuazo%2Fzookeeper_bridge-cookbook/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zuazo%2Fzookeeper_bridge-cookbook/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zuazo%2Fzookeeper_bridge-cookbook/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zuazo","download_url":"https://codeload.github.com/zuazo/zookeeper_bridge-cookbook/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zuazo%2Fzookeeper_bridge-cookbook/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261396244,"owners_count":23152442,"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":["chef","cookbook","devops","handler","integration","zookeeper","zookeeper-bridge"],"created_at":"2024-11-26T07:13:47.615Z","updated_at":"2025-10-30T05:17:15.517Z","avatar_url":"https://github.com/zuazo.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"ZooKeeper Bridge Cookbook\n=========================\n[![Cookbook Version](https://img.shields.io/cookbook/v/zookeeper_bridge.svg?style=flat)](https://supermarket.chef.io/cookbooks/zookeeper_bridge)\n[![GitHub Source](https://img.shields.io/badge/source-GitHub-blue.svg?style=flat)](https://github.com/zuazo/zookeeper_bridge-cookbook)\n[![Dependency Status](http://img.shields.io/gemnasium/zuazo/zookeeper_bridge-cookbook.svg?style=flat)](https://gemnasium.com/zuazo/zookeeper_bridge-cookbook)\n[![Code Climate](http://img.shields.io/codeclimate/github/zuazo/zookeeper_bridge-cookbook.svg?style=flat)](https://codeclimate.com/github/zuazo/zookeeper_bridge-cookbook)\n[![Build Status](http://img.shields.io/travis/zuazo/zookeeper_bridge-cookbook.svg?style=flat)](https://travis-ci.org/zuazo/zookeeper_bridge-cookbook)\n\n[Chef](https://www.chef.io/) `zookeeper_bridge` cookbook, used to help integrating the *Chef Run* with ZooKeeper.\n\nIt can help in the following:\n\n* Installing and running [Chef ZooKeeper Handler](http://onddo.github.io/chef-handler-zookeeper/).\n* Reading or writing Chef Node attributes to and from ZooKeeper.\n* Running ZooKeeper Client commands.\n* Interacting with ZooKeeper read/write locks during the *Chef Run*.\n* Interacting with ZooKeeper semaphores during the *Chef Run*.\n* Wait until a ZooKeeper znode has the desired state or a certain event happens.\n\nSome of the resources included in this cookbook have not been widely tested, so you should consider this cookbook as something **experimental**.\n\nThis cookbook is mainly used by calling the resources it provides. See their documentation below. The `zookeeper_bridge::default` recipe needs to be included before their use.\n\nRequirements\n============\n\n## Supported Platforms\n\nThis cookbook has been tested on the following platforms:\n\n* Amazon\n* CentOS\n* Debian\n* Ubuntu\n\nPlease, [let us know](https://github.com/zuazo/zookeeper_bridge-cookbook/issues/new?title=I%20have%20used%20it%20successfully%20on%20...) if you use it successfully on any other platform.\n\n## Required Cookbooks\n\n* [build-essential](https://supermarket.chef.io/cookbooks/build-essential) `~\u003e 2.0`\n* [chef_handler](https://supermarket.chef.io/cookbooks/chef_handler)\n\n## Required Applications\n\n* Ruby `1.9.3` or higher.\n* `zk` ruby gem.\n\nAttributes\n==========\n\n| Attribute                                             | Default                       | Description                       |\n|:------------------------------------------------------|:------------------------------|:----------------------------------|\n| `node['zookeeper_bridge']['server']`                  | `'127.0.0.1:2181'`            | ZooKeeper server address.\n| `node['zookeeper_bridge']['chef_handler']['version']` | `nil` *(latest)*              | `chef-handler-zookeeper` gem version to install.\n| `node['zookeeper_bridge']['chef_handler']['znode']`   | `\"/chef/#{node.name}/status\"` | `chef-handler-zookeeper` znode path. The path must be absolute.\n\nRecipes\n=======\n\n## zookeeper_bridge::default\n\nRecipe required before using the resources.\n\n## zookeeper_bridge::chef_handler\n\nInstalls and enables [`chef-handler-zookeeper`](http://onddo.github.io/chef-handler-zookeeper/) gem.\n\n### zookeeper_bridge::chef_handler Example\n\nThe `node['zookeeper_bridge']['chef_handler']['znode']` path must exist before calling this recipe:\n\n    $ ./zkCli.sh\n    [zk: localhost:2181(CONNECTED) 0] create /chef {}\n    [zk: localhost:2181(CONNECTED) 1] create /chef/server1.example.com {}\n    [zk: localhost:2181(CONNECTED) 2] create /chef/server1.example.com/status {}\n\nOr using the recipe itself:\n\n```ruby\n# We set the ZooKeeper server address\nnode.default['zookeeper_bridge']['server'] = 'zk.example.com'\n\n# zookeeper_bridge_cli resource should ignore cli errors if they already exist\nzookeeper_bridge_cli 'create /chef {}'\nzookeeper_bridge_cli \"create /chef/#{node.name} {}\"\nzookeeper_bridge_cli \"create /chef/#{node.name}/status {}\"\n```\n\nThis is because the [`chef-handler-zookeeper` requires that the znode exists](http://onddo.github.io/chef-handler-zookeeper/#handler-configuration-options).\n\nNow we can install and enable the handler:\n\n```ruby\nnode.default['zookeeper_bridge']['chef_handler']['znode'] = \"/chef/#{node.name}/status\"\ninclude_recipe 'zookeeper_bridge::chef_handler'\n```\n\n## zookeeper_bridge::depends\n\nInstall some dependencies required by this cookbook. Used by the other recipes.\n\nResources\n=========\n\n## zookeeper_bridge_rdlock[path]\n\nRuns a [Read or Shared Lock](http://en.wikipedia.org/wiki/Readers%E2%80%93writer_lock) inside ZooKeeper. This resource is intended to be used together with the `zookeeper_bridge_wrlock` resource.\n\n### zookeeper_bridge_rdlock Actions\n\n* `run`\n\n### zookeeper_bridge_rdlock Parameters\n\n| Parameter | Default                              | Description                       |\n|:----------|:-------------------------------------|:----------------------------------|\n| path      | *name*                               | Znode path. The path can be relative to `'/_zklocking'`.\n| server    | `node['zookeeper_bridge']['server']` | ZooKeeper server address.\n| wait      | `true`                               | This can be an integer to wait a maximum of seconds and raise a timeout exception if this time is exceeded. By default is set to `true`, which will wait infinitely.\n| block     | `nil`                                | The *recipe code* that will be run within the lock.\n\n### zookeeper_bridge_rdlock Examples\n\n```ruby\nzookeeper_bridge_rdlock 'lock1' do\n  server 'zk.example.com'\n  block do\n    # recipe code can be used here\n    execute '...'\n  end\nend\n```\n\nThen we can use an exclusive lock from another node:\n\n```ruby\nzookeeper_bridge_wrlock 'lock1' do\n  server 'zk.example.com'\n  block do\n    # recipe code can be used here\n    execute '...'\n  end\nend\n```\n\n## zookeeper_bridge_wrlock[path]\n\nRuns a [Write or Exclusive Lock](http://en.wikipedia.org/wiki/Readers%E2%80%93writer_lock) inside ZooKeeper. This resource is intended to be used together with the `zookeeper_bridge_rdlock` resource.\n\n### zookeeper_bridge_wrlock Actions\n\n* `run`\n\n### zookeeper_bridge_wrlock Parameters\n\n| Parameter | Default                              | Description                       |\n|:----------|:-------------------------------------|:----------------------------------|\n| path      | *name*                               | Znode path. The path can be relative to `'/_zklocking'`.\n| server    | `node['zookeeper_bridge']['server']` | ZooKeeper server address.\n| wait      | `true`                               | This can be an integer to wait a maximum of seconds and raise a timeout exception if this time is exceeded. By default is set to `true`, which will wait infinitely.\n| block     | `nil`                                | The *recipe code* that will be run within the lock.\n\n### zookeeper_bridge_wrlock Examples\n\nThe following block will only be running by a maximum of one node at a particular instant:\n\n```ruby\nzookeeper_bridge_wrlock 'lock1' do\n  server 'zk.example.com'\n  block do\n    # recipe code can be used here\n    execute '...'\n  end\nend\n```\n\n## zookeeper_bridge_sem[path]\n\nRuns a [Semaphore](http://en.wikipedia.org/wiki/Semaphore_%28programming%29) inside ZooKeeper.\n\n### zookeeper_bridge_sem Actions\n\n* `run`\n\n### zookeeper_bridge_sem Parameters\n\n| Parameter | Default                              | Description                       |\n|:----------|:-------------------------------------|:----------------------------------|\n| path      | *name*                               | Znode path. The path can be relative to `'/_zksemaphore'`.\n| server    | `node['zookeeper_bridge']['server']` | ZooKeeper server address.\n| size      | `nil`                                | Semaphore size: the maximum number of nodes that will be able to run the block at the same time.\n| block     | `nil`                                | The *recipe code* that will be run within the semaphore.\n| wait      | `true`                               | This can be an integer to wait a maximum of seconds and raise a timeout exception if this time is exceeded. By default is set to `true`, which will wait infinitely.\n\n### zookeeper_bridge_sem Examples\n\nYou can call this from multiple nodes. The code within the following block will be running by a maximum of three nodes at the same time:\n\n```ruby\nzookeeper_bridge_sem 'sem1' do\n  server 'zk.example.com'\n  size 3\n  block do\n    # recipe code can be used here\n    execute '...'\n  end\nend\n```\n\n## zookeeper_bridge_attrs[path]\n\nUsed to read or write Chef Node attributes from or to ZooKeeper znode paths. The attributes are saved into the znode using *JSON* format.\n\n### zookeeper_bridge_attrs Actions\n\n* `read`: Read Node attributes from a znode.\n* `write`: Write Node attributes to a znode.\n\n### zookeeper_bridge_attrs Parameters\n\n| Parameter      | Default                              | Description                       |\n|:---------------|:-------------------------------------|:----------------------------------|\n| path           | *name*                               | Znode path. The path must be absolute.\n| server         | `node['zookeeper_bridge']['server']` | ZooKeeper server address.\n| attribute      | `nil`                                | Node attribute object or a Ruby Hash. This should be something like `node['foo']` for **reading** and `node.normal['foo']` for **writing**.\n| merge          | *calculated*                         | Whether to merge hashes. This is `true` by default for `:read` action, which will merge the current node attributes with the attributes read from ZooKeeper. For `:write` is `false` by default, which will not merge the current attributes saved in ZooKeeper with the node attributes to write, the data in ZooKeeper will be completely overwritten.\n| force_encoding | `nil` | Force character encoding. For example: `'UTF-8'`.\n\n### zookeeper_bridge_attrs Examples\n\n#### Reading All Node Attributes\n\nThe znode to read attributes from must exist before reading it. For writing, at least the parent znode must exist:\n\n    $ ./zkCli.sh\n    [zk: localhost:2181(CONNECTED) 0] create /chef {}\n    [zk: localhost:2181(CONNECTED) 1] create /chef/server1.example.com {}\n    [zk: localhost:2181(CONNECTED) 2] create /chef/server1.example.com/read_attributes {\"attr1\":\"value1\"}\n\nWe can also create them from a recipe using `zookeeper_bridge_cli`:\n\n```ruby\n# We set the ZooKeeper server address\nnode.default['zookeeper_bridge']['server'] = 'zk.example.com'\n\n# zookeeper_bridge_cli resource should ignore cli errors if they already exist\nzookeeper_bridge_cli('create /chef {}').run_action(:run)\nzookeeper_bridge_cli(\"create /chef/#{node.name} {}\").run_action(:run)\n# zkCli.sh does not support spaces in the data:\nzookeeper_bridge_cli(\"create /chef/#{node.name}/read_attributes {\\\"attr1\\\":\\\"value1\\\"}\")\n  .run_action(:run)\n```\n\nNow we can read and write all node attributes from and to ZooKeeper:\n\n```ruby\nzookeeper_bridge_attrs \"/chef/#{node.name}/read_attributes\" do\n  attribute node.normal\n  action :nothing\nend.run_action(:read)\n\n# [...]\n\nzookeeper_bridge_attrs \"/chef/#{node.name}/write_attributes\" do\n  attribute node.attributes\n  action :write\nend\n```\n\n**Note:** You need to understand how [compile and converge phases work on Chef Run](http://docs.chef.io/essentials_nodes_chef_run.html) to know when to use `#run_action`.\n\n### Reading and Writing Apache Cookbook Attributes\n\nAs in the previous example, we create the necessary znodes:\n\n    $ ./zkCli.sh\n    [zk: localhost:2181(CONNECTED) 0] create /chef {}\n    [zk: localhost:2181(CONNECTED) 1] create /chef/server1.example.com {}\n    [zk: localhost:2181(CONNECTED) 2] create /chef/server1.example.com/apache_attributes {}\n\nWe can also create them from a recipe using `zookeeper_bridge_cli`:\n\n```ruby\n# We set the ZooKeeper server address\nnode.default['zookeeper_bridge']['server'] = 'zk.example.com'\n\n# zookeeper_bridge_cli resource should ignore cli errors if they already exist\nzookeeper_bridge_cli 'create /chef {}'\nzookeeper_bridge_cli \"create /chef/#{node.name} {}\"\nzookeeper_bridge_cli \"create /chef/#{node.name}/apache_attributes {}\"\n```\n\nNow we can read and write apache attributes:\n\n```ruby\n# We use override in this case to overwrite default and normal values, why not?\nzookeeper_bridge_attrs \"/chef/#{node.name}/apache_attributes\" do\n  attribute node.override['apache']\n  action :nothing\nend.run_action(:read)\n\n# [...]\n\nzookeeper_bridge_attrs \"/chef/#{node.name}/apache_attributes\" do\n  attribute node['apache']\n  action :write\nend\n```\n\n## zookeeper_bridge_wait[path]\n\nWaits until a given ZooKeeper znode path exists, does not exist or changes its state.\n\n### zookeeper_bridge_wait Actions\n\n* `run`\n\n### zookeeper_bridge_wait Parameters\n\n| Parameter | Default                              | Description                       |\n|:----------|:-------------------------------------|:----------------------------------|\n| path      | *name*                               | Znode path. The path must be absolute.\n| server    | `node['zookeeper_bridge']['server']` | ZooKeeper server address.\n| status    | `:any`                               | Wait until znode has this status. Possible values: `:any`, `:created` or `:deleted.`. `:any` means to ignore the status, normally used when the `event` parameter below is set.\n| event     | `:none`                              | Wait until specific znode event occurs. Possible values: `:none`, `:created`, `:deleted.`, `:changed`, `:child` or an array of multiple values. `:none` means to ignore the events, normally used when the `status` parameter is set. `:child` is for znode child events.\n\n### zookeeper_bridge_wait Examples\n\nWait until host znode is created (at compile time, to avoid compiling the next resources):\n\n```ruby\nzookeeper_bridge_wait \"/chef/#{node.name}\" do\n  status :created\n  event :none\n  action :nothing\nend.run_action(:run)\n```\n\nWait until the attributes exists before reading them:\n\n```ruby\nzookeeper_bridge_wait \"/chef/#{node.name}/attributes\" do\n  status :created\n  event :none\n  action :nothing\nend.run_action(:run)\n\nzookeeper_bridge_attrs \"/chef/#{node.name}/attributes\" do\n  attribute node.normal\n  action :nothing\nend.run_action(:read)\n```\n\nContinue the *Chef Run convergence* only when the *stop znode* does not exist:\n\n```ruby\nzookeeper_bridge_wait \"/chef/#{node.name}/chef_stop\" do\n  status :deleted\n  event :none\nend\n```\n\nContinue the *Chef Run convergence* only when the *continue znode* is updated:\n\n```ruby\nzookeeper_bridge_wait \"/chef/#{node.name}/chef_continue\" do\n  status :any\n  event :changed\nend\n```\n\n## zookeeper_bridge_cli[path]\n\nRuns a ZooKeeper command using the `zkCli.sh` script. This resource should be run from the ZooKeeper server node, because `zkCli.sh` connects to *localhost* (connecting to remote server is not supported yet).\n\nRemember that this script has some limitations, so use it with caution.\n\n### zookeeper_bridge_cli Actions\n\n* `run`: Runs a command.\n\n### zookeeper_bridge_cli Parameters\n\n| Parameter  | Default                              | Description                       |\n|:-----------|:-------------------------------------|:----------------------------------|\n| command    | *name*                               | ZooKeeper `zkCli.sh` command.\n| base_path  | *calculated*                         | ZooKeeper installation path.\n| sleep      | `nil`                                | Time to sleep in seconds before the command is run (type `Float`).\n| background | `false`                              | Whether to run the command in background.\n\n### zookeeper_bridge_cli Examples\n\n```ruby\nzookeeper_bridge_cli 'create /test some_random_data'\n```\n\nThis resource is currently used in the integration tests. See the [zookeeper_bridge_test](https://github.com/zuazo/zookeeper_bridge-cookbook/blob/master/test/cookbooks/zookeeper_bridge_test) cookbook recipes for more usage examples.\n\nTesting\n=======\n\nSee [TESTING.md](https://github.com/zuazo/zookeeper_bridge-cookbook/blob/master/TESTING.md).\n\n## ChefSpec Matchers\n\n### zookeeper_bridge_attrs(path)\n\nHelper method for locating a `zookeeper_bridge_attrs` resource in the collection.\n\n```ruby\nresource = chef_run.zookeeper_bridge_attrs(\"/chef/#{node['fqdn']}/attributes\")\nexpect(resource).to notify('service[apache2]').to(:reload)\n```\n\n### read_zookeeper_bridge_attrs(path)\n\nAssert that the *Chef Run* reads `zookeeper_bridge_attrs` at compile time.\n\n```ruby\nexpect(chef_run).to read_zookeeper_bridge_attrs(\"/chef/#{node['fqdn']}/attributes\").at_compile_time\n```\n\n### write_zookeeper_bridge_attrs(path)\n\nAssert that the *Chef Run* writes `zookeeper_bridge_attrs`.\n\n```ruby\nexpect(chef_run).to write_zookeeper_bridge_attrs(\"/chef/#{node['fqdn']}/attributes\")\n```\n\n### zookeeper_bridge_cli(command)\n\nHelper method for locating a `zookeeper_bridge_cli` resource in the collection.\n\n```ruby\nresource = chef_run.zookeeper_bridge_cli('ls /chef')\nexpect(resource).to notify('service[apache2]').to(:reload)\n```\n\n### run_zookeeper_bridge_cli(command)\n\nAssert that the *Chef Run* runs `zookeeper_bridge_cli`.\n\n```ruby\nexpect(chef_run).to run_zookeeper_bridge_cli('create /test some_random_data')\n```\n\n### zookeeper_bridge_rdlock(path)\n\nHelper method for locating a `zookeeper_bridge_rdlock` resource in the collection.\n\n```ruby\nresource = chef_run.zookeeper_bridge_rdlock('my_lock')\nexpect(resource).to notify('service[apache2]').to(:reload)\n```\n\n### run_zookeeper_bridge_rdlock(path)\n\nAssert that the *Chef Run* runs `zookeeper_bridge_rdlock`.\n\n```ruby\nexpect(chef_run).to run_zookeeper_bridge_rdlock('my_lock')\n```\n\n### zookeeper_bridge_sem(path)\n\nHelper method for locating a `zookeeper_bridge_sem` resource in the collection.\n\n```ruby\nresource = chef_run.zookeeper_bridge_sem('my_semaphore')\nexpect(resource).to notify('service[apache2]').to(:reload)\n```\n\n### run_zookeeper_bridge_sem(path)\n\nAssert that the Chef Run runs `zookeeper_bridge_sem`.\n\n```ruby\nexpect(chef_run).to run_zookeeper_bridge_sem('my_semaphore')\n  .with_size(1)\n```\n\n### zookeeper_bridge_wait(path)\n\nHelper method for locating a `zookeeper_bridge_wait` resource in the collection.\n\n```ruby\nresource = chef_run.zookeeper_bridge_wait(\"/chef/#{node['fqdn']}/attributes\")\nexpect(resource).to notify('service[apache2]').to(:reload)\n```\n\n### run_zookeeper_bridge_wait(path)\n\nAssert that the Chef Run runs `zookeeper_bridge_wait`.\n\n```ruby\n# ensure waits until the attributes file exists\nexpect(chef_run).to run_zookeeper_bridge_wait(\"/chef/#{node['fqdn']}/attributes\")\n  .with_status(:created)\n  .with_event(:none)\n```\n\n### zookeeper_bridge_wrlock(path)\n\nHelper method for locating a `zookeeper_bridge_wrlock` resource in the collection.\n\n```ruby\nresource = chef_run.zookeeper_bridge_wrlock('my_lock')\nexpect(resource).to notify('service[apache2]').to(:reload)\n```\n\n### run_zookeeper_bridge_wrlock(path)\n\nAssert that the Chef Run runs `zookeeper_bridge_wrlock`.\n\n```ruby\nexpect(chef_run).to run_zookeeper_bridge_wrlock('my_lock')\n```\n\nContributing\n============\n\nPlease do not hesitate to [open an issue](https://github.com/zuazo/zookeeper_bridge-cookbook/issues/new) with any questions or problems.\n\nSee [CONTRIBUTING.md](https://github.com/zuazo/zookeeper_bridge-cookbook/blob/master/CONTRIBUTING.md).\n\nTODO\n====\n\nSee [TODO.md](https://github.com/zuazo/zookeeper_bridge-cookbook/blob/master/TODO.md).\n\n\nLicense and Author\n==================\n\n|                      |                                          |\n|:---------------------|:-----------------------------------------|\n| **Author:**          | [Xabier de Zuazo](https://github.com/zuazo) (\u003cxabier@zuazo.org\u003e)\n| **Copyright:**       | Copyright (c) 2015, Xabier de Zuazo\n| **Copyright:**       | Copyright (c) 2013-2014, Onddo Labs, SL.\n| **License:**         | Apache License, Version 2.0\n\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n        http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzuazo%2Fzookeeper_bridge-cookbook","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzuazo%2Fzookeeper_bridge-cookbook","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzuazo%2Fzookeeper_bridge-cookbook/lists"}