r10k 1.2.1 → 1.2.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- NzM2NDQyNzM1Y2I0Zjc5ZmUzNmEyZDA0MTJiMzZjM2E2MWNhNWJhMw==
4
+ MzBlNGU0MTQxMjk1ODQzM2ZkOGMzNmEyYjFmZTVkMGIzY2RiMzk5OQ==
5
5
  data.tar.gz: !binary |-
6
- NmRkYWZiZDYxNGEyNTZiZDgzZDQwMjEzYjQ0MjA2MjgxNjE0MjRlMw==
6
+ NTc0ZWVhNjdiZGZjZWNlZTUyZjQ3OTU5ZGMxZWI1NDAzN2Q4YTQ1ZQ==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- YWE2ZTg3ZDI1YzA4YTlkNTFlNjQ2MDIzZDU1YWNjZGExMjY3NTY5NGRhN2Fm
10
- MTNhNDA4NzY1YTNkODM4ZjQ4NTI4ZmRiOTEwNDIwZWYwOWNiN2VhZWE3M2My
11
- NDE4MGY0M2ZiZjcyOGI2Y2UyNWU5ZWRjNjlhZGJkZDc4ZjZlMGY=
9
+ ODk2YzRlZGZhOGEwNmMyYTgzMzNjMTY0YzI4OTZjZTc5ZjA3MWYwNTViMTA1
10
+ MmNmMDhjMDUzMDRkYzQ2ZmY5NWRkNmQ3ZWU1YWRkMDZkYTdmOWYxZWYzOGVh
11
+ ZjU1MzY3MjU1OTgzNTk0ZmIyYzYwYjE0YjA5N2I4YWIwNTNjYjA=
12
12
  data.tar.gz: !binary |-
13
- NzM5YmU2ODRlNzg2NGEzMzQ3NjBmODIzYzE4MmUzM2NkYmRmYmExOTBhMWNk
14
- NGNhMjI5Njc3MGEyNWVjYjg3NTNmMjJkOTY0ZTAzMDM3NzQ5YzhlYjlhZDI0
15
- Yzg5MDQ0MDNlNmI5NjlhNGQwZTRiMGRhM2ZkNDI3MWM4Zjk2OGQ=
13
+ ZDUzYzQ1Yjg3Njk2NjA1YmM2YjVhN2JjNDkyYjY3OTU5YWVkYmE1NGI0OGJl
14
+ MzQ3OGM2NDY2M2U3OGMwYjVkMGY3OTU4NjI0NTIyMjQyMDlmMzg2YzMyZDg2
15
+ OTQwMjI4NDVhZGQwYzMyOTkxNWYyZWEzNmQ5ZjYwNzUzNmU1YjI=
data/CHANGELOG CHANGED
@@ -1,6 +1,41 @@
1
1
  CHANGELOG
2
2
  =========
3
3
 
4
+ 1.2.2
5
+ -----
6
+
7
+ 2014/07/16
8
+
9
+ ### User Notes
10
+
11
+ (GH-165) `r10k puppetfile` only consumes handled command line options.
12
+
13
+ Previously, passing `-v` or other commands when running `r10k puppetfile *`
14
+ could result in this error:
15
+
16
+ r10k puppetfile install --help --trace
17
+ Error while running: #<RuntimeError: Unrecognized options: help>
18
+
19
+ This was due to overly greedy code passing in all options from the command line
20
+ to the TaskRunner. This has been fixed so only known options are passed along,
21
+ and options that aren't relevant (such as :verbose) will be ignored.
22
+
23
+ (GH-158) Log levels are now documented in the command line --help pages.
24
+
25
+ (GH-137) Git remotes are now correctly updated.
26
+
27
+ A regression in the Git remote handling meant that git remotes would never be
28
+ properly updated when switching Git environments and modules from one remote
29
+ to another, and the git alternates file was never updated properly. This has
30
+ been fixed so that when the Git remote is updated, all references to the
31
+ remotes and alternates will be updated.
32
+
33
+ (GH-163) All Git tags are deleted when switching Git remotes
34
+
35
+ Git tags cannot necessarily be transferred from one Git repository to another,
36
+ so when a Git repo has its remotes changed all tags are deleted to prevent stale
37
+ tags from overwriting tags from the new repo.
38
+
4
39
  1.2.1
5
40
  -----
6
41
 
