Skip to content
This repository has been archived by the owner on Jul 14, 2021. It is now read-only.

Commit

Permalink
Add :delivery_supermarket default source type
Browse files Browse the repository at this point in the history
This type behaves like the supermarket/community source, except that
only the highest version cookbook is exposed via the universe graph.
  • Loading branch information
danielsdeleo committed Oct 22, 2015
1 parent b093421 commit 35a8c7e
Show file tree
Hide file tree
Showing 5 changed files with 234 additions and 0 deletions.
1 change: 1 addition & 0 deletions lib/chef-dk/policyfile/cookbook_sources.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@
require 'chef-dk/policyfile/community_cookbook_source'
require 'chef-dk/policyfile/chef_server_cookbook_source'
require 'chef-dk/policyfile/chef_repo_cookbook_source'
require 'chef-dk/policyfile/delivery_supermarket_source'
82 changes: 82 additions & 0 deletions lib/chef-dk/policyfile/delivery_supermarket_source.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#
# Copyright:: Copyright (c) 2014 Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

require 'forwardable'

require 'semverse'

require 'chef-dk/policyfile/community_cookbook_source'

module ChefDK
module Policyfile

# Fetches cookbooks from a supermarket, similar to CommunityCookbookSource
# (which it delegates to), except that only the latest versions of any
# cookbook can be used.
#
# This is intended to be used in an environment where the team wants to
# make only the newest version of a given cookbook available in order to
# force developers to integrate continuously at the component artifact
# (cookbook) level. To achieve this goal, two constraints must be imposed:
#
# * Cookbook changes pass through a Ci pipeline and are ultimately uploaded
# to a private supermarket (or equivalent, i.e. mini-mart) after final
# approval (which can be automated or not)
# * Version numbers for cookbooks that pass through the Ci pipeline always
# increase over time (so that largest version number == newest)
#
# In the future, alternative approaches may be persued to achieve the goal
# of continuously integrating at the cookbook level without imposing those
# constraints.
#
class DeliverySupermarketSource

extend Forwardable

def_delegator :@community_source, :uri
def_delegator :@community_source, :source_options_for
def_delegator :@community_source, :null?

def initialize(uri)
@community_source = CommunityCookbookSource.new(uri)
end

def ==(other)
other.kind_of?(self.class) && other.uri == uri
end

def universe_graph
@universe_graph ||= begin
@community_source.universe_graph.inject({}) do |truncated, (cookbook_name, version_and_deps_list)|
sorted_versions = version_and_deps_list.keys.sort_by do |version_string|
Semverse::Version.new(version_string)
end
greatest_version = sorted_versions.last
truncated[cookbook_name] = { greatest_version => version_and_deps_list[greatest_version] }
truncated
end
end
end

def desc
"delivery_supermarket(#{uri})"
end

end
end
end

10 changes: 10 additions & 0 deletions lib/chef-dk/policyfile/dsl.rb
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ def default_source(source_type = nil, source_argument = nil)
case source_type
when :community, :supermarket
set_default_community_source(source_argument)
when :delivery_supermarket
set_default_delivery_supermarket_source(source_argument)
when :chef_server
set_default_chef_server_source(source_argument)
when :chef_repo
Expand Down Expand Up @@ -143,6 +145,14 @@ def set_default_community_source(source_uri)
set_default_source(CommunityCookbookSource.new(source_uri))
end

def set_default_delivery_supermarket_source(source_uri)
if source_uri.nil?
@errors << "You must specify the server's URI when using a default_source :delivery_supermarket"
else
set_default_source(DeliverySupermarketSource.new(source_uri))
end
end

def set_default_chef_server_source(source_uri)
if source_uri.nil?
@errors << "You must specify the server's URI when using a default_source :chef_server"
Expand Down
105 changes: 105 additions & 0 deletions spec/unit/policyfile/delivery_supermarket_source_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#
# Copyright:: Copyright (c) 2014 Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

