r10k 1.2.1 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml 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