@@ -0,0 +1,24 @@
1
+ Dynamic Environments
2
+ ====================
3
+
4
+ Dynamic environment deployment is the core functionality of r10k.
5
+
6
+ Table of contents
7
+ -----------------
8
+
9
+ * [Introduction](dynamic-environments/introduction/): A brief description of
10
+ what dynamic environments are and how they work.
11
+ * [Git environments](dynamic-environments/git-environments/) How r10k
12
+ implements dynamic environments using git
13
+ * [Configuration](dynamic-environments/configuration/) A reference of dynamic
14
+ environment configuration options and how they're used
15
+ * [Usage](dynamic-environments/usage/) A reference of r10k commands and how
16
+ they're used.
17
+
18
+ - - -
19
+
20
+ Community guides
21
+ ----------------
22
+
23
+ * [Building a Functional Puppet Workflow Part 3: Dynamic Environments with R10k](http://garylarizza.com/blog/2014/02/18/puppet-workflow-part-3/)
24
+ * [Puppet Infrastructure with r10k](http://terrarum.net/blog/puppet-infrastructure-with-r10k.html)
@@ -0,0 +1,177 @@
1
+ Dynamic Environment Configuration
2
+ =================================
3
+
4
+ r10k uses a configuration file to determine how dynamic environments should be
5
+ deployed.
6
+
7
+ Config file location
8
+ --------------------
9
+
10
+ By default r10k will try to read `/etc/r10k.yaml` for configuration settings.
11
+ You can specify an alternate configuration file by specifying the `--config`
12
+ option, like so:
13
+
14
+ r10k deploy -c /srv/puppet/r10k.yaml
15
+
16
+ General options
17
+ ---------------
18
+
19
+ ### cachedir
20
+
21
+ The 'cachedir' setting specifies where r10k should keep cached information.
22
+ Right now this is predominantly used for caching git repositories but will be
23
+ expanded as other subsystems can take advantage of caching.
24
+
25
+ For example:
26
+
27
+ ```yaml
28
+ ---
29
+ # Store all cache information in /var/cache
30
+ cachedir: '/var/cache/r10k'
31
+ ```
32
+
33
+ [prerun_command](http://docs.puppetlabs.com/references/latest/configuration.html#preruncommand)
34
+
35
+ The cachedir setting defaults to `~/.r10k'. If the HOME environment variable is
36
+ unset r10k will assume that r10k is being run with the Puppet [`prerun_command`][prerun_command]
37
+ setting and will set the cachedir default to `/root/.r10k`.
38
+
39
+ Deployment options
40
+ ------------------
41
+
42
+ The following options configure how r10k deploys dynamic environments.
43
+
44
+ ### sources
45
+
46
+ The `sources` setting specifies what repositories should be used for creating
47
+ dynamic environments. It is a hash where each key is the short name of a
48
+ specific repository (for instance, "qa" or "web" or "ops") and the value is a
49
+ hash of properties for that source.
50
+
51
+ ```yaml
52
+ ---
53
+ sources:
54
+ main:
55
+ # Source settings follow
56
+ ```
57
+
58
+ Source options
59
+ --------------
60
+
61
+ The following options are respected by all source implementations. Sources may
62
+ implement other options in addition to the ones listed below; see the source
63
+ specific documentation for more information.
64
+
65
+ ### remote
66
+
67
+ The 'remote' setting specifies where the source repository should be fetched
68
+ from. It may be any valid URL that the source may check out or clone. The remote
69
+ must be able to be fetched without any interactive input, eg usernames or
70
+ passwords cannot be prompted for in order to fetch the remote.
71
+
72
+ ```
73
+ ---
74
+ sources:
75
+ mysource:
76
+ remote: 'git://git-server.site/my-org/main-modules'
77
+ ```
78
+
79
+ ### basedir
80
+
81
+ The 'basedir' setting specifies where environments will be created for this
82
+ source. This directory will be entirely managed by r10k and any contents that
83
+ r10k did not put there will be _removed_.
84
+
85
+ ```yaml
86
+ ---
87
+ sources:
88
+ mysource:
89
+ basedir: '/etc/puppet/environments'
90
+ ```
91
+
92
+ R10k will not check to make sure that different sources collide in a single base
93
+ directory; if you are using multiple sources you are responsible for making sure
94
+ that they do not overwrite each other. See also the prefix setting.
95
+
96
+ ### prefix
97
+
98
+ The prefix setting allows environment names to be prefixed with the short name
99
+ of the given source. This prevents collisions when multiple sources are deployed
100
+ into the same directory.
101
+
102
+ ```yaml
103
+ ---
104
+ sources:
105
+ mysource:
106
+ basedir: '/etc/puppet/environments'
107
+ prefix: true # All environments will be prefixed with "mysource_"
108
+ ```
109
+
110
+ Examples
111
+ --------
112
+
113
+ ### Minimal example
114
+
115
+ The majority of users will only have a single repository where all modules and
116
+ hiera data files are kept. In this case you will specify a single source:
117
+
118
+ ```yaml
119
+ ---
120
+ sources:
121
+ operations:
122
+ remote: 'git://git-server.site/my-org/org-modules'
123
+ basedir: '/etc/puppet/environments'
124
+ ```
125
+
126
+ ### Separate hiera data
127
+
128
+ For more complex cases where you want to store hiera data in a different
129
+ repository and your modules in another repository, you can specify two sources:
130
+
131
+ ```yaml
132
+ ---
133
+ sources:
134
+ operations:
135
+ remote: 'git://git-server.site/my-org/org-modules'
136
+ basedir: '/etc/puppet/environments'
137
+ hiera:
138
+ remote: 'git://git-server.site/my-org/org-hiera-data'
139
+ basedir: '/etc/puppet/hiera-data'
140
+ ```
141
+
142
+ ### Multiple tenancy
143
+
144
+ Alternately you may want to create separate environments from multiple
145
+ repositories. This is useful when you want two groups to be able to deploy
146
+ Puppet modules but they should only have write access to their own modules and
147
+ not the modules of other groups.
148
+
149
+ ```yaml
150
+ ---
151
+ sources:
152
+ main:
153
+ remote: 'git://git-server.site/my-org/main-modules'
154
+ basedir: '/etc/puppet/environments'
155
+ prefix: false # Prefix defaults to false so this is only here for clarity
156
+ qa:
157
+ remote: 'git://git-server.site/my-org/qa-puppet-modules'
158
+ basedir: '/etc/puppet/environments'
159
+ prefix: true
160
+ dev:
161
+ remote: 'git://git-server.site/my-org/dev-puppet-modules'
162
+ basedir: '/etc/puppet/environments'
163
+ prefix: true
164
+ ```
165
+
166
+ This will create the following directory structure:
167
+
168
+ ```
169
+ /etc/puppet/environments
170
+ |-- production # main-modules repository, production branch
171
+ |-- upgrade_apache # main-modules repository, upgrade_apache branch
172
+ |-- qa_production # qa repository, production branch
173
+ |-- qa_jenkins_test # qa repository, jenkins_test branch
174
+ |-- dev_production # dev repository, production branch
175
+ `-- dev_loadtest # dev repository, loadtest branch
176
+ ```
177
+
@@ -0,0 +1,42 @@
1
+ Git Based Dynamic Environments
2
+ ==============================
3
+
4
+ r10k can use Git repositories to implement dynamic environments. You can create,
5
+ update, and delete Puppet environments automatically as part of your normal Git
6
+ workflow.
7
+
8
+ Dynamic Environments in a nutshell
9
+ ----------------------------------
10
+
11
+ The core idea of dynamic environments is that you should be able to manage your
12
+ Puppet modules in the same manner that you would manage any other code base. It
13
+ builds on top of Git topic branch model.
14
+
15
+ [git-topic-branching]: http://git-scm.com/book/en/Git-Branching-Branching-Workflows#Topic-Branches "Git Topic Branches"
16
+
17
+ One of the most prevalent ways of using Git relies on using [topic branches][git-topic-branching].
18
+ Whenever changes need to be made that need to be reviewed or tested before going
19
+ live, they should be done in a different, short lived branch called a topic
20
+ branch. Work can be freely done on a topic branch in isolation and when the work
21
+ is completed it is merged into a "master" or "production" branch. This is very
22
+ powerful because it allows any number of people to rapidly develop features in
23
+ isolation and merge features in a single operation.
24
+
25
+ The dynamic environment model extends extends this git branching strategy to
26
+ your live Puppet masters. It creates a mapping between Git branches and Puppet
27
+ environments so that you can use the Git branching model and have that be
28
+ seamlessly reflected in Puppet environments. This means that creating a new Git
29
+ branch creates a new Puppet environment, updating a Git branch will update that
30
+ environment, and deleting a Git branch will remove that environment.
31
+
32
+ How it works
33
+ ------------
34
+
35
+ r10k works by tracking the state of your git repositories and comparing them the
36
+ the currently deployed environments. If there's a Git branch that doesn't have a
37
+ corresponding Puppet environment then r10k will clone that branch into the
38
+ appropriate directory. When Git branches are updated r10k will update the
39
+ appropriate Puppet environment to the latest version. Finally if there are
40
+ Puppet environments that don't have matching Git branches, r10k will assume that
41
+ the branches for those environments were deleted and will remove those
42
+ environments.
@@ -0,0 +1,70 @@
1
+ Dynamic Environments
2
+ ====================
3
+
4
+ One of the most important functions of r10k is its ability to dynamically manage
5
+ your Puppet environments.
6
+
7
+ When environments were originally built into Puppet they were meant to be static
8
+ in nature. Each environment had to be defined beforehand in the master's
9
+ puppet.conf file in a section, like so:
10
+
11
+ ```ini
12
+ [master]
13
+ # Environment independent settings
14
+ vardir = '/var/lib/puppet'
15
+
16
+ [production]
17
+ modulepath = '/etc/puppet/environments/production/modules'
18
+
19
+ [testing]
20
+ modulepath = '/etc/puppet/environments/testing/modules'
21
+
22
+ [development]
23
+ modulepath = '/etc/puppet/environments/development/modules'
24
+ ```
25
+
26
+ Static Puppet environments were frequently used to implement a pipeline for
27
+ developing Puppet code. New Puppet code would be developed and deployed to the
28
+ development environment, pushed to testing for validation, and then finally
29
+ pushed to the production for general deployment.
30
+
31
+ This static nature of Puppet environments turned out to be inflexible in
32
+ practice. With a predefined list of environments it could be very cumbersome to
33
+ develop on different parts of a Puppet codebase in isolation; you could either
34
+ develop multiple features in the same environment and risk cross pollution, or
35
+ manually create new environments every time you needed isolation.
36
+
37
+ Dynamic environments work by dynamically determining the settings for Puppet
38
+ environment when the environment is used, rather than by defining an explicit
39
+ section in puppet.conf. This works by making the current environment (in the
40
+ '$environment' variable) part of of the path to environment specific settings,
41
+ like modulepath, manifest, and so forth.
42
+
43
+ ```ini
44
+ [master]
45
+ vardir = '/var/lib/puppet'
46
+ modulepath = '/etc/puppet/environments/$environment/modules'
47
+ ```
48
+
49
+ Running `puppet agent -t --environment myenv` will cause $environment to be
50
+ expanded to 'myenv', so the modulepath for that environment will be set to
51
+ '/etc/puppet/environments/myenv/modules'.
52
+
53
+ This approach of allowing environments to be defined on the fly is a complete
54
+ reversal of the original architecture of environments. This approach means that
55
+ it can be very easy to create new environments, update existing environments,
56
+ and remove environments that aren't needed anymore. It's common practice
57
+ to create a temporary environment to test an idea and destroy it shortly after.
58
+ R10k is designed to enable this sort of fluid workflow.
59
+
60
+ R10k predominantly uses version control systems to implement dynamic
61
+ environments. This works by inspecting the VCS repositories containing your
62
+ Puppet code and checking out that code on your masters so, that there's a 1:1
63
+ connection between a branch in your VCS repository and a Puppet environment on
64
+ your masters. This approach allows you to define the way you want to work and
65
+ use that with your chosen VCS, and r10k will make Puppet implement that
66
+ workflow.
67
+
68
+ Different version control systems will implement dynamic environments in
69
+ slightly different ways; check out the VCS specific documentation for more
70
+ information.
@@ -0,0 +1,75 @@
1
+ Usage
2
+ =====
3
+
4
+ R10k provides fairly fine grained controls over your environments to fit your
5
+ needs. If you want to do a full update of all of your environments and modules
6
+ and don't need it to be done in real time, you can trigger a full update and let
7
+ it run in the background. If you are actively developing code and need to run
8
+ very fast updates of one specific environment, you can do a targeted update of
9
+ that code as well.
10
+
11
+ All commands that deal with deploying environments are grouped under the `r10k
12
+ deploy` subcommand.
13
+
14
+ Command line invocation
15
+ -----------------------
16
+
17
+ ### Deploying environments
18
+
19
+ Recursively update all environments:
20
+
21
+ r10k deploy environment --puppetfile
22
+
23
+ The simplest way to use r10k is by simply updating all environments and modules
24
+ and takes the brute force approach of "update everything, ever." When this
25
+ command is run r10k will update all sources, create new environments and delete
26
+ old environments, and recursively update all environment modules specified in
27
+ environment Puppetfiles. While this is the simplest method for running r10k, is
28
+ is also the slowest by a very large degree because it does the maximum possible
29
+ work. This should not be something you run interactively, or use on a regular
30
+ basis.
31
+
32
+ - - -
33
+
34
+ Update environments while avoiding unnecessary recursion
35
+
36
+ r10k deploy environment
37
+
38
+ This will update existing environments and recursively create new environments.
39
+ Note that when an environment is deployed for the first time, it will
40
+ automatically update all modules as well. For subsequent updates only the
41
+ environment itself will be updated.
42
+
43
+ - - -
44
+
45
+ Update a single environment:
46
+
47
+ r10k deploy environment my_working_environment
48
+
49
+ When you're actively developing on a given environment, this is the best way to
50
+ deploy your changes. Note that when an environment is deployed for the first
51
+ time, it will automatically update all modules as well. For subsequent updates
52
+ only the environment itself will be updated.
53
+
54
+ - - -
55
+
56
+ Update a single environment and force an update of modules:
57
+
58
+ r10k deploy environment my_working_environment --puppetfile
59
+
60
+ This will update the given environment and update all contained modules. This is
61
+ useful if you want to make sure that a given environment is fully up to date.
62
+
63
+ ### Deploying modules
64
+
65
+ Update a single module across all environments
66
+
67
+ r10k deploy module apache
68
+
69
+ This is useful for when you're working on a module specified in a Puppetfile and want to update it across all environments.
70
+
71
+ - - -
72
+
73
+ Update multiple modules across all environments
74
+
75
+ r10k deploy module apache jenkins java
data/lib/r10k/cli.rb CHANGED
@@ -16,10 +16,23 @@ module R10K::CLI
16
16
  complex environments.
17
17
  EOD
18
18
 
19
- flag :h, :help, 'Show help for this command'
19
+
20
+ flag :h, :help, 'Show help for this command' do |value, cmd|
21
+ # This is evil because we may not necessarily be called from the
22
+ # command line and have a meaningful ARGV to scan. However the best
23
+ # way of having a globally useful --help command is to define the
24
+ # behavior in the block of the option to immediately handle it and exit
25
+ # and we don't have access to the verbose option, so the simple method
26
+ # is to simply scan ARGV.
27
+ verbose = (ARGV.include?('-v') || ARGV.include?('--verbose'))
28
+ puts cmd.help(:verbose => verbose)
29
+ exit 0
30
+ end
31
+
20
32
  flag :t, :trace, 'Display stack traces on application crash'
21
33
 
22
- optional :v, :verbose, 'Set verbosity level' do |value, cmd|
34
+ loglevels = R10K::Logging::LOG_LEVELS.reverse.map(&:downcase).join(", ")
35
+ optional :v, :verbose, "Set log verbosity. Valid values: #{loglevels}" do |value, cmd|
23
36
  case value
24
37
  when true
25
38
  R10K::Logging.level = 'INFO'
@@ -51,10 +51,6 @@ scheduled. On subsequent deployments, Puppetfile deployment will default to off.
51
51
  DESCRIPTION
52
52
 
53
53
  flag :p, :puppetfile, 'Deploy modules from a puppetfile'
54
- flag :h, :help, 'Show help for this command' do |value, cmd|
55
- puts cmd.help
56
- exit 0
57
- end
58
54
 
59
55
  run do |opts, args, cmd|
60
56
  deploy = R10K::Deployment.load_config(opts[:config])
@@ -90,11 +86,6 @@ It will load the Puppetfile configurations out of all environments, and will
90
86
  try to deploy the given module names in all environments.
91
87
  DESCRIPTION
92
88
 
93
- flag :h, :help, 'Show help for this command' do |value, cmd|
94
- puts cmd.help
95
- exit 0
96
- end
97
-
98
89
  run do |opts, args, cmd|
99
90
  deploy = R10K::Deployment.load_config(opts[:config])
100
91
 
@@ -120,10 +111,6 @@ try to deploy the given module names in all environments.
120
111
  summary 'Display environments and modules in the deployment'
121
112
 
122
113
  flag :p, :puppetfile, 'Display Puppetfile modules'
123
- flag :h, :help, 'Show help for this command' do |value, cmd|
124
- puts cmd.help
125
- exit 0
126
- end
127
114
 
128
115
  run do |opts, args, cmd|
129
116
  deploy = R10K::Deployment.load_config(opts[:config])
@@ -37,7 +37,7 @@ Puppetfile (http://bombasticmonkey.com/librarian-puppet/).
37
37
 
38
38
  puppetfile = R10K::Puppetfile.new(puppetfile_root, puppetfile_path, puppetfile)
39
39
 
40
- runner = R10K::TaskRunner.new(opts)
40
+ runner = R10K::TaskRunner.new(:trace => opts[:trace])
41
41
  task = R10K::Task::Puppetfile::Sync.new(puppetfile)
42
42
  runner.append_task task
43
43
 
@@ -90,7 +90,7 @@ Puppetfile (http://bombasticmonkey.com/librarian-puppet/).
90
90
 
91
91
  puppetfile = R10K::Puppetfile.new(puppetfile_root, puppetfile_path, puppetfile)
92
92
 
93
- runner = R10K::TaskRunner.new(opts)
93
+ runner = R10K::TaskRunner.new(:trace => opts[:trace])
94
94
  task = R10K::Task::Puppetfile::Purge.new(puppetfile)
95
95
  runner.append_task task
96
96
 
data/lib/r10k/git.rb CHANGED
@@ -10,6 +10,7 @@ module R10K
10
10
 
11
11
  require 'r10k/git/repository'
12
12
  require 'r10k/git/cache'
13
+ require 'r10k/git/alternates'
13
14
  require 'r10k/git/working_dir'
14
15
  end
15
16
  end
@@ -0,0 +1,49 @@
1
+ require 'pathname'
2
+
3
+ # Manage `$GIT_DIR/objects/info/alternates`
4
+ #
5
+ # @see man gitrepository-layout(5)
6
+ class R10K::Git::Alternates
7
+
8
+ # @attribute [r] file
9
+ # @return [Pathname] The alternates file
10
+ attr_reader :file
11
+
12
+ # @param git_dir [String] The path to the git repository
13
+ def initialize(git_dir)
14
+ @file = Pathname.new(File.join(git_dir, 'objects', 'info', 'alternates'))
15
+ end
16
+
17
+ def to_a
18
+ read()
19
+ end
20
+
21
+ def <<(path)
22
+ write(to_a << path)
23
+ end
24
+
25
+ def include?(path)
26
+ to_a.include?(path)
27
+ end
28
+
29
+ private
30
+
31
+ def write(entries)
32
+ if ! @file.parent.directory?
33
+ raise R10K::Git::GitError, "Cannot write #{@file.to_path}; parent directory does not exist"
34
+ end
35
+ @file.open("w") do |fh|
36
+ entries.each do |entry|
37
+ fh.puts(entry)
38
+ end
39
+ end
40
+ end
41
+
42
+ def read
43
+ entries = []
44
+ if @file.file?
45
+ entries = @file.readlines.map(&:chomp)
46
+ end
47
+ entries
48
+ end
49
+ end
@@ -84,7 +84,7 @@ class R10K::Git::Repository
84
84
 
85
85
  ret = {}
86
86
  output.stdout.each_line do |line|
87
- next if line.match /\(push\)/
87
+ next if line.match(/\(push\)/)
88
88
  name, url, _ = line.split(/\s+/)
89
89
  ret[name] = url
90
90
  end
@@ -92,6 +92,13 @@ class R10K::Git::Repository
92
92
  ret
93
93
  end
94
94
 
95
+ def tags
96
+ entries = []
97
+ output = git(['tag', '-l'], :git_dir => @git_dir).stdout
98
+ output.each_line { |line| entries << line.chomp }
99
+ entries
100
+ end
101
+
95
102
  private
96
103
 
97
104
  # Fetch objects and refs from the given git remote
@@ -41,7 +41,8 @@ class R10K::Git::WorkingDir < R10K::Git::Repository
41
41
  @full_path = File.join(@basedir, @dirname)
42
42
  @git_dir = File.join(@full_path, '.git')
43
43
 
44
- @cache = R10K::Git::Cache.generate(@remote)
44
+ @alternates = R10K::Git::Alternates.new(@git_dir)
45
+ @cache = R10K::Git::Cache.generate(@remote)
45
46
 
46
47
  if ref.is_a? String
47
48
  @ref = R10K::Git::Ref.new(ref, self)
@@ -61,7 +62,9 @@ class R10K::Git::WorkingDir < R10K::Git::Repository
61
62
  end
62
63
 
63
64
  def update
64
- if fetch?
65
+ update_remotes if update_remotes?
66
+
67
+ if ref_needs_fetch?
65
68
  fetch_from_cache
66
69
  checkout(@ref)
67
70
  elsif needs_checkout?
@@ -114,22 +117,17 @@ class R10K::Git::WorkingDir < R10K::Git::Repository
114
117
 
115
118
  private
116
119
 
117
- def fetch?
120
+ # Do we need to fetch additional objects and refs in order to resolve the given ref?
121
+ # @return [true, false]
122
+ def ref_needs_fetch?
118
123
  @ref.fetch?
119
124
  end
120
125
 
121
126
  def fetch_from_cache
122
- set_cache_remote
123
127
  @cache.sync
124
128
  fetch('cache')
125
129
  end
126
130
 
127
- def set_cache_remote
128
- if self.remote != @cache.remote
129
- git ["remote", "set-url", "cache", @cache.git_dir], :path => @full_path
130
- end
131
- end
132
-
133
131
  # Perform a non-bare clone of a git repository.
134
132
  def clone
135
133
  @cache.sync
@@ -151,6 +149,30 @@ class R10K::Git::WorkingDir < R10K::Git::Repository
151
149
  expected = ref.sha1
152
150
  actual = rev_parse('HEAD')
153
151
 
154
- ! (expected == actual)
152
+ !(expected == actual)
153
+ end
154
+
155
+ def update_remotes?
156
+ real_remotes = remotes
157
+
158
+ expected_origin = @remote
159
+ expected_cache = @cache.git_dir
160
+
161
+ !(expected_origin == real_remotes['origin'] and expected_cache == real_remotes['cache'])
162
+ end
163
+
164
+ def update_remotes
165
+ # todo: remove all existing refs as they may belong to the old remote
166
+ git ['remote', 'set-url', 'origin', remote], :path => @full_path
167
+ git ['remote', 'set-url', 'cache', @cache.git_dir], :path => @full_path
168
+ @alternates << File.join(@cache.git_dir, 'objects')
169
+ logger.debug("Removing stale git tags from #{@full_path}")
170
+ remove_tags
171
+ end
172
+
173
+ def remove_tags
174
+ tags.each do |tag|
175
+ git ['tag', '-d', tag], :path => @full_path
176
+ end
155
177
  end
156
178
  end
data/lib/r10k/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module R10K
2
- VERSION = '1.2.1'
2
+ VERSION = '1.2.2'
3
3
  end
@@ -0,0 +1,90 @@
1
+ require 'spec_helper'
2
+ require 'stringio'
3
+ require 'r10k/git'
4
+
5
+ describe R10K::Git::Alternates do
6
+ subject { described_class.new("/some/nonexistent/path/.git") }
7
+
8
+ it "interacts with the alternates file in the given git repository" do
9
+ expect(subject.file.to_path).to eq("/some/nonexistent/path/.git/objects/info/alternates")
10
+ end
11
+
12
+ describe "reading alternate object entries" do
13
+ it "reads the alternates file and splits on lines" do
14
+ expect(subject.file).to receive(:file?).and_return true
15
+ expect(subject.file).to receive(:readlines).and_return([
16
+ "/var/cache/r10k/git/git---github.com-puppetlabs-puppetlabs-apache.git\n",
17
+ "/vagrant/.r10k/git/git---github.com-puppetlabs-puppetlabs-apache.git\n",
18
+ ])
19
+
20
+ expect(subject.to_a).to eq([
21
+ "/var/cache/r10k/git/git---github.com-puppetlabs-puppetlabs-apache.git",
22
+ "/vagrant/.r10k/git/git---github.com-puppetlabs-puppetlabs-apache.git",
23
+ ])
24
+ end
25
+
26
+ it "returns an empty array when the file is not present" do
27
+ expect(subject.file).to receive(:file?).and_return false
28
+ expect(subject.file).to receive(:readlines).never
29
+ expect(subject.to_a).to eq([])
30
+ end
31
+ end
32
+
33
+ describe "determining if an entry is already present" do
34
+ before do
35
+ allow(subject).to receive(:to_a).and_return([
36
+ "/var/cache/r10k/git/git---github.com-puppetlabs-puppetlabs-apache.git",
37
+ "/vagrant/.r10k/git/git---github.com-puppetlabs-puppetlabs-apache.git",
38
+ ])
39
+ end
40
+
41
+ it "is true if the element is in the array of read entries" do
42
+ expect(subject).to include("/vagrant/.r10k/git/git---github.com-puppetlabs-puppetlabs-apache.git")
43
+ end
44
+
45
+ it "is false if the element is not in the array of read entries" do
46
+ expect(subject).to_not include("/tmp/.r10k/git/git---github.com-puppetlabs-puppetlabs-apache.git")
47
+ end
48
+ end
49
+
50
+ describe "appending a new alternate object entry" do
51
+ describe "and the git objects/info directory does not exist" do
52
+ it "raises an error when the parent directory does not exist" do
53
+ expect {
54
+ subject << "/tmp/.r10k/git/git---github.com-puppetlabs-puppetlabs-apache.git"
55
+ }.to raise_error(R10K::Git::GitError,"Cannot write /some/nonexistent/path/.git/objects/info/alternates; parent directory does not exist")
56
+ end
57
+ end
58
+
59
+ describe "and the git objects/info directory exists" do
60
+ let(:io) { StringIO.new }
61
+
62
+ before do
63
+ expect(subject.file).to receive(:open).with('w').and_yield(io)
64
+ subject.file.stub_chain(:parent, :directory?).and_return true
65
+ end
66
+
67
+
68
+ it "creates the alternates file with the new entry when not present" do
69
+ expect(subject).to receive(:to_a).and_return([])
70
+ subject << "/tmp/.r10k/git/git---github.com-puppetlabs-puppetlabs-apache.git"
71
+
72
+ expect(io.string).to eq("/tmp/.r10k/git/git---github.com-puppetlabs-puppetlabs-apache.git\n")
73
+ end
74
+
75
+ it "rewrites the file with all alternate entries" do
76
+ expect(subject).to receive(:to_a).and_return([
77
+ "/var/cache/r10k/git/git---github.com-puppetlabs-puppetlabs-apache.git",
78
+ "/vagrant/.r10k/git/git---github.com-puppetlabs-puppetlabs-apache.git",
79
+ ])
80
+ subject << "/tmp/.r10k/git/git---github.com-puppetlabs-puppetlabs-apache.git"
81
+
82
+ expect(io.string).to eq(<<-EOD)
83
+ /var/cache/r10k/git/git---github.com-puppetlabs-puppetlabs-apache.git
84
+ /vagrant/.r10k/git/git---github.com-puppetlabs-puppetlabs-apache.git
85
+ /tmp/.r10k/git/git---github.com-puppetlabs-puppetlabs-apache.git
86
+ EOD
87
+ end
88
+ end
89
+ end
90
+ end
@@ -21,4 +21,14 @@ describe R10K::Git::Repository do
21
21
  })
22
22
  end
23
23
  end
24
+
25
+ describe "tags" do
26
+ let(:tags) { %w[0.1.1 0.1.2 0.1.3 0.1.4 0.2.0 0.3.0 2.0.0] }
27
+ let(:output) { tags.map {|x| x + "\n"}.join }
28
+
29
+ it "returns a list of tags for this repo" do
30
+ expect(subject).to receive(:git).with(%w[tag -l], anything).and_return(double(:stdout => output))
31
+ expect(subject.tags).to eq(tags)
32
+ end
33
+ end
24
34
  end
@@ -2,11 +2,120 @@ require 'spec_helper'
2
2
  require 'r10k/git'
3
3
 
4
4
  describe R10K::Git::WorkingDir do
5
+ include_context "fail on execution"
5
6
 
6
7
  describe "initializing" do
7
8
  it "generates a new cache for the remote" do
8
- wd = described_class.new('master', 'git://github.com/adrienthebo/r10k-fixture-repo', '/tmp')
9
+ wd = described_class.new('master', 'git://github.com/adrienthebo/r10k-fixture-repo', '/some/nonexistent/dir')
9
10
  wd.cache.should be_kind_of R10K::Git::Cache
10
11
  end
12
+
13
+ it "uses the provided ref as the dirname when no dirname is given" do
14
+ wd = described_class.new('master', 'git://github.com/adrienthebo/r10k-fixture-repo', '/some/nonexistent/dir')
15
+ expect(wd.dirname).to eq('master')
16
+ end
17
+
18
+ it "uses an explicit dirname when given" do
19
+ wd = described_class.new('master', 'git://github.com/adrienthebo/r10k-fixture-repo', '/some/nonexistent/dir', 'mydir')
20
+ expect(wd.dirname).to eq('mydir')
21
+ end
22
+ end
23
+
24
+ describe "synchronizing the working directory" do
25
+ subject { described_class.new('master', 'git://github.com/adrienthebo/r10k-fixture-repo', '/some/nonexistent/dir') }
26
+ it "clones the repository when the repository doesn't exist" do
27
+ expect(subject).to receive(:cloned?).and_return false
28
+ expect(subject).to receive(:clone)
29
+ subject.sync
30
+ end
31
+
32
+ it "updates the repository when the repository already exists" do
33
+ expect(subject).to receive(:cloned?).and_return true
34
+ expect(subject).to receive(:update)
35
+ subject.sync
36
+ end
37
+ end
38
+
39
+ describe "when cloning a new repository" do
40
+ subject { described_class.new('master', 'git://github.com/adrienthebo/r10k-fixture-repo', '/some/nonexistent/dir') }
41
+
42
+ before do
43
+ allow(subject).to receive(:cloned?).and_return false
44
+ end
45
+
46
+ it "updates the cache before cloning" do
47
+ expect(subject.cache).to receive(:sync)
48
+ allow(subject).to receive(:git)
49
+ allow(subject).to receive(:checkout)
50
+ subject.sync
51
+ end
52
+
53
+ it "clones the repository and uses the cache git dir as an object reference" do
54
+ allow(subject.cache).to receive(:sync)
55
+ expect(subject).to receive(:git).with(['clone', '--reference', subject.cache.git_dir,
56
+ 'git://github.com/adrienthebo/r10k-fixture-repo',
57
+ '/some/nonexistent/dir/master'])
58
+ expect(subject).to receive(:git).with(['remote', 'add', 'cache', subject.cache.git_dir],
59
+ an_instance_of(Hash))
60
+
61
+ expect(subject).to receive(:git).with(['fetch', 'cache'], an_instance_of(Hash))
62
+ allow(subject).to receive(:checkout)
63
+ subject.sync
64
+ end
65
+
66
+ it 'checks out the specific ref after the clone' do
67
+ allow(subject.cache).to receive(:sync)
68
+ allow(subject).to receive(:git)
69
+ expect(subject).to receive(:checkout)
70
+ subject.sync
71
+ end
72
+ end
73
+
74
+ describe "updating an existing repository" do
75
+ subject { described_class.new('master', 'git://github.com/adrienthebo/r10k-fixture-repo', '/some/nonexistent/dir') }
76
+
77
+ before do
78
+ allow(subject).to receive(:cloned?).and_return true
79
+ end
80
+
81
+ it "updates the remotes when they are out of sync" do
82
+ allow(subject).to receive(:ref_needs_fetch?).and_return false
83
+ allow(subject).to receive(:needs_checkout?).and_return false
84
+
85
+ expect(subject).to receive(:update_remotes?).and_return true
86
+ expect(subject).to receive(:update_remotes)
87
+
88
+ subject.sync
89
+ end
90
+
91
+ it "updates the cache when the ref requires an update" do
92
+ allow(subject).to receive(:update_remotes?).and_return false
93
+
94
+ expect(subject).to receive(:ref_needs_fetch?).and_return true
95
+ expect(subject).to receive(:fetch_from_cache)
96
+ expect(subject).to receive(:checkout).with(an_instance_of(R10K::Git::Ref))
97
+
98
+ subject.sync
99
+ end
100
+
101
+ it "checks out the ref when the wrong commit is checked out" do
102
+ allow(subject).to receive(:update_remotes?).and_return false
103
+ allow(subject).to receive(:ref_needs_fetch?).and_return false
104
+
105
+ expect(subject).to receive(:needs_checkout?).and_return true
106
+ expect(subject).to receive(:checkout).with(an_instance_of(R10K::Git::Ref))
107
+
108
+ subject.sync
109
+ end
110
+
111
+ it "doesn't update the repo when everything is in sync" do
112
+ allow(subject).to receive(:update_remotes?).and_return false
113
+ allow(subject).to receive(:ref_needs_fetch?).and_return false
114
+ allow(subject).to receive(:needs_checkout?).and_return false
115
+
116
+ expect(subject).to_not receive(:checkout)
117
+
118
+ subject.sync
119
+ end
11
120
  end
12
121
  end
@@ -46,6 +46,10 @@ describe R10K::Util::Subprocess do
46
46
  end
47
47
 
48
48
  it "raises an exception if raise_on_fail is true" do
49
+ if RUBY_VERSION =~ /^2\./
50
+ pending "Ruby 2.x and RSpec 2.x fail when raising an exception with a custom #to_s method"
51
+ end
52
+
49
53
  subject.raise_on_fail = true
50
54
 
51
55
  allow(result).to receive(:exit_code).and_return(255)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: r10k
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.1
4
+ version: 1.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adrien Thebo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-04-22 00:00:00.000000000 Z
11
+ date: 2014-07-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: colored
@@ -197,7 +197,11 @@ files:
197
197
  - README.markdown
198
198
  - Rakefile
199
199
  - bin/r10k
200
- - doc/dynamic-environments.markdown
200
+ - doc/dynamic-environments.mkd
201
+ - doc/dynamic-environments/configuration.mkd
202
+ - doc/dynamic-environments/git-environments.markdown
203
+ - doc/dynamic-environments/introduction.mkd
204
+ - doc/dynamic-environments/usage.mkd
201
205
  - doc/puppetfile.markdown
202
206
  - lib/r10k.rb
203
207
  - lib/r10k/cli.rb
@@ -223,6 +227,7 @@ files:
223
227
  - lib/r10k/errors.rb
224
228
  - lib/r10k/execution.rb
225
229
  - lib/r10k/git.rb
230
+ - lib/r10k/git/alternates.rb
226
231
  - lib/r10k/git/cache.rb
227
232
  - lib/r10k/git/commit.rb
228
233
  - lib/r10k/git/errors.rb
@@ -292,6 +297,7 @@ files:
292
297
  - spec/system/version_spec.rb
293
298
  - spec/unit/deployment/environment_spec.rb
294
299
  - spec/unit/deployment/source_spec.rb
300
+ - spec/unit/git/alternates_spec.rb
295
301
  - spec/unit/git/cache_spec.rb
296
302
  - spec/unit/git/commit_spec.rb
297
303
  - spec/unit/git/head_spec.rb
@@ -381,6 +387,7 @@ test_files:
381
387
  - spec/unit/git/commit_spec.rb
382
388
  - spec/unit/git/repository_spec.rb
383
389
  - spec/unit/git/head_spec.rb
390
+ - spec/unit/git/alternates_spec.rb
384
391
  - spec/unit/git/tag_spec.rb
385
392
  - spec/unit/deployment/environment_spec.rb
386
393
  - spec/unit/deployment/source_spec.rb
@@ -1,206 +0,0 @@
1
- Dynamic Environments
2
- ====================
3
-
4
- r10k implements the dynamic environment workflow with Puppet. This allows you to
5
- create, modify, and remove Puppet environments on the fly with Git branches.
6
-
7
- Dynamic Environments in a nutshell
8
- ----------------------------------
9
-
10
- The core idea of dynamic environments is that you should be able to manage your
11
- Puppet modules in the same manner that you would manage any other code base. It
12
- builds on top of Git topic branch model.
13
-
14
- [git-topic-branching]: http://git-scm.com/book/en/Git-Branching-Branching-Workflows#Topic-Branches "Git Topic Branches"
15
-
16
- One of the most prevalent ways of using Git relies on using [topic branches][git-topic-branching].
17
- Whenever changes need to be made that need to be reviewed or tested before going
18
- live, they should be done in a different, short lived branch called a topic
19
- branch. Work can be freely done on a topic branch in isolation and when the work
20
- is completed it is merged into a "master" or "production" branch. This is very
21
- powerful because it allows any number of people to rapidly develop features in
22
- isolation and merge features in a single operation.
23
-
24
- The dynamic environment model extends extends this git branching strategy to
25
- your live Puppet masters. It creates a mapping between Git branches and Puppet
26
- environments so that you can use the Git branching model and have that be
27
- seamlessly reflected in Puppet environments. This means that creating a new Git
28
- branch creates a new Puppet environment, updating a Git branch will update that
29
- environment, and deleting a Git branch will remove that environment.
30
-
31
- How it works
32
- ------------
33
-
34
- r10k works by tracking the state of your git repositories and comparing them the
35
- the currently deployed environments. If there's a Git branch that doesn't have a
36
- corresponding Puppet environment then r10k will clone that branch into the
37
- appropriate directory. When Git branches are updated r10k will update the
38
- appropriate Puppet environment to the latest version. Finally if there are
39
- Puppet environments that don't have matching Git branches, r10k will assume that
40
- the branches for those environments were deleted and will remove those
41
- environments.
42
-
43
- Configuration
44
- -------------
45
-
46
- r10k uses a configuration file to determine how dynamic environments should be
47
- deployed.
48
-
49
- ### Config file location
50
-
51
- By default r10k will try to read `/etc/r10k.yaml` for configuration settings.
52
- You can specify an alternate configuration file by specifying the `--config`
53
- option, like so:
54
-
55
- r10k deploy -c /srv/puppet/r10k.yaml
56
-
57
- ### Configuration format
58
-
59
- #### cachedir
60
-
61
- The `cachedir` setting specifies where r10k should keep cached information.
62
- Right now this is predominantly used for caching git repositories but will be
63
- expanded as other subsystems can take advantage of caching.
64
-
65
- For example:
66
-
67
- ---
68
- # Store all cache information in /var/cache
69
- cachedir: '/var/cache/r10k'
70
-
71
- #### sources
72
-
73
- The `sources` setting specifies what repositories should be used for creating
74
- dynamic environments.
75
-
76
- The `sources` setting is a hash where each key is the short name of a specific
77
- repository (for instance, "qa" or "web" or "ops") and the value is a hash of
78
- properties for that source.
79
-
80
- #### source sub-options
81
-
82
- ##### remote
83
-
84
- The remote is the URL of the Git repository to clone. This repository will need
85
- to be cloned without user intervention so SSH keys will need to be configured
86
- for the user running r10k.
87
-
88
- ##### basedir
89
-
90
- The basedir is the directory that will be populated with Puppet environments.
91
- This directory will be entirely managed by r10k and any contents that r10k did
92
- not put there will be _removed_.
93
-
94
- ##### prefix
95
-
96
- The prefix setting allows environment names to be prefixed with the short name
97
- of the given source. This prevents collisions when multiple sources are deployed
98
- into the same directory.
99
-
100
- #### source examples
101
-
102
- ##### Basic examples
103
-
104
- The majority of users will only have a single repository where all modules and
105
- hiera data files are kept. In this case you will specify a single source:
106
-
107
- ---
108
- # Specify a single environment source
109
- sources:
110
- operations:
111
- remote: 'git@github.com:my-org/org-modules'
112
- basedir: '/etc/puppet/environments'
113
-
114
- - - -
115
-
116
- ##### Advanced examples
117
-
118
- For more complex cases where you want to store hiera data in a different
119
- repository and your modules in another repository, you can specify two sources:
120
-
121
- ---
122
- sources:
123
- operations:
124
- remote: 'git@github.com:my-org/org-modules'
125
- basedir: '/etc/puppet/environments'
126
- hiera:
127
- remote: 'git@github.com:my-org/org-hiera-data'
128
- basedir: '/etc/puppet/hiera-data'
129
-
130
- - - -
131
-
132
- Alternately you may want to create separate environments from multiple
133
- repositories. This is useful when you want two groups to be able to deploy
134
- Puppet modules but they should only have write access to their own modules and
135
- not the modules of other groups.
136
-
137
- ---
138
- sources:
139
- main:
140
- remote: 'git@github.com:my-org/main-modules'
141
- basedir: '/etc/puppet/environments'
142
- prefix: false # Prefix defaults to false so this is only here for clarity
143
- qa:
144
- remote: 'git@github.com:my-org/qa-puppet-modules'
145
- basedir: '/etc/puppet/environments'
146
- prefix: true
147
- dev:
148
- remote: 'git@github.com:my-org/dev-puppet-modules'
149
- basedir: '/etc/puppet/environments'
150
- prefix: true
151
-
152
- This will create the following directory structure:
153
-
154
-
155
- /etc/puppet/environments
156
- |-- production # main-modules repository, production branch
157
- |-- upgrade_apache # main-modules repository, upgrade_apache branch
158
- |-- qa_production # qa repository, production branch
159
- |-- qa_jenkins_test # qa repository, jenkins_test branch
160
- |-- dev_production # dev repository, production branch
161
- `-- dev_loadtest # dev repository, loadtest branch
162
-
163
- Dynamic environments and Puppetfiles
164
- ------------------------------------
165
-
166
- TODO
167
-
168
- Interacting with dynamic environments
169
- -------------------------------------
170
-
171
- r10k provides fairly fine grained controls over your environments to fit your
172
- needs. If you want to do a full update of all of your environments and modules
173
- and don't need it to be done in real time, you can trigger a full update and let
174
- it run in the background. If you are actively developing code and need to run
175
- very fast updates of one specific environment, you can do a targeted update of
176
- that code as well.
177
-
178
- All commands that deal with deploying environments are grouped under the `r10k
179
- deploy` subcommand.
180
-
181
- ### Examples
182
-
183
- #### Deploying environments
184
-
185
- # Update all environments across all sources. This can be slow depending
186
- # on the number of environments and modules that you're using.
187
- r10k deploy environment
188
-
189
- # Update a single environment. When you're actively working on an
190
- # environment this is the best way to deploy your changes.
191
- r10k deploy environment my_working_environment
192
-
193
- # This is the brute force approach of "update everything, ever." This can
194
- # run for an extremely long time so it should not be something you run
195
- # interactively on a regular basis.
196
- r10k deploy environment --puppetfile
197
-
198
- #### Deploying modules
199
-
200
- # Update a single module across all environments This is useful for when
201
- # you're working on a module in an environment and only want to update that
202
- # one module.
203
- r10k deploy module apache
204
-
205
- # More than one module can be updated at a time.
206
- r10k deploy module apache jenkins java