require 'spec_helper'
require 'chef-dk/policyfile/delivery_supermarket_source'

describe ChefDK::Policyfile::DeliverySupermarketSource do

let(:supermarket_uri) { "https://delivery-supermarket.example" }

subject(:cookbook_source) { ChefDK::Policyfile::DeliverySupermarketSource.new(supermarket_uri) }

let(:http_connection) { double("Chef::HTTP::Simple") }

let(:universe_response_encoded) { IO.read(File.join(fixtures_path, "cookbooks_api/small_universe.json")) }

let(:truncated_universe) do
{
"nginx" => {
"2.7.4" => {
"apt" => "~> 2.2.0",
"bluepill" => "~> 2.3.0",
"build-essential" => "~> 2.0.0",
"ohai" => "~> 2.0.0",
"runit" => "~> 1.2.0",
"yum-epel" => "~> 0.3.0"
}
},
"mysql" => {
"5.3.6" => {
"yum-mysql-community" => ">= 0.0.0"
}
},
"application" => {
"4.1.4" => {}
},
"database" => {
"2.2.0" => {
"mysql" => ">= 5.0.0",
"postgresql" => ">= 1.0.0",
"aws" => ">= 0.0.0",
"xfs" => ">= 0.0.0",
"mysql-chef_gem" => ">= 0.0.0"
}
},
"postgresql" => {
"3.4.1" => {
"apt" => ">= 1.9.0",
"build-essential" => ">= 0.0.0",
"openssl" => ">= 0.0.0"
}
},
"apache2" => {
"1.10.4" => {
"iptables" => ">= 0.0.0",
"logrotate" => ">= 0.0.0",
"pacman" => ">= 0.0.0"
}
},
"apt" => { "2.4.0" => {}},
"yum" => { "3.2.2" => {}}
}
end

it "uses `delivery_supermarket` it its description" do
expect(cookbook_source.desc).to eq("delivery_supermarket(https://delivery-supermarket.example)")
end

describe "when fetching the /universe graph" do

before do
expect(Chef::HTTP::Simple).to receive(:new).with(supermarket_uri).and_return(http_connection)
expect(http_connection).to receive(:get).with("/universe").and_return(universe_response_encoded)
end

it "fetches the universe graph and truncates to only the latest versions" do
actual_universe = cookbook_source.universe_graph
expect(actual_universe).to have_key("apt")
expect(actual_universe["apt"]).to eq(truncated_universe["apt"])
expect(cookbook_source.universe_graph).to eq(truncated_universe)
end

it "generates location options for a cookbook from the given graph" do
expected_opts = { artifactserver: "https://supermarket.chef.io/api/v1/cookbooks/apache2/versions/1.10.4/download", version: "1.10.4" }
expect(cookbook_source.source_options_for("apache2", "1.10.4")).to eq(expected_opts)
end

end

end

36 changes: 36 additions & 0 deletions spec/unit/policyfile_evaluation_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,42 @@

end

context "with the default source set to a delivery_supermarket" do

context "when no URI is given" do

let(:policyfile_rb) do
<<-EOH
run_list "foo", "bar"
default_source :delivery_supermarket
EOH
end

it "errors out with a message that the supermarket URI is required" do
expect(policyfile.errors).to eq([ "You must specify the server's URI when using a default_source :delivery_supermarket" ])
end

end

context "when the URI is given" do

let(:policyfile_rb) do
<<-EOH
run_list "foo", "bar"
default_source :delivery_supermarket, "https://supermarket.example.com"
EOH
end

it "sets the default source to the delivery_supermarket" do
expect(policyfile.errors).to eq([])
expected = [ ChefDK::Policyfile::DeliverySupermarketSource.new("https://supermarket.example.com") ]
expect(policyfile.default_source).to eq(expected)
end

end

end

context "with the default source set to a chef server" do

let(:policyfile_rb) do
Expand Down

0 comments on commit 35a8c7e

Please sign in to comment.