Last active
September 5, 2015 21:31
-
-
Save vinyar/8e14c9ab738bcd4bae17 to your computer and use it in GitHub Desktop.
cookbook reverse dependency lookup
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Its a cookbook class that we use to abstract cookbooks and their | |
dependencies. The key method to look at is dependency_hash which creates | |
a hash based on the dependencies of the cookbook. | |
We do not explicitly do a reverse dependency lookup but we can use this | |
hash to infer a change in dependencies from a change in any cookbook in | |
an environment. So the flow is: | |
1. I change cookbook A and it gets sent to the chef server and indexed | |
in berks. | |
2. We do a berks update on the environment cookbook. | |
3. We invoke the kitchen builds for each cookbook in the environment | |
4. Each of these cookbooks checks to see if their dependency hash as | |
calculated by all the current berks changes from #2 above is now | |
different from the one we store in our LKG_{environment name} | |
environment that stores the hash of the cookbook as it was ehwn it last | |
passed its kitchen test. | |
Hope this makes sense. | |
require 'berkshelf' | |
require 'digest/sha1' | |
require 'json' | |
module Promote | |
class Cookbook | |
def initialize(cookbook_name, config) | |
@name = cookbook_name | |
@config = config | |
@metadata_path = File.join(path, 'metadata.rb') | |
@berks_path = File.join(path, "Berksfile") | |
end | |
def dependencies | |
@dependencies ||= get_synced_dependencies_from_lockfile | |
end | |
def metadata_dependencies | |
metadata.dependencies | |
end | |
def version(version=nil) | |
metadata.version | |
end | |
def version=(version) | |
version_line = raw_metadata[/^\s*version\s.*$/] | |
current_version = version_line[/('|").*("|')/].gsub(/('|")/,"") | |
if current_version != version.to_s | |
new_version_line = version_line.gsub(current_version, version.to_s) | |
new_content = raw_metadata.gsub(version_line, new_version_line) | |
save_metadata(new_content) | |
end | |
version | |
end | |
def stamp_commit(commit) | |
commit_line = "#sha1 '#{commit}'" | |
new_content = raw_metadata.gsub(/#sha1.*$/, commit_line) | |
if new_content[/#sha1.*$/].nil? | |
new_content += "\n#{commit_line}" | |
end | |
save_metadata(new_content) | |
end | |
def raw_metadata | |
@raw_metadata ||= File.read(@metadata_path) | |
end | |
def metadata | |
@metadata ||=get_metadata_from_file | |
end | |
def path | |
File.join(@config.cookbook_directory, @name) | |
end | |
def sync_berksfile(update=false) | |
return if berksfile.nil? | |
update = false unless File.exist?("#{@berks_path}.lock") | |
update ? berksfile_update : berksfile.install | |
end | |
def dependencies_changed_after_update? | |
old_deps = dependencies | |
sync_berksfile(true) | |
new_deps = get_dependencies_from_lockfile | |
return true unless old_deps.count == new_deps.count | |
old_deps.each do |k,v| | |
if k != @name | |
return true unless new_deps[k] == v | |
end | |
end | |
return false | |
end | |
def dependency_hash(environment_cookbook_name) | |
sync_latest_app_cookbooks(environment_cookbook_name) | |
hash_src = '' | |
dependencies.each do | k,v | | |
hash_src << "#{k}::#{v}::" | |
end | |
Digest::SHA1.hexdigest(hash_src) | |
end | |
def sync_latest_app_cookbooks(environment_cookbook_name) | |
result = {} | |
latest_server_cookbooks = Utils.chef_server_cookbooks(@config, 1) | |
env_cookbook = Cookbook.new(environment_cookbook_name, @config) | |
env_cookbook.metadata_dependencies.each do |key| | |
cb_key = key[0] | |
next if cb_key == @name || !latest_server_cookbooks.has_key?(cb_key) | |
latest_version = latest_server_cookbooks[cb_key]['versions'][0]['version'] | |
if dependencies.keys.include?(cb_key) && latest_version > dependencies[cb_key].to_s | |
berksfile_update(cb_key) | |
result[cb_key] = latest_version | |
end | |
end | |
result | |
end | |
private | |
def berksfile | |
@berksfile ||= get_berksfile | |
end | |
def save_metadata(content) | |
File.open(@metadata_path, 'w') do |out| | |
out << content | |
end | |
@metadata=nil | |
@raw_metadata = nil | |
end | |
def get_metadata_from_file | |
metadata = Chef::Cookbook::Metadata.new | |
metadata.from_file(@metadata_path) | |
metadata | |
end | |
def get_synced_dependencies_from_lockfile | |
berksfile.install | |
get_dependencies_from_lockfile | |
end | |
def get_dependencies_from_lockfile | |
berks_deps = berksfile.list | |
deps = {} | |
berks_deps.each {|dep| deps[dep.name] = dep.locked_version} | |
deps | |
end | |
def get_berksfile | |
return unless File.exist?(@berks_path) | |
Berkshelf.set_format :null | |
Berkshelf::Berksfile.from_file(@berks_path) | |
end | |
def berksfile_update(cookbooks = nil) | |
cookbooks.nil? ? berksfile.update : berksfile.update(cookbooks) | |
@dependencies = nil | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment