Batali
Batali is a light weight cookbook resolver. It is now in a beta state, moving quickly towards a proper stable release.
What is Batali?
Batali is a cookbook resolver. It's built to be light weight but feature rich. Batali helps to manage your cookbooks and stay out of your way.
Usage
Provide a Batali
file:
Batali.define do
source 'https://supermarket.chef.io'
cookbook 'postgresql'
end
and then run:
$ batali update
in the same directory. It will destroy your cookbooks
directory
by default.
IT WILL DESTROY YOUR COOKBOOKS DIRECTORY BY DEFAULT
You can make it not destroy your cookbooks directory by providing a different path. A better idea is to not use the cookbooks directory. Just ignore that sucker and let Batali do its thing.
Commands
batali resolve
- Resolve dependencies and producebatali.manifest
batali install
- Install entries from thebatali.manifest
batali update
- Performresolve
and theninstall
Features
Origins
Currently supported "origins":
- RemoteSite
- Path
- Git
RemoteSite
This is simply a supermarket endpoint:
source 'https://supermarket.chef.io'
Multiple endpoints can be provided by specifying multiple
source
lines. They can also be named:
source 'https://supermarket.chef.io', :name => 'opscode'
source 'https://cookbooks.example.com', :name => 'example'
Path
Paths are defined via cookbook entries:
cookbook 'example', path: '/path/to/example'
Git
Git sources are defined via cookbook entries:
cookbook 'example', git: 'git://git.example.com/example-repo.git', ref: 'master'
Least Impact Updates
After a batali.manifest
file has been generated, subsequent resolve
requests
will update cookbook versions using a "least impact" approach. This means that
by default if the Batali
file has not changed, running a batali resolve
will
be a noop, even if new versions of cookbooks may be available. This helps to reduce
unintended upgrades that may break things due to a required cookbook update. Allowing
a cookbook to be updated is done simply by adding it to the request:
$ batali resolve example
This will only update the version of the example cookbook, and any dependency cookbooks that must be updated to provide resolution. Dependency cookbooks that require an upgrade based on constraints will attempt to upgrade with the least impact possible by attempting to satisfy constraints within the minimum version segement possible. For example, if our Batali file contains the following:
Batali.define do
source 'https://example.com'
cookbook 'soup'
end
and after resolving we have two cookbooks in our manifest:
soup <1.0.0>
salad <0.1.4>
Some time passes and a new version of soup
is released, version 1.0.2. In that time
multiple new versions of the salad
cookbook have been released, with new features and
with some breaking changes. For this example, lets assume available versions of the salad
cookbook are:
<0.1.4>
<0.1.6>
<0.1.8>
<0.2.0>
<0.2.2>
<0.3.0>
<1.0.0>
and the soup
cookbook has updated its salad
dependency:
# soup metadata.rb
depends 'salad', '> 0.2'
Due to the behavior of existing solvers, we may expect the resolved manifest to include
salad
at the latest possible version: 1.0.0
. This is a valid solution, since the
dependency is simply stating the constraint requires salad
be greater than 0.2
and
nothing more. However, this is a very large jump from what we currently have defined
within our manifest, and jumps a major and minor version. The possibility of breaking
changes being introduced is extremely high.
Since Batali has the least impact feature enabled by default, it will only upgrade
salad
to the 0.2.2
version. This is due to the fact that the least impact feature
prefers the latest cookbook available within the closest version segement of the cookbook
version currently defined within the manifest. Since thew new soup
dependency contraint
requires versions > 0.2
, no > 0.1
versions are acceptable. Batali then looks to the
next available segment 0.2
and attempts to use the latest version: 0.2.2
. This solves the
constraint, and is used for the new solution.
Multiple cookbooks can be listed for upgrade:
$ batali resolve example ipsum lorem
or this feature can be disabled to allow everything to be updated to the latest possible versions:
$ batali resolve --no-least-impact
Light weight
One of the goals for batali was being light weight resolver, in the same vein as the librarian project. This means it does nothing more than manage local cookbooks. This includes dependency and constraint resolution, as well as providing a local installation of assets defined within the generated manifest. It provides no extra features outside of that scope.
Multiple platform support
Batali does not rely on the chef gem to function. This removes any dependencies on gems that may be incompatible outside the MRI platform.
Isolated manifest files
Manifest files are fully isolated. The resolver does not need to perform any actions for installing cookbooks defined within the manifest. This allows for easy transmission and direct installation of a manifest without the requirement of re-pulling information from sources.
Infrastructure manifests
Batali aims to solve the issue of full infrastructure resolution: resolving dependencies
from an infrastructure repository. Resolving a single dependency path will not provide
a correct resolution. This is because environments or run lists can provide extra constraints
that will result in unsolvable resolutions on individual nodes. In this case we want
to know what cookbooks are allowed within a solution, and ensure all those cookbooks
are available. Batali provides infrastructure level manifests by setting the infrastructure
flag:
$ batali resolve --infrastructure
NOTE: Depending on constraints defined within the Batali file, this can be a very large manifest
Test Kitchen
Batali can be used with Test Kitchen:
Info
- Repository: https://github.com/hw-labs/batali