r10k 0.0.9 → 1.0.0rc1
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.
- data/bin/r10k +1 -1
- data/lib/r10k.rb +0 -4
- data/lib/r10k/cli.rb +9 -5
- data/lib/r10k/cli/deploy.rb +108 -0
- data/lib/r10k/cli/environment.rb +5 -1
- data/lib/r10k/cli/environment/deploy.rb +6 -28
- data/lib/r10k/cli/environment/list.rb +6 -10
- data/lib/r10k/cli/environment/stale.rb +6 -16
- data/lib/r10k/cli/module.rb +5 -1
- data/lib/r10k/cli/module/deploy.rb +5 -32
- data/lib/r10k/cli/module/list.rb +6 -27
- data/lib/r10k/cli/puppetfile.rb +76 -0
- data/lib/r10k/cli/synchronize.rb +8 -24
- data/lib/r10k/cli/version.rb +22 -0
- data/lib/r10k/deployment.rb +55 -26
- data/lib/r10k/deployment/config.rb +69 -0
- data/lib/r10k/{config → deployment/config}/loader.rb +9 -5
- data/lib/r10k/deployment/environment.rb +88 -0
- data/lib/r10k/deployment/source.rb +79 -0
- data/lib/r10k/errors.rb +3 -5
- data/lib/r10k/execution.rb +43 -0
- data/lib/r10k/git/cache.rb +131 -0
- data/lib/r10k/git/errors.rb +34 -0
- data/lib/r10k/git/repository.rb +74 -0
- data/lib/r10k/git/working_dir.rb +142 -0
- data/lib/r10k/logging.rb +6 -2
- data/lib/r10k/module.rb +10 -13
- data/lib/r10k/module/forge.rb +35 -22
- data/lib/r10k/module/git.rb +18 -8
- data/lib/r10k/puppetfile.rb +107 -0
- data/lib/r10k/task.rb +13 -0
- data/lib/r10k/task/deployment.rb +151 -0
- data/lib/r10k/task/environment.rb +29 -0
- data/lib/r10k/task/module.rb +18 -0
- data/lib/r10k/task/puppetfile.rb +99 -0
- data/lib/r10k/task_runner.rb +72 -0
- data/lib/r10k/util/purgeable.rb +50 -0
- data/lib/r10k/version.rb +1 -1
- data/spec/unit/deployment/environment_spec.rb +19 -0
- data/spec/unit/git/cache_spec.rb +37 -0
- data/spec/unit/git/working_dir_spec.rb +15 -0
- data/spec/unit/module/forge_spec.rb +95 -0
- data/spec/unit/module_spec.rb +29 -0
- metadata +79 -44
- data/lib/r10k/action.rb +0 -7
- data/lib/r10k/action/environment.rb +0 -74
- data/lib/r10k/action/module.rb +0 -36
- data/lib/r10k/cli/cache.rb +0 -32
- data/lib/r10k/config.rb +0 -46
- data/lib/r10k/deployment/environment_collection.rb +0 -75
- data/lib/r10k/librarian.rb +0 -31
- data/lib/r10k/librarian/dsl.rb +0 -20
- data/lib/r10k/root.rb +0 -98
- data/lib/r10k/synchro/git.rb +0 -226
data/lib/r10k/module.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
require 'r10k'
|
2
2
|
|
3
|
-
|
3
|
+
module R10K::Module
|
4
4
|
|
5
5
|
# Register an inheriting class for later generation
|
6
|
-
def self.
|
6
|
+
def self.included(klass)
|
7
|
+
klass.extend self
|
7
8
|
@klasses ||= []
|
8
9
|
@klasses << klass
|
9
10
|
end
|
@@ -16,28 +17,24 @@ class R10K::Module
|
|
16
17
|
# with `name, args`, and generates an object of that class.
|
17
18
|
#
|
18
19
|
# @param [String] name The unique name of the module
|
19
|
-
# @param [String]
|
20
|
+
# @param [String] basedir The root to install the module in
|
20
21
|
# @param [Object] args An arbitary value or set of values that specifies the implementation
|
21
22
|
#
|
22
23
|
# @return [Object < R10K::Module] A member of the implementing subclass
|
23
|
-
def self.new(name,
|
24
|
-
if implementation = @klasses.find { |klass| klass.
|
25
|
-
obj = implementation.
|
26
|
-
obj.send(:initialize, name, path, args)
|
24
|
+
def self.new(name, basedir, args)
|
25
|
+
if implementation = @klasses.find { |klass| klass.implement?(name, args) }
|
26
|
+
obj = implementation.new(name, basedir, args)
|
27
27
|
obj
|
28
28
|
else
|
29
29
|
raise "Module #{name} with args #{args.inspect} doesn't have an implementation. (Are you using the right arguments?)"
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
|
-
attr_accessor :name, :
|
34
|
-
|
35
|
-
def initialize(name, path, args)
|
36
|
-
@name, @path, @args = name, path, args
|
37
|
-
end
|
33
|
+
attr_accessor :name, :basedir
|
38
34
|
|
35
|
+
# @return [String] The full filesystem path to the module.
|
39
36
|
def full_path
|
40
|
-
File.join(@
|
37
|
+
File.join(@basedir, @name)
|
41
38
|
end
|
42
39
|
end
|
43
40
|
|
data/lib/r10k/module/forge.rb
CHANGED
@@ -7,70 +7,81 @@ require 'systemu'
|
|
7
7
|
require 'semver'
|
8
8
|
require 'json'
|
9
9
|
|
10
|
-
|
10
|
+
module R10K
|
11
|
+
module Module
|
12
|
+
class Forge
|
11
13
|
|
12
|
-
|
13
|
-
|
14
|
+
include R10K::Module
|
15
|
+
|
16
|
+
def self.implement?(name, args)
|
17
|
+
!!(name.match %r[\w+/\w+])
|
14
18
|
end
|
15
19
|
|
16
20
|
include R10K::Logging
|
17
21
|
|
18
|
-
|
19
|
-
super
|
22
|
+
attr_accessor :version, :owner, :full_name
|
20
23
|
|
24
|
+
def initialize(name, basedir, args)
|
21
25
|
@full_name = name
|
26
|
+
@basedir = basedir
|
22
27
|
|
23
28
|
@owner, @name = name.split('/')
|
24
|
-
|
29
|
+
|
30
|
+
if args.is_a? String
|
31
|
+
@version = SemVer.new(args)
|
32
|
+
end
|
25
33
|
end
|
26
34
|
|
27
|
-
def sync
|
35
|
+
def sync(options = {})
|
28
36
|
return if insync?
|
29
37
|
|
30
38
|
if insync?
|
31
|
-
logger.debug1 "Module #{@full_name} already matches version #{@version}"
|
39
|
+
#logger.debug1 "Module #{@full_name} already matches version #{@version}"
|
32
40
|
elsif File.exist? metadata_path
|
33
|
-
logger.debug "Module #{@full_name} is installed but doesn't match version #{@version}, upgrading"
|
41
|
+
#logger.debug "Module #{@full_name} is installed but doesn't match version #{@version}, upgrading"
|
34
42
|
cmd = []
|
35
43
|
cmd << 'upgrade'
|
36
|
-
cmd << "--version=#{@version}"
|
44
|
+
cmd << "--version=#{@version}" if @version
|
37
45
|
cmd << "--ignore-dependencies"
|
38
46
|
cmd << @full_name
|
39
47
|
pmt cmd
|
40
48
|
else
|
41
|
-
logger.debug "Module #{@full_name} is not installed"
|
49
|
+
#logger.debug "Module #{@full_name} is not installed"
|
42
50
|
cmd = []
|
43
51
|
cmd << 'install'
|
44
|
-
cmd << "--version=#{@version}"
|
52
|
+
cmd << "--version=#{@version}" if @version
|
45
53
|
cmd << "--ignore-dependencies"
|
46
54
|
cmd << @full_name
|
47
55
|
pmt cmd
|
48
56
|
end
|
49
57
|
end
|
50
58
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
59
|
+
# @return [SemVer, NilClass]
|
60
|
+
def version
|
61
|
+
if metadata
|
62
|
+
SemVer.new(metadata['version'])
|
63
|
+
else
|
64
|
+
SemVer::MIN
|
65
|
+
end
|
55
66
|
end
|
56
67
|
|
57
68
|
def insync?
|
58
|
-
@version ==
|
59
|
-
rescue
|
60
|
-
false
|
69
|
+
@version == version
|
61
70
|
end
|
62
71
|
|
63
72
|
def metadata
|
64
|
-
JSON.parse(File.read(metadata_path))
|
73
|
+
@metadata = JSON.parse(File.read(metadata_path)) rescue nil
|
65
74
|
end
|
66
75
|
|
67
76
|
def metadata_path
|
68
77
|
File.join(full_path, 'metadata.json')
|
69
78
|
end
|
70
79
|
|
80
|
+
private
|
81
|
+
|
71
82
|
def pmt(args)
|
72
|
-
cmd = "puppet module --modulepath '#{@
|
73
|
-
log_event = "puppet module #{args.join(' ')}, modulepath: #{@
|
83
|
+
cmd = "puppet module --modulepath '#{@basedir}' #{args.join(' ')}"
|
84
|
+
log_event = "puppet module #{args.join(' ')}, modulepath: #{@basedir.inspect}"
|
74
85
|
logger.debug1 "Execute: #{cmd}"
|
75
86
|
|
76
87
|
status, stdout, stderr = systemu(cmd)
|
@@ -88,3 +99,5 @@ class R10K::Module::Forge < R10K::Module
|
|
88
99
|
stdout
|
89
100
|
end
|
90
101
|
end
|
102
|
+
end
|
103
|
+
end
|
data/lib/r10k/module/git.rb
CHANGED
@@ -1,24 +1,34 @@
|
|
1
1
|
require 'r10k'
|
2
2
|
require 'r10k/module'
|
3
|
-
require 'r10k/
|
3
|
+
require 'r10k/git/working_dir'
|
4
|
+
require 'forwardable'
|
4
5
|
|
5
|
-
|
6
|
+
module R10K
|
7
|
+
module Module
|
8
|
+
class Git
|
9
|
+
include R10K::Module
|
6
10
|
|
7
|
-
def self.
|
11
|
+
def self.implement?(name, args)
|
8
12
|
args.is_a? Hash and args.has_key?(:git)
|
9
13
|
rescue
|
10
14
|
false
|
11
15
|
end
|
12
16
|
|
13
|
-
|
14
|
-
|
17
|
+
extend Forwardable
|
18
|
+
def_delegator :@working_dir, :sync
|
19
|
+
|
20
|
+
def initialize(name, basedir, args)
|
21
|
+
@name, @basedir, @args = name, basedir, args
|
15
22
|
|
16
23
|
@remote = @args[:git]
|
17
24
|
@ref = (@args[:ref] || 'master')
|
25
|
+
|
26
|
+
@working_dir = R10K::Git::WorkingDir.new(@ref, @remote, @basedir, @name)
|
18
27
|
end
|
19
28
|
|
20
|
-
def
|
21
|
-
|
22
|
-
synchro.sync(full_path, @ref, options)
|
29
|
+
def version
|
30
|
+
@ref
|
23
31
|
end
|
24
32
|
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
require 'r10k/module'
|
2
|
+
require 'r10k/logging'
|
3
|
+
require 'r10k/util/purgeable'
|
4
|
+
|
5
|
+
module R10K
|
6
|
+
class Puppetfile
|
7
|
+
# Defines the data members of a Puppetfile
|
8
|
+
|
9
|
+
include R10K::Logging
|
10
|
+
|
11
|
+
# @!attribute [r] forge
|
12
|
+
# @return [String] The URL to use for the Puppet Forge
|
13
|
+
attr_reader :forge
|
14
|
+
|
15
|
+
# @!attribute [r] modules
|
16
|
+
# @return [Array<R10K::Module>]
|
17
|
+
attr_reader :modules
|
18
|
+
|
19
|
+
# @!attribute [r] basedir
|
20
|
+
# @return [String] The base directory that contains the Puppetfile
|
21
|
+
attr_reader :basedir
|
22
|
+
|
23
|
+
# @!attribute [r] moduledir
|
24
|
+
# @return [String] The directory to install the modules #{basedir}/modules
|
25
|
+
attr_reader :moduledir
|
26
|
+
|
27
|
+
# @!attrbute [r] puppetfile_path
|
28
|
+
# @return [String] The path to the Puppetfile
|
29
|
+
attr_reader :puppetfile_path
|
30
|
+
|
31
|
+
# @param [String] basedir
|
32
|
+
# @param [String] puppetfile The path to the Puppetfile, default to #{basedir}/Puppetfile
|
33
|
+
def initialize(basedir, moduledir = nil, puppetfile = nil)
|
34
|
+
@basedir = basedir
|
35
|
+
@moduledir = moduledir || File.join(basedir, 'modules')
|
36
|
+
@puppetfile_path = puppetfile || File.join(basedir, 'Puppetfile')
|
37
|
+
|
38
|
+
@modules = []
|
39
|
+
@forge = 'forge.puppetlabs.com'
|
40
|
+
end
|
41
|
+
|
42
|
+
def load
|
43
|
+
if File.readable? @puppetfile_path
|
44
|
+
self.load!
|
45
|
+
else
|
46
|
+
logger.debug "Puppetfile #{@puppetfile_path.inspect} missing or unreadable"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def load!
|
51
|
+
dsl = R10K::Puppetfile::DSL.new(self)
|
52
|
+
dsl.instance_eval(puppetfile_contents, @puppetfile_path)
|
53
|
+
end
|
54
|
+
|
55
|
+
# @param [String] forge
|
56
|
+
def set_forge(forge)
|
57
|
+
@forge = forge
|
58
|
+
end
|
59
|
+
|
60
|
+
# @param [String] name
|
61
|
+
# @param [*Object] args
|
62
|
+
def add_module(name, args)
|
63
|
+
@modules << R10K::Module.new(name, @moduledir, args)
|
64
|
+
end
|
65
|
+
|
66
|
+
include R10K::Util::Purgeable
|
67
|
+
|
68
|
+
def managed_directory
|
69
|
+
@moduledir
|
70
|
+
end
|
71
|
+
|
72
|
+
# List all modules that should exist in the module directory
|
73
|
+
# @note This implements a required method for the Purgeable mixin
|
74
|
+
# @return [Array<String>]
|
75
|
+
def desired_contents
|
76
|
+
@modules.map { |mod| mod.name }
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
def puppetfile_contents
|
82
|
+
File.read(@puppetfile_path)
|
83
|
+
end
|
84
|
+
|
85
|
+
class DSL
|
86
|
+
# A barebones implementation of the Puppetfile DSL
|
87
|
+
#
|
88
|
+
# @api private
|
89
|
+
|
90
|
+
def initialize(librarian)
|
91
|
+
@librarian = librarian
|
92
|
+
end
|
93
|
+
|
94
|
+
def mod(name, args = [])
|
95
|
+
@librarian.add_module(name, args)
|
96
|
+
end
|
97
|
+
|
98
|
+
def forge(location)
|
99
|
+
@librarian.set_forge(location)
|
100
|
+
end
|
101
|
+
|
102
|
+
def method_missing(method, *args)
|
103
|
+
raise NoMethodError, "unrecognized declaration '#{method}'"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
data/lib/r10k/task.rb
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
require 'r10k/task'
|
2
|
+
require 'r10k/task_runner'
|
3
|
+
|
4
|
+
require 'r10k/task/environment'
|
5
|
+
require 'r10k/task/puppetfile'
|
6
|
+
|
7
|
+
module R10K
|
8
|
+
module Task
|
9
|
+
module Deployment
|
10
|
+
module SharedBehaviors
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def load_environments!
|
15
|
+
@environments = @deployment.environments.inject({}) do |hash, env|
|
16
|
+
hash[env.dirname] = env
|
17
|
+
hash
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# @param [Array<String>] names The list of environments to deploy.
|
22
|
+
#
|
23
|
+
def with_environments(names = [], &block)
|
24
|
+
load_environments!
|
25
|
+
|
26
|
+
# If an explicit list of environments were not given, deploy everything
|
27
|
+
if names.size > 0
|
28
|
+
to_deploy = names
|
29
|
+
else
|
30
|
+
to_deploy = @environments.keys
|
31
|
+
end
|
32
|
+
|
33
|
+
to_deploy.each do |env_name|
|
34
|
+
if (env = @environments[env_name])
|
35
|
+
yield env
|
36
|
+
else
|
37
|
+
logger.warn "Environment #{env_name} not found in any source"
|
38
|
+
task_runner.succeeded = false
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class DeployEnvironments < R10K::Task::Base
|
45
|
+
|
46
|
+
include SharedBehaviors
|
47
|
+
|
48
|
+
# @!attribute environment_names
|
49
|
+
# @return [Array<String>] A list of environments to deploy, by name.
|
50
|
+
attr_accessor :environment_names
|
51
|
+
|
52
|
+
# @!attribute update_puppetfile
|
53
|
+
# @return [TrueClass, FalseClass] Whether to deploy modules in a puppetfile
|
54
|
+
attr_accessor :update_puppetfile
|
55
|
+
|
56
|
+
def initialize(deployment)
|
57
|
+
@deployment = deployment
|
58
|
+
@update_puppetfile = false
|
59
|
+
@environment_names = []
|
60
|
+
end
|
61
|
+
|
62
|
+
def call
|
63
|
+
logger.info "Loading environments from all sources"
|
64
|
+
@deployment.fetch_sources
|
65
|
+
|
66
|
+
with_environments(@environment_names) do |env|
|
67
|
+
task = R10K::Task::Environment::Deploy.new(env)
|
68
|
+
task.update_puppetfile = @update_puppetfile
|
69
|
+
task_runner.insert_task_after(self, task)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
class DeployModules < R10K::Task::Base
|
75
|
+
|
76
|
+
include SharedBehaviors
|
77
|
+
|
78
|
+
attr_accessor :module_names
|
79
|
+
|
80
|
+
# @!attribute environment_names
|
81
|
+
# @return [Array<String>] A list of environments to update modules
|
82
|
+
attr_accessor :environment_names
|
83
|
+
|
84
|
+
def initialize(deployment)
|
85
|
+
@deployment = deployment
|
86
|
+
@environment_names = []
|
87
|
+
end
|
88
|
+
|
89
|
+
def call
|
90
|
+
with_environments(@environment_names) do |env|
|
91
|
+
puppetfile = env.puppetfile
|
92
|
+
|
93
|
+
task = R10K::Task::Puppetfile::DeployModules.new(puppetfile)
|
94
|
+
task.module_names = module_names
|
95
|
+
|
96
|
+
task_runner.insert_task_after(self, task)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
class PurgeEnvironments < R10K::Task::Base
|
102
|
+
|
103
|
+
def initialize(deployment)
|
104
|
+
@deployment = deployment
|
105
|
+
end
|
106
|
+
|
107
|
+
def call
|
108
|
+
@deployment.sources.each do |source|
|
109
|
+
stale_envs = source.stale_contents
|
110
|
+
|
111
|
+
dir = source.managed_directory
|
112
|
+
|
113
|
+
if stale_envs.empty?
|
114
|
+
logger.debug "No stale environments in #{dir}"
|
115
|
+
else
|
116
|
+
logger.info "Purging stale environments from #{dir}"
|
117
|
+
logger.debug "Stale modules in #{dir}: #{stale_envs.join(', ')}"
|
118
|
+
source.purge!
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
class Display < R10K::Task::Base
|
125
|
+
|
126
|
+
attr_accessor :puppetfile
|
127
|
+
|
128
|
+
def initialize(deployment)
|
129
|
+
@deployment = deployment
|
130
|
+
end
|
131
|
+
|
132
|
+
def call
|
133
|
+
@deployment.environments.each do |env|
|
134
|
+
|
135
|
+
puts " - #{env.dirname}"
|
136
|
+
|
137
|
+
if @puppetfile
|
138
|
+
puppetfile = env.puppetfile
|
139
|
+
puppetfile.load
|
140
|
+
|
141
|
+
puppetfile.modules.each do |mod|
|
142
|
+
puts " - #{mod.name} (#{mod.version})"
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|