We’ve installed and configured r10k, are using it for deployments, and have a workflow for new modules. More commonly, we will be working on existing modules, a slightly different workflow. We can examine this new workflow by modifying the base module only.
Workflow to Modify Existing Module
Unlike adding a new module, the Puppetfile only needs to be modified to reflect the feature branch. This is where the workflows diverge: instead of requiring a merge, commit, and push, we can create a temporary branch and just delete it when we’re done. Only the module branch needs merged. We’ll show this by making a simple change, modifying Dave’s name. We have another Dave Smith who works here, so we’ll add a middle initial and the name of Dave’s organization, to prevent confusion.
The feature branch is just called dave. We’ll work on the module repo first. Make sure you’re in master and checkout the new branch. Dave’s description should be updated to “Dave G. Smith – IT Administrator” – everything will be alright unless they hire another Dave G. Smith over there. Commit the change and push it.
[root@puppet rnelson0-base]# git branch * master motd [root@puppet rnelson0-base]# git checkout -b dave Switched to a new branch 'dave' [root@puppet rnelson0-base]# vi manifests/ init.pp user.pp [root@puppet rnelson0-base]# vi manifests/init.pp [root@puppet rnelson0-base]# git diff diff --git a/manifests/init.pp b/manifests/init.pp index 6f78ed2..0f097b1 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -53,7 +53,7 @@ class base { id => 'dave', uid => '507', pass => $defaultpass, - realname => 'Dave Smith', + realname => 'Dave G. Smith - IT Administrator', sgroups => [], } [root@puppet rnelson0-base]# git commit -a -m "Update Dave's name in the user definition" [dave 096e9c1] Update Dave's name in the user definition 1 files changed, 1 insertions(+), 1 deletions(-) [root@puppet rnelson0-base]# git push origin dave Counting objects: 7, done. Compressing objects: 100% (4/4), done. Writing objects: 100% (4/4), 417 bytes, done. Total 4 (delta 2), reused 0 (delta 0) To https://rnelson0@github.com/rnelson0/rnelson0-base.git * [new branch] dave -> dave
Next, move to the puppet repo. Make sure you’re on production this time and checkout the new branch. In the Puppetfile, add a :ref to the dave branch of our module. Even though this is a temporary branch, we still need to commit and push it upstream.
[root@puppet puppet-tutorial]# git push origin dave * master motd [root@puppet rnelson0-base]# git checkout -b dave Switched to a new branch 'dave' [root@puppet rnelson0-base]# vi manifests/init.pp [root@puppet rnelson0-base]# git diff diff --git a/manifests/init.pp b/manifests/init.pp index 6f78ed2..0f097b1 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -53,7 +53,7 @@ class base { id => 'dave', uid => '507', pass => $defaultpass, - realname => 'Dave Smith', + realname => 'Dave G. Smith - IT Administrator', sgroups => [], } [root@puppet rnelson0-base]# git commit -a -m "Update Dave's name in the user definition" [dave 096e9c1] Update Dave's name in the user definition 1 files changed, 1 insertions(+), 1 deletions(-) [root@puppet puppet-tutorial]# git push origin dave Counting objects: 5, done. Compressing objects: 100% (3/3), done. Writing objects: 100% (3/3), 399 bytes, done. Total 3 (delta 1), reused 0 (delta 0) To https://rnelson0@github.com/rnelson0/puppet-tutorial * [new branch] dave -> dave
Deploy and test both production and dave environments. You can use noop, or just make sure production is the last one you run against:
[root@puppet puppet-tutorial]# r10k deploy environment -p Faraday: you may want to install system_timer for reliable timeouts [root@puppet puppet-tutorial]# puppet agent --test --environment dave Notice: /Stage[main]/Base/Base::User[dave]/User[dave]/comment: comment changed 'Dave Smith' to 'Dave G. Smith - IT Administrator' Notice: Generated from our notify branch Notice: /Stage[main]/Main/Node[puppet.nelson.va]/Notify[Generated from our notify branch]/message: defined 'message' as 'Generated from our notify branch' Notice: Finished catalog run in 1.07 seconds [root@puppet puppet-tutorial]# puppet agent --test Notice: /Stage[main]/Base/Base::User[dave]/User[dave]/comment: comment changed 'Dave G. Smith - IT Administrator' to 'Dave Smith' Notice: Generated from our notify branch Notice: /Stage[main]/Main/Node[puppet.nelson.va]/Notify[Generated from our notify branch]/message: defined 'message' as 'Generated from our notify branch' Notice: Finished catalog run in 0.93 seconds
Once everything’s good to go, switch back to the module repo. Checkout master, merge dave, and push it upstream.
[root@puppet rnelson0-base]# git branch * dave master motd [root@puppet rnelson0-base]# git checkout master Switched to branch 'master' [root@puppet rnelson0-base]# git merge dave Updating ad2a585..096e9c1 Fast-forward manifests/init.pp | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) [root@puppet rnelson0-base]# git push origin master Total 0 (delta 0), reused 0 (delta 0) To https://rnelson0@github.com/rnelson0/rnelson0-base.git ad2a585..096e9c1 master -> master
Redeploy again and test both environments. Now production and dave do the same thing – unlike when adding a new module, the existing module works fine because production‘s Puppetfile already pointed to the module with no changes.
[root@puppet rnelson0-base]# r10k deploy environment -p Faraday: you may want to install system_timer for reliable timeouts [root@puppet rnelson0-base]# puppet agent --test --environment dave --noop Notice: /Stage[main]/Base/Base::User[dave]/User[dave]/comment: current_value Dave Smith, should be Dave G. Smith - IT Administrator (noop) Notice: Base::User[dave]: Would have triggered 'refresh' from 1 events Notice: Class[Base]: Would have triggered 'refresh' from 1 events Notice: /Stage[main]/Main/Node[puppet.nelson.va]/Notify[Generated from our notify branch]/message: current_value absent, should be Generated from our notify branch (noop) Notice: Node[puppet.nelson.va]: Would have triggered 'refresh' from 1 events Notice: Class[Main]: Would have triggered 'refresh' from 1 events Notice: Stage[main]: Would have triggered 'refresh' from 2 events Notice: Finished catalog run in 0.99 seconds [root@puppet rnelson0-base]# puppet agent --test Notice: /Stage[main]/Base/Base::User[dave]/User[dave]/comment: comment changed 'Dave Smith' to 'Dave G. Smith - IT Administrator' Notice: Generated from our notify branch Notice: /Stage[main]/Main/Node[puppet.nelson.va]/Notify[Generated from our notify branch]/message: defined 'message' as 'Generated from our notify branch' Notice: Finished catalog run in 1.25 seconds
Because we don’t have to merge changes in the puppet repo, we can go into both repos, delete the feature branch (using the -D switch for puppet, as we never merged the branch), and push changes upstream. After re-deploying, there won’t be a dave feature branch so there won’t be a dave environment, as shown below (for those playing along via github, I DID delete the branch on the github repo, so you’ll have to perform the above changes yourself). However, running the agent against production shows everything is still working.
[root@puppet rnelson0-base]# git branch dave * master motd [root@puppet rnelson0-base]# git branch -D dave Deleted branch dave (was 096e9c1). [root@puppet rnelson0-base]# git push origin :dave To https://rnelson0@github.com/rnelson0/rnelson0-base.git - [deleted] dave [root@puppet rnelson0-base]# cd ../puppet-tutorial/ [root@puppet puppet-tutorial]# git branch * dave master motd production [root@puppet puppet-tutorial]# git checkout production Switched to branch 'production' [root@puppet puppet-tutorial]# git branch -D dave Deleted branch dave (was 580b993). [root@puppet puppet-tutorial]# git push origin :dave To https://rnelson0@github.com/rnelson0/puppet-tutorial - [deleted] dave [root@puppet puppet-tutorial]# r10k deploy environment -p Faraday: you may want to install system_timer for reliable timeouts [root@puppet puppet-tutorial]# ls /etc/puppet/environments/ master motd production [root@puppet puppet-tutorial]# puppet agent --test Notice: Generated from our notify branch Notice: /Stage[main]/Main/Node[puppet.nelson.va]/Notify[Generated from our notify branch]/message: defined 'message' as 'Generated from our notify branch' Notice: Finished catalog run in 1.48 seconds
Summary of Existing Module Workflow
Here’s another quick recap of the workflow.
Module Repo:
- Create a new branch in the existing module repo(s): git checkout -b <feature>
- Modify the existing module(s) as needed to reference the new module(s)
- Commit changes: git commit -a -m ‘Add <feature> reference to module’
- Push upstream: git push origin <feature>
Puppet Repo:
- Create a new branch in the puppet repo: git checkout -b <feature>
- Modify Puppetfile:
- Add a :ref to existing module repos with a value of the new feature branch’s name.
- Commit changes: git commit -a -m ‘Add module <X> to branch <feature>’
- Push upstream: git push origin <feature>
Puppet Master:
- Deploy environments with r10k: r10k deploy environment -p
- Test catalog compilation in the new feature branch: puppet agent –test –noop –environment <feature>
Repeat the above steps until your changes are complete and all tests succeed. When ready, merge the changes to your module and discard the changes to puppet:
Module repo:
- Checkout the master branch: git checkout master
- Merge changes from the feature branch: git merge <feature>
- Push upstream: git push origin master
- OPTIONAL – Delete feature branch (recommended for short lived features, not recommended for version tags): git branch -D feature; git push origin :feature
Puppet repo:
- Checkout the production branch: git checkout production
- OPTIONAL – Delete feature branch (recommended for short lived features, not recommended for version tags): git branch -D feature; git push origin :feature
Puppet Master:
- Deploy environments with r10k: r10k deploy environment -p
- Test catalog compilation in the production branch: puppet agent –test –noop
UPDATE: In the comments, David B. asked about preserving development and production environments in the workflow. The above workflow assumes only production (and the corresponding master branches) are long-lived. If you need a long-lived development environment, the workflow will be slightly different and a bit more tedious. This should be easy to setup.
One Time Setup Work
Puppet repo:
- Create a branch for each long-lived environment you need – development, testing, qa, etc. – with git checkout -b <environment>
- In each branch (git checkout <environment>), edit Puppetfile and add a ref for each module you will modify to the branch name matching the environment. I recommend that the branch and environment names match, but any name will work as long as the ref matches.
- Commit changes: git commit -a -m ‘Add long-lived environment <environment> and references to the environment branch on all developed modules’
- Push upstream: git push origin <environment>
- Repeat for the next environment.
Module repos:
- Create a branch for each long-lived environment you need – development, testing, qa, etc. – with git checkout -b <environment>
- Commit changes: git commit -a -m ‘Add long-lived environment <environment>. No changes.’
- Push upstream: git push origin <environment>
- Repeat for the next environment.
If you add a new module, you’ll need to add it to each Puppet repo branch with the correct refs, and create the environment branches in the module’s repo.
Recurring Workflow
Module Repo:
- Create a new branch in the existing module repo(s): git checkout -b <feature>
- Modify the existing module(s) as needed to reference the new module(s)
- Commit changes: git commit -a -m ‘Add <feature> reference to module’
- Push upstream: git push origin <feature>
Puppet Repo:
- Create a new branch in the puppet repo: git checkout -b <feature>
- Modify Puppetfile:
- Add a :ref to existing module repos with a value of the new feature branch’s name.
- Commit changes: git commit -a -m ‘Add module <X> to branch <feature>’
- Push upstream: git push origin <feature>
Puppet Master:
- Deploy environments with r10k: r10k deploy environment -p
- Test catalog compilation in the new feature branch: puppet agent –test –noop –environment <feature>
Repeat the above steps until your changes are complete and all tests succeed. When ready, merge the changes to your module into the next environment:
Module repo:
- Repeat the following three steps, merging feature into development, then again into testing, qa, etc., until it is time to merge it into production:
- Checkout the environment branch: git checkout <environment>
- Merge changes from the feature branch: git merge <feature>
- Push upstream: git push origin <environment>
- OPTIONAL – Delete feature branch (recommended for short lived features, not recommended for version tags): git branch -D feature; git push origin :feature
Puppet repo:
- No work needs done on any branch, as the refs all point to the environment branch for each module.
- When all work is done, checkout the production branch so that future branches are based off it: git checkout production
- OPTIONAL – Delete feature branch (recommended for short lived features, not recommended for version tags): git branch -D feature; git push origin :feature
Puppet Master:
- Deploy environments with r10k: r10k deploy environment -p
- Test catalog compilation in the environment branch: puppet agent –test –noop –environment <environment>
I do not use such a workflow in my lab or at work so the above is best effort. If you do implement this, please let me know how it works out and any tweaks you needed to make.
What’s Next?
You now have two workflows you can use:
- Static environments where root does push pulls
- Dynamic environments where users push and r10k pulls
We still haven’t eliminated the need for someone to log into the master as root and do some work, though. Next week, we’ll look at git hooks and how they can help automate our dynamic environments even further, almost eliminating the need to log in to the master.
Hi
Would it possible to have a production AND a development branch on which new module features get merged?
First on development, once validated, merged to production as well.
This way, you keep working branches similar to real environment.
David.
Yes, this is doable. This would modify the workflow slightly, both with respect to the Puppetfile and the module repos. I’ll update the article shortly to describe this process.