From 94074c10f95fe6b826fe68b8607be34b5595fadb Mon Sep 17 00:00:00 2001 From: Reid Vandewiele Date: Fri, 28 Dec 2018 13:24:38 -0800 Subject: [PATCH 1/8] Implement R10K::Environment::WithModules baseclass This commit implements a new capability for R10K environment objects: environments can now contain modules directly, when built from an appropriate source type and environment type. Previously, modules could only be attached to an environment by loading an environment, then reading the Puppetfile it contained. This constrained the system because in order for modules to be added, removed, or updated, either the core environment content needed to be changed (the Puppetfile edited), or some kind of magic pattern needed to be specified in the Puppetfile which delegated part of the work of defining a module to an external source (the :control_branch pattern). Now, the framework exists that enables an environment source to add, remove, or update deployed module versions without ever touching or modifying a Puppetfile. --- lib/r10k/action/deploy/environment.rb | 4 +- lib/r10k/environment.rb | 1 + lib/r10k/environment/with_modules.rb | 127 ++++++++++++++++++++ lib/r10k/module/base.rb | 5 + lib/r10k/puppetfile.rb | 6 + spec/unit/action/deploy/environment_spec.rb | 1 + 6 files changed, 142 insertions(+), 2 deletions(-) create mode 100644 lib/r10k/environment/with_modules.rb diff --git a/lib/r10k/action/deploy/environment.rb b/lib/r10k/action/deploy/environment.rb index 92423bf54..587c77c71 100644 --- a/lib/r10k/action/deploy/environment.rb +++ b/lib/r10k/action/deploy/environment.rb @@ -140,14 +140,14 @@ def visit_puppetfile(puppetfile) end def visit_module(mod) - logger.info _("Deploying Puppetfile content %{mod_path}") % {mod_path: mod.path} + logger.info _("Deploying %{origin} content %{path}") % {origin: mod.origin, path: mod.path} mod.sync(force: @force) end def write_environment_info!(environment, started_at, success) module_deploys = [] begin - environment.puppetfile.modules.each do |mod| + environment.modules.each do |mod| name = mod.name version = mod.version sha = mod.repo.head rescue nil diff --git a/lib/r10k/environment.rb b/lib/r10k/environment.rb index 3a3719580..211951e86 100644 --- a/lib/r10k/environment.rb +++ b/lib/r10k/environment.rb @@ -1,6 +1,7 @@ module R10K module Environment require 'r10k/environment/base' + require 'r10k/environment/with_modules' require 'r10k/environment/git' require 'r10k/environment/svn' end diff --git a/lib/r10k/environment/with_modules.rb b/lib/r10k/environment/with_modules.rb new file mode 100644 index 000000000..a06458c3f --- /dev/null +++ b/lib/r10k/environment/with_modules.rb @@ -0,0 +1,127 @@ +require 'r10k/util/purgeable' + +# This abstract base class implements an environment that can include module +# content +# +# @since 3.4.0 +class R10K::Environment::WithModules < R10K::Environment::Base + + # @!attribute [r] moduledir + # @return [String] The directory to install environment-defined modules + # into (default: #{basedir}/modules) + attr_reader :moduledir + + # Initialize the given environment. + # + # @param name [String] The unique name describing this environment. + # @param basedir [String] The base directory where this environment will be created. + # @param dirname [String] The directory name for this environment. + # @param options [Hash] An additional set of options for this environment. + # + # @param options [String] :moduledir The path to install modules to + # @param options [Hash] :modules Modules to add to the environment + def initialize(name, basedir, dirname, options = {}) + super(name, basedir, dirname, options) + + @managed_content = {} + @modules = [] + @moduledir = case options[:moduledir] + when nil + File.join(@basedir, @dirname, 'modules') + when File.absolute_path(options[:moduledir]) + options.delete(:moduledir) + else + File.join(@basedir, @dirname, options.delete(:moduledir)) + end + + modhash = options.delete(:modules) + load_modules(modhash) unless modhash.nil? + end + + # @return [Array] All modules associated with this environment. + # Modules may originate from either: + # - The r10k environment object + # - A Puppetfile in the environment's content + def modules + return @modules if @puppetfile.nil? + + @puppetfile.load unless @puppetfile.loaded? + @modules + @puppetfile.modules + end + + def accept(visitor) + visitor.visit(:environment, self) do + @modules.each do |mod| + mod.accept(visitor) + end + + puppetfile.accept(visitor) + validate_no_module_conflicts + end + end + + def load_modules(module_hash) + module_hash.each do |name, args| + add_module(name, args) + end + end + + # @param [String] name + # @param [*Object] args + def add_module(name, args) + if args.is_a?(Hash) + # symbolize keys in the args hash + args = args.inject({}) { |memo,(k,v)| memo[k.to_sym] = v; memo } + end + + if args.is_a?(Hash) && install_path = args.delete(:install_path) + install_path = resolve_install_path(install_path) + validate_install_path(install_path, name) + else + install_path = @moduledir + end + + # Keep track of all the content this environment is managing to enable purging. + @managed_content[install_path] = Array.new unless @managed_content.has_key?(install_path) + + mod = R10K::Module.new(name, install_path, args, self.name) + mod.origin = 'Environment' + + @managed_content[install_path] << mod.name + @modules << mod + end + + def validate_no_module_conflicts + @puppetfile.load unless @puppetfile.loaded? + conflicts = (@modules + @puppetfile.modules) + .group_by { |mod| mod.name } + .select { |_, v| v.size > 1 } + .map(&:first) + unless conflicts.empty? + msg = _('Puppetfile cannot contain module names defined by environment %{name}') % {name: self.name} + msg += ' ' + msg += _("Remove the conflicting definitions of the following modules: %{conflicts}" % { conflicts: conflicts.join(' ') }) + raise R10K::Error.new(msg) + end + end + + include R10K::Util::Purgeable + + # Returns an array of the full paths that can be purged. + # @note This implements a required method for the Purgeable mixin + # @return [Array] + def managed_directories + [@full_path] + end + + # Returns an array of the full paths of filenames that should exist. Files + # inside managed_directories that are not listed in desired_contents will + # be purged. + # @note This implements a required method for the Purgeable mixin + # @return [Array] + def desired_contents + @managed_content.flat_map do |install_path, modnames| + modnames.collect { |name| File.join(install_path, name) } + end + end +end diff --git a/lib/r10k/module/base.rb b/lib/r10k/module/base.rb index af7a6c764..58172e135 100644 --- a/lib/r10k/module/base.rb +++ b/lib/r10k/module/base.rb @@ -31,6 +31,10 @@ class R10K::Module::Base # @return [R10K::Environment, nil] The parent environment of the module attr_reader :environment + # @!attribute [rw] origin + # @return [String] Where the module was sourced from. E.g., "Puppetfile" + attr_accessor :origin + # There's been some churn over `author` vs `owner` and `full_name` over # `title`, so in the short run it's easier to support both and deprecate one # later. @@ -47,6 +51,7 @@ def initialize(title, dirname, args, environment=nil) @owner, @name = parse_title(@title) @path = Pathname.new(File.join(@dirname, @name)) @environment = environment + @origin = 'external' # Expect Puppetfile or R10k::Environment to set this to a specific value end # @deprecated diff --git a/lib/r10k/puppetfile.rb b/lib/r10k/puppetfile.rb index 3c4c5bf10..070d93913 100644 --- a/lib/r10k/puppetfile.rb +++ b/lib/r10k/puppetfile.rb @@ -64,6 +64,7 @@ def initialize(basedir, moduledir = nil, puppetfile_path = nil, puppetfile_name end def load(default_branch_override = nil) + return true if self.loaded? if File.readable? @puppetfile_path self.load!(default_branch_override) else @@ -83,6 +84,10 @@ def load!(default_branch_override = nil) raise R10K::Error.wrap(e, _("Failed to evaluate %{path}") % {path: @puppetfile_path}) end + def loaded? + @loaded + end + # @param [Array] modules def validate_no_duplicate_names(modules) dupes = modules @@ -129,6 +134,7 @@ def add_module(name, args) @managed_content[install_path] = Array.new unless @managed_content.has_key?(install_path) mod = R10K::Module.new(name, install_path, args, @environment) + mod.origin = 'Puppetfile' @managed_content[install_path] << mod.name @modules << mod diff --git a/spec/unit/action/deploy/environment_spec.rb b/spec/unit/action/deploy/environment_spec.rb index a733e1ef8..43a35032e 100644 --- a/spec/unit/action/deploy/environment_spec.rb +++ b/spec/unit/action/deploy/environment_spec.rb @@ -369,6 +369,7 @@ def initialize(path, info) allow(mock_forge_module_1).to receive(:repo).and_raise(NoMethodError) fake_env = Fake_Environment.new(@tmp_path, {:name => "my_cool_environment", :signature => "pablo picasso"}) + allow(fake_env).to receive(:modules).and_return(mock_puppetfile.modules) subject.send(:write_environment_info!, fake_env, "2019-01-01 23:23:22 +0000", true) file_contents = File.read("#{@tmp_path}/.r10k-deploy.json") From edf41b70f0e3812b0558d7ab9b625d3f157ac188 Mon Sep 17 00:00:00 2001 From: Reid Vandewiele Date: Thu, 26 Sep 2019 10:59:32 -0700 Subject: [PATCH 2/8] Implement R10K::Source::Hash abstract baseclass The Hash environment source type is an abstract base class that makes it easy to define environments by simply enumerating them. For example, a REST API could provide a JSON object enumerating each environment that should exist, along with details such as modules to deploy to them. The Hash source baseclass can consume this data and produce the appropriate environments. Note that such a source would no longer need be tightly coupled with version control branches, which is the only way today's r10k sources work. --- lib/r10k/environment.rb | 28 +++++++ lib/r10k/environment/git.rb | 4 + lib/r10k/environment/svn.rb | 2 + lib/r10k/source.rb | 1 + lib/r10k/source/hash.rb | 158 ++++++++++++++++++++++++++++++++++++ 5 files changed, 193 insertions(+) create mode 100644 lib/r10k/source/hash.rb diff --git a/lib/r10k/environment.rb b/lib/r10k/environment.rb index 211951e86..b18bdc586 100644 --- a/lib/r10k/environment.rb +++ b/lib/r10k/environment.rb @@ -1,5 +1,33 @@ module R10K module Environment + def self.factory + @factory ||= R10K::KeyedFactory.new + end + + def self.register(key, klass) + factory.register(key, klass) + end + + def self.retrieve(key) + factory.retrieve(key) + end + + def self.generate(type, name, basedir, dirname, options = {}) + factory.generate(type, name, basedir, dirname, options) + end + + def self.from_hash(name, hash) + R10K::Util::SymbolizeKeys.symbolize_keys!(hash) + + basedir = hash.delete(:basedir) + dirname = hash.delete(:dirname) || name + + type = hash.delete(:type) + type = type.is_a?(String) ? type.to_sym : type + + generate(type, name, basedir, dirname, hash) + end + require 'r10k/environment/base' require 'r10k/environment/with_modules' require 'r10k/environment/git' diff --git a/lib/r10k/environment/git.rb b/lib/r10k/environment/git.rb index 4830f1912..ec798111e 100644 --- a/lib/r10k/environment/git.rb +++ b/lib/r10k/environment/git.rb @@ -10,6 +10,10 @@ class R10K::Environment::Git < R10K::Environment::Base include R10K::Logging + R10K::Environment.register(:git, self) + # Register git as the default environment type + R10K::Environment.register(nil, self) + # @!attribute [r] remote # @return [String] The URL to the remote git repository attr_reader :remote diff --git a/lib/r10k/environment/svn.rb b/lib/r10k/environment/svn.rb index f70e1ead3..8b47cb053 100644 --- a/lib/r10k/environment/svn.rb +++ b/lib/r10k/environment/svn.rb @@ -9,6 +9,8 @@ class R10K::Environment::SVN < R10K::Environment::Base include R10K::Logging + R10K::Environment.register(:svn, self) + # @!attribute [r] remote # @return [String] The URL to the remote SVN branch to check out attr_reader :remote diff --git a/lib/r10k/source.rb b/lib/r10k/source.rb index 39f054909..2b5f00b9d 100644 --- a/lib/r10k/source.rb +++ b/lib/r10k/source.rb @@ -32,6 +32,7 @@ def self.from_hash(name, hash) end require 'r10k/source/base' + require 'r10k/source/hash' require 'r10k/source/git' require 'r10k/source/svn' end diff --git a/lib/r10k/source/hash.rb b/lib/r10k/source/hash.rb new file mode 100644 index 000000000..cdd5a04df --- /dev/null +++ b/lib/r10k/source/hash.rb @@ -0,0 +1,158 @@ +# This class implements an environment source based on recieving a hash of +# environments +# +# @since 3.4.0 +# +# DESCRIPTION +# +# This class implements environments defined by a hash having the following +# schema: +# +# --- +# type: object +# additionalProperties: +# type: object +# properties: +# type: +# type: string +# basedir: +# type: string +# modules: +# type: object +# additionalProperties: +# type: object +# moduledir: +# type: string +# additionalProperties: +# type: string +# +# The top-level keys in the hash are environment names. Keys in individual +# environments should be the same as those which would be given to define a +# single source in r10k.yaml. Additionally, the "modules" key (and moduledir) +# can be used to designate module content for the environment, independent of +# the base source parameters. +# +# Example: +# +# --- +# production: +# type: git +# remote: 'https://github.com/reidmv/control-repo.git' +# ref: '1.0.0' +# modules: +# geoffwilliams-r_profile: '1.1.0' +# geoffwilliams-r_role: '2.0.0' +# +# development: +# type: git +# remote: 'https://github.com/reidmv/control-repo.git' +# ref: 'master' +# modules: +# geoffwilliams-r_profile: '1.1.0' +# geoffwilliams-r_role: '2.0.0' +# +# USAGE +# +# The following is an example implementation class showing how to use the +# R10K::Source::Hash abstract base class. Assume an r10k.yaml file such as: +# +# --- +# sources: +# proof-of-concept: +# type: demo +# basedir: '/etc/puppetlabs/code/environments' +# +# Class implementation: +# +# class R10K::Source::Demo < R10K::Source::Hash +# R10K::Source.register(:demo, self) +# +# def initialize(name, basedir, options = {}) +# # This is just a demo class, so we hard-code an example :environments +# # hash here. In a real class, we might do something here such as +# # perform an API call to retrieve an :environments hash. +# options[:environments] = { +# 'production' => { +# 'remote' => 'https://git.example.com/puppet/control-repo.git', +# 'ref' => 'release-141', +# 'modules' => { +# 'puppetlabs-stdlib' => '6.1.0', +# 'puppetlabs-ntp' => '8.1.0', +# 'example-myapp1' => { +# 'git' => 'https://git.example.com/puppet/example-myapp1.git', +# 'ref' => 'v1.3.0', +# }, +# }, +# }, +# 'development' => { +# 'remote' => 'https://git.example.com/puppet/control-repo.git', +# 'ref' => 'master', +# 'modules' => { +# 'puppetlabs-stdlib' => '6.1.0', +# 'puppetlabs-ntp' => '8.1.0', +# 'example-myapp1' => { +# 'git' => 'https://git.example.com/puppet/example-myapp1.git', +# 'ref' => 'v1.3.1', +# }, +# }, +# }, +# } +# +# # All we need to do is supply options with the :environments hash. +# # The R10K::Source::Hash parent class takes care of the rest. +# super(name, basedir, options) +# end +# end +# +# Example output: +# +# [root@master:~] % r10k deploy environment production -pv +# INFO -> Using Puppetfile '/etc/puppetlabs/code/environments/production/Puppetfile' +# INFO -> Using Puppetfile '/etc/puppetlabs/code/environments/development/Puppetfile' +# INFO -> Deploying environment /etc/puppetlabs/code/environments/production +# INFO -> Environment production is now at 74ea2e05bba796918e4ff1803018c526337ef5f3 +# INFO -> Deploying Environment content /etc/puppetlabs/code/environments/production/modules/stdlib +# INFO -> Deploying Environment content /etc/puppetlabs/code/environments/production/modules/ntp +# INFO -> Deploying Environment content /etc/puppetlabs/code/environments/production/modules/myapp1 +# INFO -> Deploying Puppetfile content /etc/puppetlabs/code/environments/production/modules/ruby_task_helper +# INFO -> Deploying Puppetfile content /etc/puppetlabs/code/environments/production/modules/bolt_shim +# INFO -> Deploying Puppetfile content /etc/puppetlabs/code/environments/production/modules/apply_helpers +# +class R10K::Source::Hash < R10K::Source::Base + + # @param name [String] The identifier for this source. + # @param basedir [String] The base directory where the generated environments will be created. + # @param options [Hash] An additional set of options for this source. The + # semantics of this hash may depend on the source implementation. + # + # @option options [Boolean, String] :prefix If a String this becomes the prefix. + # If true, will use the source name as the prefix. All sources should respect this option. + # Defaults to false for no environment prefix. + # @option options [Hash] :environments The hash definition of environments + def initialize(name, basedir, options = {}) + super(name, basedir, options) + + @environments_hash = options.delete(:environments) || {} + + @environments_hash.keys.each do |name| + # TODO: deal with names that aren't valid + ::R10K::Util::SymbolizeKeys.symbolize_keys!(@environments_hash[name]) + @environments_hash[name][:basedir] = basedir + @environments_hash[name][:dirname] = name + end + end + + def environments + @environments ||= @environments_hash.map do |name, hash| + R10K::Environment.from_hash(name, hash) + end + end + + # List all environments that should exist in the basedir for this source + # @note This is required by {R10K::Util::Basedir} + # @return [Array] + def desired_contents + environments.map {|env| env.dirname } + end + +end From a657ab85c4de928114582d046a8f5a225dd9ba78 Mon Sep 17 00:00:00 2001 From: Reid Vandewiele Date: Thu, 26 Sep 2019 11:03:22 -0700 Subject: [PATCH 3/8] Extend Git environment type using WithModules This commit changes the R10K::Environment::Git class's parent from R10K::Environment::Base to R10K::Environment::WithModules. The practical effect of this is that Git environments are now compatible with environment sources that directly define modules to deploy (in addition to or instead of modules defined in a Puppetfile). --- lib/r10k/environment/git.rb | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/r10k/environment/git.rb b/lib/r10k/environment/git.rb index ec798111e..e6861111a 100644 --- a/lib/r10k/environment/git.rb +++ b/lib/r10k/environment/git.rb @@ -6,7 +6,7 @@ # This class implements an environment based on a Git branch. # # @since 1.3.0 -class R10K::Environment::Git < R10K::Environment::Base +class R10K::Environment::Git < R10K::Environment::WithModules include R10K::Logging @@ -70,15 +70,12 @@ def signature include R10K::Util::Purgeable - def managed_directories - [@full_path] - end - # Returns an array of the full paths to all the content being managed. # @note This implements a required method for the Purgeable mixin # @return [Array] def desired_contents desired = [File.join(@full_path, '.git')] desired += @repo.tracked_paths.map { |entry| File.join(@full_path, entry) } + desired += super end end From 779a8fb6a8b582a5c0b389afa467998f8c3c9ab7 Mon Sep 17 00:00:00 2001 From: Reid Vandewiele Date: Thu, 26 Sep 2019 12:23:44 -0700 Subject: [PATCH 4/8] Bugfix: version absent on install for Forge mods Prior to this fix, the .r10k-deploy.json file wouldn't have a module version in it on first install. It would be present after an upgrade or other modification of an already-present module, just not the first time the module was added to an environment. After this commit, the .r10k-deploy.json file is correctly populated with new-install Forge modules' version numbers. --- lib/r10k/module/forge.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/r10k/module/forge.rb b/lib/r10k/module/forge.rb index 233ba703f..1917a208f 100644 --- a/lib/r10k/module/forge.rb +++ b/lib/r10k/module/forge.rb @@ -75,7 +75,11 @@ def expected_version # @return [String] The version of the currently installed module def current_version - @metadata ? @metadata.version : nil + if insync? + (@metadata ||= @metadata_file.read).nil? ? nil : @metadata.version + else + nil + end end alias version current_version From 7500495e5b80eea9d16041860108880633cb4bcc Mon Sep 17 00:00:00 2001 From: Reid Vandewiele Date: Thu, 3 Oct 2019 08:05:02 -0700 Subject: [PATCH 5/8] Implement yaml source type This allows r10k to read environment definitions from a YAML file, located by default at /etc/puppetlabs/r10k/environments.yaml. --- lib/r10k/source.rb | 1 + lib/r10k/source/yaml.rb | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 lib/r10k/source/yaml.rb diff --git a/lib/r10k/source.rb b/lib/r10k/source.rb index 2b5f00b9d..768e89956 100644 --- a/lib/r10k/source.rb +++ b/lib/r10k/source.rb @@ -35,5 +35,6 @@ def self.from_hash(name, hash) require 'r10k/source/hash' require 'r10k/source/git' require 'r10k/source/svn' + require 'r10k/source/yaml' end end diff --git a/lib/r10k/source/yaml.rb b/lib/r10k/source/yaml.rb new file mode 100644 index 000000000..ea3e00b15 --- /dev/null +++ b/lib/r10k/source/yaml.rb @@ -0,0 +1,20 @@ +class R10K::Source::Yaml < R10K::Source::Hash + R10K::Source.register(:yaml, self) + + def initialize(name, basedir, options = {}) + config = options[:config] || '/etc/puppetlabs/r10k/environments.yaml' + + begin + contents = ::YAML.load_file(config) + rescue => e + raise ConfigError, _("Couldn't open environments file %{file}: %{err}") % {file: config, err: e.message} + end + + # Set the environments key for the parent class to consume + options[:environments] = contents + + # All we need to do is supply options with the :environments hash. + # The R10K::Source::Hash parent class takes care of the rest. + super(name, basedir, options) + end +end From f68bfdaa47f997119a576be480602d7c799b9633 Mon Sep 17 00:00:00 2001 From: Reid Vandewiele Date: Thu, 3 Oct 2019 16:44:43 -0400 Subject: [PATCH 6/8] Fix error relating to purging environments w/ mods --- lib/r10k/environment/with_modules.rb | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/r10k/environment/with_modules.rb b/lib/r10k/environment/with_modules.rb index a06458c3f..20558c7c4 100644 --- a/lib/r10k/environment/with_modules.rb +++ b/lib/r10k/environment/with_modules.rb @@ -1,3 +1,4 @@ +require 'r10k/logging' require 'r10k/util/purgeable' # This abstract base class implements an environment that can include module @@ -6,6 +7,8 @@ # @since 3.4.0 class R10K::Environment::WithModules < R10K::Environment::Base + include R10K::Logging + # @!attribute [r] moduledir # @return [String] The directory to install environment-defined modules # into (default: #{basedir}/modules) @@ -120,8 +123,17 @@ def managed_directories # @note This implements a required method for the Purgeable mixin # @return [Array] def desired_contents - @managed_content.flat_map do |install_path, modnames| + list = @managed_content.keys + list += @managed_content.flat_map do |install_path, modnames| modnames.collect { |name| File.join(install_path, name) } end end + + def purge_exclusions + super + @managed_content.flat_map do |install_path, modnames| + modnames.map do |name| + File.join(install_path, name, '**', '*') + end + end + end end From 4e57af5c46cd90f025d745af059bffec47a80255 Mon Sep 17 00:00:00 2001 From: Reid Vandewiele Date: Thu, 3 Oct 2019 16:02:50 -0400 Subject: [PATCH 7/8] Implement "bare" environment type This type has no content besides environment-attached modules --- lib/r10k/environment.rb | 1 + lib/r10k/environment/bare.rb | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 lib/r10k/environment/bare.rb diff --git a/lib/r10k/environment.rb b/lib/r10k/environment.rb index b18bdc586..5acd31231 100644 --- a/lib/r10k/environment.rb +++ b/lib/r10k/environment.rb @@ -30,6 +30,7 @@ def self.from_hash(name, hash) require 'r10k/environment/base' require 'r10k/environment/with_modules' + require 'r10k/environment/bare' require 'r10k/environment/git' require 'r10k/environment/svn' end diff --git a/lib/r10k/environment/bare.rb b/lib/r10k/environment/bare.rb new file mode 100644 index 000000000..719f41531 --- /dev/null +++ b/lib/r10k/environment/bare.rb @@ -0,0 +1,16 @@ +class R10K::Environment::Bare < R10K::Environment::WithModules + + R10K::Environment.register(:bare, self) + + def sync + path.mkpath + end + + def status + :not_applicable + end + + def signature + 'bare-default' + end +end From 1311dbe3176ad8a435f4a9ed2f488997a4425426 Mon Sep 17 00:00:00 2001 From: Reid Vandewiele Date: Thu, 12 Dec 2019 15:38:49 -0800 Subject: [PATCH 8/8] Add experimental documentation for new features Yaml source Environment modules Bare environment type --- doc/dynamic-environments/configuration.mkd | 97 ++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/doc/dynamic-environments/configuration.mkd b/doc/dynamic-environments/configuration.mkd index 05bcc2744..303bb661f 100644 --- a/doc/dynamic-environments/configuration.mkd +++ b/doc/dynamic-environments/configuration.mkd @@ -509,3 +509,100 @@ This will create the following directory structure: |-- app1_production # app1 data repository, production branch |-- app1_develop # app1 data repository, develop branch ``` + +Experimental Features +-------- + +### YAML Environment Source + +Dynamically deploying Puppet content based on the state of version control repositories can be powerful and efficient for development workflows. The linkage however is not advantageous when trying to build precision controls over deployment of previously-developed and tested content. + +The YAML environment source type allows for a clear separation of tooling between development workflow, and deployment workflow. Development workflow creates new commits in the version control system. Deployment workflow consumes them. + +To use the YAML environment source, configure r10k's sources with at least one entry using the yaml type. + +```yaml +# r10k.yaml +--- +sources: + puppet: + type: yaml + basedir: /etc/puppetlabs/code/environments + config: /etc/puppetlabs/r10k/environments.yaml # default + +``` + +When using the YAML source type, every environment is enumerated in a single yaml file. Each environment specifies a type, source, and version (typically a Git ref) to deploy. In the following example, two environments are defined, which are identical to each other. + +```yaml +--- +production: + type: git + remote: git@github.com:puppetlabs/control-repo.git + ref: 8820892 + +development: + type: git + remote: git@github.com:puppetlabs/control-repo.git + ref: 8820892 +``` + +### Environment Modules + +The environment modules feature allows module content to be attached to an environment at environment definition time. This happens before modules specified in a Puppetfile are attached to an environment, which does not happen until deploy time. Environment module implementation depends on the environment source type. + +For the YAML environment source type, attach modules to an environment by specifying a modules key for the environment, and providing a hash of modules to attach. Each module accepts the same arguments accepted by the `mod` method in a Puppetfile. + +The example below includes two Forge modules and one module sourced from a Git repository. The two environments are almost identical. However, a new version of the stdlib module has been deployed in development (6.2.0), that has not yet been deployed to production. + +```yaml +--- +production: + type: git + remote: git@github.com:puppetlabs/control-repo.git + ref: 8820892 + modules: + puppetlabs-stdlib: 6.0.0 + puppetlabs-concat: 6.1.0 + reidmv-xampl: + git: https://github.com/reidmv/reidmv-xampl.git + ref: 62d07f2 + +development: + type: git + remote: git@github.com:puppetlabs/control-repo.git + ref: 8820892 + modules: + puppetlabs-stdlib: 6.2.0 + puppetlabs-concat: 6.1.0 + reidmv-xampl: + git: https://github.com/reidmv/reidmv-xampl.git + ref: 62d07f2 +``` + +### Bare Environment Type + +A "control repository" typically contains a hiera.yaml, an environment.conf, a manifests/site.pp file, and a few other things. However, none of these are strictly necessary for an environment to be functional if modules can be deployed to it. + +The bare environment type allows sources that support environment modules to operate without a control repo being required. Modules can be deployed directly. + +```yaml +--- +production: + type: bare + modules: + puppetlabs-stdlib: 6.0.0 + puppetlabs-concat: 6.1.0 + reidmv-xampl: + git: https://github.com/reidmv/reidmv-xampl.git + ref: 62d07f2 + +development: + type: bare + modules: + puppetlabs-stdlib: 6.0.0 + puppetlabs-concat: 6.1.0 + reidmv-xampl: + git: https://github.com/reidmv/reidmv-xampl.git + ref: 62d07f2 +```