berkshelf-api 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.ruby-version +1 -0
- data/.travis.yml +17 -0
- data/CONTRIBUTING.md +33 -0
- data/Gemfile +40 -0
- data/Guardfile +20 -0
- data/LICENSE +201 -0
- data/README.md +37 -0
- data/Thorfile +39 -0
- data/berkshelf-api.gemspec +35 -0
- data/bin/berks-api +5 -0
- data/lib/berkshelf-api.rb +1 -0
- data/lib/berkshelf/api.rb +25 -0
- data/lib/berkshelf/api/application.rb +114 -0
- data/lib/berkshelf/api/cache_builder.rb +60 -0
- data/lib/berkshelf/api/cache_builder/worker.rb +116 -0
- data/lib/berkshelf/api/cache_builder/worker/chef_server.rb +46 -0
- data/lib/berkshelf/api/cache_builder/worker/opscode.rb +59 -0
- data/lib/berkshelf/api/cache_manager.rb +96 -0
- data/lib/berkshelf/api/config.rb +23 -0
- data/lib/berkshelf/api/cucumber.rb +11 -0
- data/lib/berkshelf/api/dependency_cache.rb +123 -0
- data/lib/berkshelf/api/endpoint.rb +17 -0
- data/lib/berkshelf/api/endpoint/v1.rb +19 -0
- data/lib/berkshelf/api/errors.rb +8 -0
- data/lib/berkshelf/api/generic_server.rb +50 -0
- data/lib/berkshelf/api/logging.rb +37 -0
- data/lib/berkshelf/api/mixin.rb +7 -0
- data/lib/berkshelf/api/mixin/services.rb +48 -0
- data/lib/berkshelf/api/rack_app.rb +5 -0
- data/lib/berkshelf/api/remote_cookbook.rb +3 -0
- data/lib/berkshelf/api/rest_gateway.rb +62 -0
- data/lib/berkshelf/api/rspec.rb +20 -0
- data/lib/berkshelf/api/rspec/server.rb +29 -0
- data/lib/berkshelf/api/site_connector.rb +7 -0
- data/lib/berkshelf/api/site_connector/opscode.rb +162 -0
- data/lib/berkshelf/api/srv_ctl.rb +63 -0
- data/lib/berkshelf/api/version.rb +5 -0
- data/spec/fixtures/reset.pem +27 -0
- data/spec/spec_helper.rb +53 -0
- data/spec/support/actor_mocking.rb +7 -0
- data/spec/support/chef_server.rb +73 -0
- data/spec/unit/berkshelf/api/application_spec.rb +24 -0
- data/spec/unit/berkshelf/api/cache_builder/worker/chef_server_spec.rb +59 -0
- data/spec/unit/berkshelf/api/cache_builder/worker/opscode_spec.rb +41 -0
- data/spec/unit/berkshelf/api/cache_builder/worker_spec.rb +80 -0
- data/spec/unit/berkshelf/api/cache_builder_spec.rb +37 -0
- data/spec/unit/berkshelf/api/cache_manager_spec.rb +123 -0
- data/spec/unit/berkshelf/api/config_spec.rb +24 -0
- data/spec/unit/berkshelf/api/dependency_cache_spec.rb +109 -0
- data/spec/unit/berkshelf/api/endpoint/v1_spec.rb +18 -0
- data/spec/unit/berkshelf/api/logging_spec.rb +28 -0
- data/spec/unit/berkshelf/api/mixin/services_spec.rb +68 -0
- data/spec/unit/berkshelf/api/rack_app_spec.rb +6 -0
- data/spec/unit/berkshelf/api/rest_gateway_spec.rb +26 -0
- data/spec/unit/berkshelf/api/site_connector/opscode_spec.rb +85 -0
- data/spec/unit/berkshelf/api/srv_ctl_spec.rb +56 -0
- metadata +293 -0
data/bin/berks-api
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'berkshelf/api'
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'celluloid'
|
2
|
+
require 'hashie'
|
3
|
+
require 'ridley'
|
4
|
+
require 'faraday'
|
5
|
+
require 'json'
|
6
|
+
|
7
|
+
module Berkshelf
|
8
|
+
module API
|
9
|
+
require_relative 'api/errors'
|
10
|
+
require_relative 'api/logging'
|
11
|
+
require_relative 'api/mixin'
|
12
|
+
require_relative 'api/generic_server'
|
13
|
+
|
14
|
+
require_relative 'api/application'
|
15
|
+
require_relative 'api/cache_builder'
|
16
|
+
require_relative 'api/cache_manager'
|
17
|
+
require_relative 'api/config'
|
18
|
+
require_relative 'api/dependency_cache'
|
19
|
+
require_relative 'api/endpoint'
|
20
|
+
require_relative 'api/rack_app'
|
21
|
+
require_relative 'api/remote_cookbook'
|
22
|
+
require_relative 'api/site_connector'
|
23
|
+
require_relative 'api/srv_ctl'
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
trap 'INT' do
|
2
|
+
Berkshelf::API::Application.shutdown
|
3
|
+
end
|
4
|
+
|
5
|
+
trap 'TERM' do
|
6
|
+
Berkshelf::API::Application.shutdown
|
7
|
+
end
|
8
|
+
|
9
|
+
module Berkshelf::API
|
10
|
+
class ApplicationSupervisor < Celluloid::SupervisionGroup
|
11
|
+
# @option options [Boolean] :disable_http (false)
|
12
|
+
# run the application without the rest gateway
|
13
|
+
def initialize(registry, options = {})
|
14
|
+
super(registry)
|
15
|
+
supervise_as(:cache_manager, Berkshelf::API::CacheManager)
|
16
|
+
supervise_as(:cache_builder, Berkshelf::API::CacheBuilder)
|
17
|
+
|
18
|
+
unless options[:disable_http]
|
19
|
+
require_relative 'rest_gateway'
|
20
|
+
supervise_as(:rest_gateway, Berkshelf::API::RESTGateway, options)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
module Application
|
26
|
+
class << self
|
27
|
+
extend Forwardable
|
28
|
+
include Berkshelf::API::Logging
|
29
|
+
include Berkshelf::API::Mixin::Services
|
30
|
+
|
31
|
+
def_delegators :registry, :[], :[]=
|
32
|
+
|
33
|
+
def config
|
34
|
+
@config ||= begin
|
35
|
+
Berkshelf::API::Config.from_file(Berkshelf::API::Config.default_path)
|
36
|
+
rescue
|
37
|
+
Berkshelf::API::Config.new
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# @option options [String, Fixnum] :log_location (STDOUT)
|
42
|
+
# @option options [String, nil] :log_level ("INFO")
|
43
|
+
# - "DEBUG
|
44
|
+
# - "INFO"
|
45
|
+
# - "WARN"
|
46
|
+
# - "ERROR"
|
47
|
+
# - "FATAL"
|
48
|
+
def configure_logger(options = {})
|
49
|
+
Logging.init(level: options[:log_level], location: options[:log_location])
|
50
|
+
end
|
51
|
+
|
52
|
+
def instance
|
53
|
+
return @instance if @instance
|
54
|
+
|
55
|
+
raise NotStartedError, "application not running"
|
56
|
+
end
|
57
|
+
|
58
|
+
# The Actor registry for Berkshelf::API.
|
59
|
+
#
|
60
|
+
# @note Berkshelf::API uses it's own registry instead of Celluloid::Registry.root to
|
61
|
+
# avoid conflicts in the larger namespace. Use Berkshelf::API::Application[] to access Berkshelf::API
|
62
|
+
# actors instead of Celluloid::Actor[].
|
63
|
+
#
|
64
|
+
# @return [Celluloid::Registry]
|
65
|
+
def registry
|
66
|
+
@registry ||= Celluloid::Registry.new
|
67
|
+
end
|
68
|
+
|
69
|
+
# Run the application in the foreground (sleep on main thread)
|
70
|
+
#
|
71
|
+
# @option options [Boolean] :disable_http (false)
|
72
|
+
# run the application without the rest gateway
|
73
|
+
def run(options = {})
|
74
|
+
loop do
|
75
|
+
supervisor = run!(options)
|
76
|
+
|
77
|
+
sleep 0.1 while supervisor.alive?
|
78
|
+
|
79
|
+
break if @shutdown
|
80
|
+
|
81
|
+
log.error "!!! #{self} crashed. Restarting..."
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# Run the application in the background
|
86
|
+
#
|
87
|
+
# @option options [Boolean] :disable_http (false)
|
88
|
+
# run the application without the rest gateway
|
89
|
+
# @option options [Boolean] :eager_build (false)
|
90
|
+
# automatically begin and loop all cache builders
|
91
|
+
#
|
92
|
+
# @return [Berkshelf::API::Application]
|
93
|
+
def run!(options = {})
|
94
|
+
options = { disable_http: false, eager_build: false }.merge(options)
|
95
|
+
configure_logger(options)
|
96
|
+
@instance = ApplicationSupervisor.new(registry, options)
|
97
|
+
cache_builder.async(:build_loop) if options[:eager_build]
|
98
|
+
@instance
|
99
|
+
end
|
100
|
+
|
101
|
+
# @return [Boolean]
|
102
|
+
def running?
|
103
|
+
instance.alive?
|
104
|
+
rescue NotStartedError
|
105
|
+
false
|
106
|
+
end
|
107
|
+
|
108
|
+
def shutdown
|
109
|
+
@shutdown = true
|
110
|
+
instance.terminate
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Berkshelf::API
|
2
|
+
class CacheBuilder
|
3
|
+
require_relative 'cache_builder/worker'
|
4
|
+
|
5
|
+
class WorkerSupervisor < Celluloid::SupervisionGroup; end
|
6
|
+
|
7
|
+
BUILD_INTERVAL = 5.0
|
8
|
+
|
9
|
+
include Berkshelf::API::GenericServer
|
10
|
+
include Berkshelf::API::Logging
|
11
|
+
|
12
|
+
server_name :cache_builder
|
13
|
+
finalizer :finalize_callback
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
log.info "Cache Builder starting..."
|
17
|
+
@worker_registry = Celluloid::Registry.new
|
18
|
+
@worker_supervisor = WorkerSupervisor.new(@worker_registry)
|
19
|
+
@building = false
|
20
|
+
|
21
|
+
Application.config.endpoints.each do |endpoint|
|
22
|
+
@worker_supervisor.supervise(CacheBuilder::Worker[endpoint.type], endpoint.options)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Issue a single build command to all workers
|
27
|
+
#
|
28
|
+
# @return [Array]
|
29
|
+
def build
|
30
|
+
workers.collect { |actor| actor.future(:build) }.map(&:value)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Issue a build command to all workers at the scheduled interval
|
34
|
+
#
|
35
|
+
# @param [Fixnum, Float] interval
|
36
|
+
def build_loop(interval = BUILD_INTERVAL)
|
37
|
+
return if @building
|
38
|
+
|
39
|
+
loop do
|
40
|
+
@building = true
|
41
|
+
build
|
42
|
+
sleep BUILD_INTERVAL
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Return the list of running workers
|
47
|
+
#
|
48
|
+
# @return [Array<CacheBuilder::Worker::Base>]
|
49
|
+
def workers
|
50
|
+
@worker_supervisor.actors
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def finalize_callback
|
56
|
+
log.info "Cache Builder shutting down..."
|
57
|
+
@worker_supervisor.terminate if @worker_supervisor && @worker_supervisor.alive?
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
module Berkshelf::API
|
2
|
+
class CacheBuilder
|
3
|
+
module Worker
|
4
|
+
class Base
|
5
|
+
class << self
|
6
|
+
# @param [#to_s, nil] type
|
7
|
+
def worker_type(type = nil)
|
8
|
+
return @worker_type if @worker_type
|
9
|
+
@worker_type = type.to_s
|
10
|
+
Worker.register(@worker_type, self)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
include Celluloid
|
15
|
+
include Berkshelf::API::Logging
|
16
|
+
include Berkshelf::API::Mixin::Services
|
17
|
+
|
18
|
+
attr_reader :options
|
19
|
+
|
20
|
+
def initialize(options = {}); end
|
21
|
+
|
22
|
+
# @abstract
|
23
|
+
#
|
24
|
+
# @param [RemoteCookbook] remote
|
25
|
+
#
|
26
|
+
# @return [Ridley::Chef::Cookbook::Metadata]
|
27
|
+
def metadata(remote)
|
28
|
+
raise RuntimeError, "must be implemented"
|
29
|
+
end
|
30
|
+
|
31
|
+
# @abstract
|
32
|
+
#
|
33
|
+
# @return [Array<RemoteCookbook>]
|
34
|
+
# The list of cookbooks this builder can find
|
35
|
+
def cookbooks
|
36
|
+
raise RuntimeError, "must be implemented"
|
37
|
+
end
|
38
|
+
|
39
|
+
def build
|
40
|
+
log.info "#{self} building..."
|
41
|
+
log.info "#{self} determining if the cache is stale..."
|
42
|
+
if stale?
|
43
|
+
log.info "#{self} cache is stale."
|
44
|
+
update_cache
|
45
|
+
else
|
46
|
+
log.info "#{self} cache is up to date."
|
47
|
+
end
|
48
|
+
|
49
|
+
log.info "clearing diff"
|
50
|
+
clear_diff
|
51
|
+
end
|
52
|
+
|
53
|
+
# @return [Array<Array<RemoteCookbook>, Array<RemoteCookbook>>]
|
54
|
+
def diff
|
55
|
+
@diff ||= cache_manager.diff(cookbooks)
|
56
|
+
end
|
57
|
+
|
58
|
+
def update_cache
|
59
|
+
created_cookbooks, deleted_cookbooks = diff
|
60
|
+
|
61
|
+
log.info "#{self} adding (#{created_cookbooks.length}) items..."
|
62
|
+
created_cookbooks.collect do |remote|
|
63
|
+
[ remote, future(:metadata, remote) ]
|
64
|
+
end.each do |remote, metadata|
|
65
|
+
cache_manager.add(remote, metadata.value)
|
66
|
+
end
|
67
|
+
|
68
|
+
log.info "#{self} removing (#{deleted_cookbooks.length}) items..."
|
69
|
+
deleted_cookbooks.each { |remote| cache_manager.remove(remote.name, remote.version) }
|
70
|
+
|
71
|
+
log.info "#{self} cache updated."
|
72
|
+
cache_manager.save
|
73
|
+
end
|
74
|
+
|
75
|
+
def stale?
|
76
|
+
created_cookbooks, deleted_cookbooks = diff
|
77
|
+
created_cookbooks.any? || deleted_cookbooks.any?
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
def clear_diff
|
83
|
+
@diff = nil
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
class << self
|
88
|
+
# @param [#to_s] name
|
89
|
+
#
|
90
|
+
# @return [Worker::Base]
|
91
|
+
def [](name)
|
92
|
+
types[name.to_s]
|
93
|
+
end
|
94
|
+
|
95
|
+
# @param [#to_s] name
|
96
|
+
# @param [Worker::Base] klass
|
97
|
+
def register(name, klass)
|
98
|
+
name = name.to_s
|
99
|
+
if types.has_key?(name)
|
100
|
+
raise RuntimeError, "worker already registered with the name '#{name}'"
|
101
|
+
end
|
102
|
+
types[name] = klass
|
103
|
+
end
|
104
|
+
|
105
|
+
# @return [Hash]
|
106
|
+
def types
|
107
|
+
@types ||= Hash.new
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
Dir["#{File.dirname(__FILE__)}/worker/*.rb"].sort.each do |path|
|
115
|
+
require_relative "worker/#{File.basename(path, '.rb')}"
|
116
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Berkshelf::API
|
2
|
+
class CacheBuilder
|
3
|
+
module Worker
|
4
|
+
class ChefServer < Worker::Base
|
5
|
+
worker_type "chef_server"
|
6
|
+
|
7
|
+
finalizer :finalize_callback
|
8
|
+
|
9
|
+
def initialize(options = {})
|
10
|
+
@connection = Ridley::Client.new_link(server_url: options[:url], client_key: options[:client_key],
|
11
|
+
client_name: options[:client_name], ssl: { verify: options[:ssl_verify] })
|
12
|
+
super
|
13
|
+
end
|
14
|
+
|
15
|
+
# @return [Array<RemoteCookbook>]
|
16
|
+
# The list of cookbooks this builder can find
|
17
|
+
def cookbooks
|
18
|
+
[].tap do |cookbook_versions|
|
19
|
+
connection.cookbook.all.each do |cookbook, versions|
|
20
|
+
versions.each do |version|
|
21
|
+
cookbook_versions << RemoteCookbook.new(cookbook, version, self.class.worker_type,
|
22
|
+
@connection.server_url)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# @param [RemoteCookbook] remote
|
29
|
+
#
|
30
|
+
# @return [Ridley::Chef::Cookbook::Metadata]
|
31
|
+
def metadata(remote)
|
32
|
+
metadata_hash = connection.cookbook.find(remote.name, remote.version).metadata
|
33
|
+
Ridley::Chef::Cookbook::Metadata.from_hash(metadata_hash)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
attr_reader :connection
|
39
|
+
|
40
|
+
def finalize_callback
|
41
|
+
connection.terminate if connection && connection.alive?
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Berkshelf::API
|
2
|
+
class CacheBuilder
|
3
|
+
module Worker
|
4
|
+
class Opscode < Worker::Base
|
5
|
+
worker_type "opscode"
|
6
|
+
|
7
|
+
finalizer :finalize_callback
|
8
|
+
|
9
|
+
def initialize(options = {})
|
10
|
+
@connection = Berkshelf::API::SiteConnector::Opscode.pool_link(size: 25)
|
11
|
+
super
|
12
|
+
end
|
13
|
+
|
14
|
+
# @return [Array<RemoteCookbook>]
|
15
|
+
# The list of cookbooks this builder can find
|
16
|
+
def cookbooks
|
17
|
+
[].tap do |cookbook_versions|
|
18
|
+
connection.cookbooks.collect do |cookbook|
|
19
|
+
[ cookbook, connection.future(:versions, cookbook) ]
|
20
|
+
end.each do |cookbook, versions|
|
21
|
+
versions.value.each do |version|
|
22
|
+
cookbook_versions << RemoteCookbook.new(cookbook, version, self.class.worker_type, @connection.api_uri)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# @param [RemoteCookbook] remote
|
29
|
+
#
|
30
|
+
# @return [Ridley::Chef::Cookbook::Metadata]
|
31
|
+
def metadata(remote)
|
32
|
+
Dir.mktmpdir do |destination|
|
33
|
+
connection.download(remote.name, remote.version, destination)
|
34
|
+
load_metadata(destination, remote.name)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
attr_accessor :connection
|
41
|
+
|
42
|
+
def finalize_callback
|
43
|
+
connection.terminate if connection && connection.alive?
|
44
|
+
end
|
45
|
+
|
46
|
+
def load_metadata(directory, cookbook)
|
47
|
+
# The community site does not enforce the name of the cookbook contained in the archive
|
48
|
+
# downloaded and extracted. This will just find the first metadata.json and load it.
|
49
|
+
file = Dir["#{directory}/**/*/metadata.json"].first
|
50
|
+
metadata = File.read(file)
|
51
|
+
Ridley::Chef::Cookbook::Metadata.from_json(metadata)
|
52
|
+
rescue JSON::ParserError => ex
|
53
|
+
log.warn "Error loading metadata for #{cookbook} from: #{file}"
|
54
|
+
abort MetadataLoadError.new(ex)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
module Berkshelf::API
|
2
|
+
class CacheManager
|
3
|
+
class << self
|
4
|
+
attr_writer :cache_file
|
5
|
+
|
6
|
+
# @return [String]
|
7
|
+
def cache_file
|
8
|
+
@cache_file ||= File.expand_path("~/.berkshelf/api-server/cerch")
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
include Berkshelf::API::GenericServer
|
13
|
+
include Berkshelf::API::Logging
|
14
|
+
|
15
|
+
SAVE_INTERVAL = 30.0
|
16
|
+
|
17
|
+
server_name :cache_manager
|
18
|
+
finalizer :finalize_callback
|
19
|
+
exclusive :add, :clear, :remove, :save
|
20
|
+
|
21
|
+
attr_reader :cache
|
22
|
+
|
23
|
+
def initialize
|
24
|
+
log.info "Cache Manager starting..."
|
25
|
+
@cache = DependencyCache.new
|
26
|
+
load_save if File.exist?(self.class.cache_file)
|
27
|
+
every(SAVE_INTERVAL) { save }
|
28
|
+
end
|
29
|
+
|
30
|
+
# @param [RemoteCookbook] cookbook
|
31
|
+
# @param [Ridley::Chef::Cookbook::Metadata] metadata
|
32
|
+
#
|
33
|
+
# @return [Hash]
|
34
|
+
def add(cookbook, metadata)
|
35
|
+
@cache.add(cookbook, metadata)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Clear any items added to the cache
|
39
|
+
#
|
40
|
+
# @return [Hash]
|
41
|
+
def clear
|
42
|
+
@cache.clear
|
43
|
+
end
|
44
|
+
|
45
|
+
# Check if the cache knows about the given cookbook version
|
46
|
+
#
|
47
|
+
# @param [#to_s] name
|
48
|
+
# @param [#to_s] version
|
49
|
+
#
|
50
|
+
# @return [Boolean]
|
51
|
+
def has_cookbook?(name, version)
|
52
|
+
@cache.has_cookbook?(name, version)
|
53
|
+
end
|
54
|
+
|
55
|
+
def load_save
|
56
|
+
@cache = DependencyCache.from_file(self.class.cache_file)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Remove the cached item matching the given name and version
|
60
|
+
#
|
61
|
+
# @param [#to_s] name
|
62
|
+
# @param [#to_s] version
|
63
|
+
#
|
64
|
+
# @return [DependencyCache]
|
65
|
+
def remove(name, version)
|
66
|
+
@cache.remove(name, version)
|
67
|
+
end
|
68
|
+
|
69
|
+
def save
|
70
|
+
log.info "Saving the cache to: #{self.class.cache_file}"
|
71
|
+
cache.save(self.class.cache_file)
|
72
|
+
log.info "Cache saved!"
|
73
|
+
end
|
74
|
+
|
75
|
+
# @param [Array<RemoteCookbook>] cookbooks
|
76
|
+
# An array of RemoteCookbooks representing all the cookbooks on the indexed site
|
77
|
+
#
|
78
|
+
# @return [Array<Array<RemoteCookbook>, Array<RemoteCookbook>>]
|
79
|
+
# A tuple of Arrays of RemoteCookbooks
|
80
|
+
# The first array contains items not in the cache
|
81
|
+
# The second array contains items in the cache, but not in the cookbooks parameter
|
82
|
+
def diff(cookbooks)
|
83
|
+
known_cookbooks = cache.cookbooks
|
84
|
+
created_cookbooks = cookbooks - known_cookbooks
|
85
|
+
deleted_cookbooks = known_cookbooks - cookbooks
|
86
|
+
[ created_cookbooks, deleted_cookbooks ]
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
def finalize_callback
|
92
|
+
log.info "Cache Manager shutting down..."
|
93
|
+
self.save
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|