knife-flow 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/README.md +81 -0
- data/Rakefile +1 -0
- data/knife-flow.gemspec +20 -0
- data/lib/chef/knife/increment.rb +122 -0
- data/lib/chef/knife/promote.rb +156 -0
- data/lib/chef/knife/release.rb +195 -0
- data/lib/knife-flow/version.rb +5 -0
- metadata +78 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
knife-flow
|
|
2
|
+
========
|
|
3
|
+
A collection of Chef plugins for managing the migration of cookbooks to environments in different Opscode organizations.
|
|
4
|
+
The main reason for having a workflow around the development and promotion of cookbooks is to ensure quality, reliability and administrative security of the process.
|
|
5
|
+
|
|
6
|
+
Requirements
|
|
7
|
+
---------------
|
|
8
|
+
Right now knife-flow is build with many assumptions:
|
|
9
|
+
|
|
10
|
+
* The knife-flow assumes you have at least 2 orgs; one for "development" and one for "production".
|
|
11
|
+
* The "development" org has one environment called "candidate".
|
|
12
|
+
* The "production" org has an "innovate" and a "production" environment.
|
|
13
|
+
* You are using git flow [http://jeffkreeftmeijer.com/2010/why-arent-you-using-git-flow/](http://jeffkreeftmeijer.com/2010/why-arent-you-using-git-flow/) for your chef-repo project.
|
|
14
|
+
|
|
15
|
+
Installing knife-flow
|
|
16
|
+
-------------------
|
|
17
|
+
Be sure you are running the latest version Chef.
|
|
18
|
+
|
|
19
|
+
Map the "development" org to the knife.rb file, and map the "production" org to a knife-production.rb file.
|
|
20
|
+
|
|
21
|
+
Copy the increment.rb, promote.rb and release.rb files to the <tt>chef-repo/.chef/knife/plugins</tt> directory.
|
|
22
|
+
|
|
23
|
+
Plugins
|
|
24
|
+
---------------
|
|
25
|
+
|
|
26
|
+
### increment
|
|
27
|
+
Increments the cookbooks version by 1 digit at the patch level (i.e. 2.3.1 -> 2.3.2 ) <br />
|
|
28
|
+
Uploads the cookbook by running <tt> knife cookbook upload COOKBOOK COOKBOOK </tt> <br />
|
|
29
|
+
Commits the changes to the "develop" branch <br />
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
$ knife increment COOKBOOK COOKBOOK ...
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
This plugin is useful when working on the projects in the "sandbox" stage. The "_default" environment will always load the latest versions of the cookbooks.
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
### promote
|
|
39
|
+
Increments the cookbooks version by 1 digit at the patch level ( i.e. 2.3.1 -> 2.3.2 ) <br />
|
|
40
|
+
Uploads the cookbook by running <tt> knife cookbook upload COOKBOOK COOKBOOK </tt> <br />
|
|
41
|
+
Updates the environments/ENVIRONMENT.json file with the list of COOKBOOK COOKBOOK and relative new versions. <br />
|
|
42
|
+
Uploads the ENVIRONMENT.json file to the "development" org. <br />
|
|
43
|
+
Commits the changes to the "develop" branch. <br />
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
$ knife promote ENVIRONMENT(i.e. candidate) COOKBOOK COOKBOOK ...
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
This plugin is useful when working on the projects in the "validation" and "performance" stage. The "candidate" environment will be used to validate the cookbooks versions.
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
### release
|
|
53
|
+
Copies the "candidate" environment cookbook list and transfer them to the ENVIRONMENT in the "production" org. <br />
|
|
54
|
+
Commits all changes and creates a release tag TAG using the <tt> git flow release start/finish TAG </tt>. <br />
|
|
55
|
+
Uploads all cookbooks to the "production" org. <br />
|
|
56
|
+
|
|
57
|
+
$ knife release ENVIRONMENT(i.e. innovate or production) TAG(i.e. 2011.2.3)
|
|
58
|
+
|
|
59
|
+
This plugin is useful when we are ready to migrate the cookbooks to the environments in the "production" org.
|
|
60
|
+
|
|
61
|
+
License terms
|
|
62
|
+
-------------
|
|
63
|
+
Authors:: Johnlouis Petitbon, Jacob Zimmerman, Aaron Suggs
|
|
64
|
+
|
|
65
|
+
Copyright:: Copyright (c) 2009-2011 Medidata Solutions Worldwide, Inc.
|
|
66
|
+
|
|
67
|
+
License:: Apache License, Version 2.0
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
71
|
+
you may not use this file except in compliance with the License.
|
|
72
|
+
You may obtain a copy of the License at
|
|
73
|
+
|
|
74
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
75
|
+
|
|
76
|
+
Unless required by applicable law or agreed to in writing, software
|
|
77
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
78
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
79
|
+
See the License for the specific language governing permissions and
|
|
80
|
+
limitations under the License.
|
|
81
|
+
|
data/Rakefile
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require 'bundler/gem_tasks'
|
data/knife-flow.gemspec
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
|
3
|
+
require "knife-flow/version"
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |s|
|
|
6
|
+
s.name = "knife-flow"
|
|
7
|
+
s.version = Knife::Flow::VERSION
|
|
8
|
+
s.authors = ["Johnlouis Petitbon", "Jacob Zimmerman", "Aaron Suggs"]
|
|
9
|
+
s.email = ["jpetitbon@mdsol.com"]
|
|
10
|
+
s.homepage = "https://github.com/mdsol/knife-flow"
|
|
11
|
+
s.summary = %q{A collection of Chef plugins for managing the migration of cookbooks to environments in different Opscode organizations.}
|
|
12
|
+
s.description = %q{The main reason for having a workflow around the development and promotion of cookbooks is to ensure quality, reliability and administrative security of the process.}
|
|
13
|
+
|
|
14
|
+
s.rubyforge_project = "knife-flow"
|
|
15
|
+
|
|
16
|
+
s.files = `git ls-files`.split("\n")
|
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
|
19
|
+
s.require_paths = ["lib"]
|
|
20
|
+
end
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
#
|
|
2
|
+
## Author:: Johnlouis Petitbon (<jpetitbon@mdsol.com>)
|
|
3
|
+
##
|
|
4
|
+
## Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
## you may not use this file except in compliance with the License.
|
|
6
|
+
## You may obtain a copy of the License at
|
|
7
|
+
##
|
|
8
|
+
## http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
##
|
|
10
|
+
## Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
## distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
## See the License for the specific language governing permissions and
|
|
14
|
+
## limitations under the License.
|
|
15
|
+
##
|
|
16
|
+
#
|
|
17
|
+
|
|
18
|
+
require 'chef/knife'
|
|
19
|
+
|
|
20
|
+
module KnifeFlow
|
|
21
|
+
class Increment < Chef::Knife
|
|
22
|
+
|
|
23
|
+
deps do
|
|
24
|
+
require 'chef/cookbook_loader'
|
|
25
|
+
require 'chef/cookbook_uploader'
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
banner "knife increment COOKBOOK"
|
|
29
|
+
|
|
30
|
+
WORKING_BRANCH = "develop"
|
|
31
|
+
|
|
32
|
+
def run
|
|
33
|
+
|
|
34
|
+
@cookbooks = parse_name_args!
|
|
35
|
+
|
|
36
|
+
self.config = Chef::Config.merge!(config)
|
|
37
|
+
|
|
38
|
+
if !config[:cookbook_path]
|
|
39
|
+
raise ArgumentError, "Default cookbook_path is not specified in the knife.rb config file, and a value to -o is not provided. Nowhere to write the new cookbook to."
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
if check_branch(WORKING_BRANCH)
|
|
43
|
+
|
|
44
|
+
pull_branch(WORKING_BRANCH)
|
|
45
|
+
|
|
46
|
+
@cookbook_path = Array(config[:cookbook_path]).first
|
|
47
|
+
|
|
48
|
+
@cookbooks.each do | book |
|
|
49
|
+
metadata_file = File.join(@cookbook_path, book, "metadata.rb")
|
|
50
|
+
|
|
51
|
+
# 1) increase version on the metadata file
|
|
52
|
+
replace_version(find_version(book), increment_version(find_version(book)), metadata_file )
|
|
53
|
+
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# 2) upload cookbooks to chef server
|
|
57
|
+
cookbook_up = Chef::Knife::CookbookUpload.new
|
|
58
|
+
cookbook_up.name_args = @cookbooks
|
|
59
|
+
cookbook_up.config[:freeze] = true
|
|
60
|
+
cookbook_up.run
|
|
61
|
+
|
|
62
|
+
# 3) commit and push WORKING_BRANCH
|
|
63
|
+
commit_and_push_branch(WORKING_BRANCH, "#{@cookbooks} have been incremented")
|
|
64
|
+
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def parse_name_args!
|
|
70
|
+
if name_args.empty?
|
|
71
|
+
ui.error("USAGE: knife increment COOKBOOK COOKBOOK COOKBOOK")
|
|
72
|
+
exit 1
|
|
73
|
+
else
|
|
74
|
+
return name_args
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def commit_and_push_branch(branch, comment)
|
|
79
|
+
print "--------------------------------- \n"
|
|
80
|
+
system("git pull origin #{branch}")
|
|
81
|
+
system("git add .")
|
|
82
|
+
system("git commit -am '#{comment}'")
|
|
83
|
+
system("git push origin #{branch}")
|
|
84
|
+
print "--------------------------------- \n"
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def pull_branch(name)
|
|
88
|
+
print "--------------------------------- \n"
|
|
89
|
+
system("git pull origin #{name}")
|
|
90
|
+
print "--------------------------------- \n"
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def check_branch(name)
|
|
94
|
+
if (`git status` =~ /#{name}/) != nil
|
|
95
|
+
return true
|
|
96
|
+
else
|
|
97
|
+
ui.error("USAGE: you must be in the #{name} branch")
|
|
98
|
+
exit 1
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def find_version(name)
|
|
103
|
+
loader = Chef::CookbookLoader.new(@cookbook_path)
|
|
104
|
+
return loader[name].version
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def increment_version(version)
|
|
108
|
+
current_version = version.split(".").map{|i| i.to_i}
|
|
109
|
+
current_version[2] = current_version[2] + 1
|
|
110
|
+
return current_version.join('.')
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def replace_version(search_string, replace_string, file)
|
|
114
|
+
open_file = File.open(file, "r")
|
|
115
|
+
body_of_file = open_file.read
|
|
116
|
+
open_file.close
|
|
117
|
+
body_of_file.gsub!(search_string, replace_string)
|
|
118
|
+
File.open(file, "w") { |file| file << body_of_file }
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
end
|
|
122
|
+
end
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
#
|
|
2
|
+
## Author:: Johnlouis Petitbon (<jpetitbon@mdsol.com>)
|
|
3
|
+
##
|
|
4
|
+
## Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
## you may not use this file except in compliance with the License.
|
|
6
|
+
## You may obtain a copy of the License at
|
|
7
|
+
##
|
|
8
|
+
## http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
##
|
|
10
|
+
## Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
## distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
## See the License for the specific language governing permissions and
|
|
14
|
+
## limitations under the License.
|
|
15
|
+
##
|
|
16
|
+
#
|
|
17
|
+
|
|
18
|
+
require 'chef/knife'
|
|
19
|
+
|
|
20
|
+
module KnifeFlow
|
|
21
|
+
class Promote < Chef::Knife
|
|
22
|
+
|
|
23
|
+
deps do
|
|
24
|
+
require 'chef/cookbook_loader'
|
|
25
|
+
require 'chef/cookbook_uploader'
|
|
26
|
+
require 'chef/environment'
|
|
27
|
+
require 'chef/knife/core/object_loader'
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
banner "knife promote ENVIRONMENT COOKBOOK"
|
|
31
|
+
|
|
32
|
+
WORKING_BRANCH = "develop"
|
|
33
|
+
|
|
34
|
+
def run
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
all_args = parse_name_args!
|
|
38
|
+
env_name = all_args[0]
|
|
39
|
+
all_args.shift
|
|
40
|
+
cookbooks = all_args
|
|
41
|
+
|
|
42
|
+
self.config = Chef::Config.merge!(config)
|
|
43
|
+
|
|
44
|
+
if !config[:cookbook_path]
|
|
45
|
+
raise ArgumentError, "Default cookbook_path is not specified in the knife.rb config file, and a value to -o is not provided. Nowhere to write the new cookbook to."
|
|
46
|
+
end
|
|
47
|
+
@cookbook_path = Array(config[:cookbook_path]).first
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
if check_branch(WORKING_BRANCH)
|
|
51
|
+
|
|
52
|
+
pull_branch(WORKING_BRANCH)
|
|
53
|
+
|
|
54
|
+
env_json = load_env_file(env_name)
|
|
55
|
+
|
|
56
|
+
env_data = JSON.parse(env_json)
|
|
57
|
+
|
|
58
|
+
cookbooks.each do | book |
|
|
59
|
+
metadata_file = File.join(@cookbook_path, book, "metadata.rb")
|
|
60
|
+
|
|
61
|
+
# 1) increase version on the metadata file
|
|
62
|
+
replace_version(find_version(book), increment_version(find_version(book)), metadata_file )
|
|
63
|
+
|
|
64
|
+
# 2) add or update the cookbook in the environment cookbook_versions list
|
|
65
|
+
env_data.cookbook_versions.merge!(book => find_version(book))
|
|
66
|
+
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# 3) write the environment to file
|
|
70
|
+
File.open("environments/#{env_name}.json","w") do |f|
|
|
71
|
+
f.write(JSON.pretty_generate(env_data))
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# 4) upload cookbooks to chef server
|
|
75
|
+
cookbook_up = Chef::Knife::CookbookUpload.new
|
|
76
|
+
cookbook_up.name_args = cookbooks
|
|
77
|
+
cookbook_up.config[:freeze] = true
|
|
78
|
+
cookbook_up.run
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
# 5) upload environment to chef server
|
|
82
|
+
knife_environment_from_file = Chef::Knife::EnvironmentFromFile.new
|
|
83
|
+
knife_environment_from_file.name_args = ["#{env_name}.json"]
|
|
84
|
+
output = knife_environment_from_file.run
|
|
85
|
+
|
|
86
|
+
# 6) commit and push all changes to develop
|
|
87
|
+
commit_and_push_branch(WORKING_BRANCH, "#{cookbooks.join(" and ").to_s} have been promoted to the #{env_name} environment")
|
|
88
|
+
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def load_env_file(env_name)
|
|
94
|
+
if File.exist?("environments/#{env_name}.json")
|
|
95
|
+
File.read("environments/#{env_name}.json")
|
|
96
|
+
else
|
|
97
|
+
# TODO - we should handle the creation of the environment.json file if it doesn't exist.
|
|
98
|
+
raise ArgumentError, "environments/#{env_name}.json was not found; please create the environment file manually.#{env_name}"
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def commit_and_push_branch(branch, comment)
|
|
103
|
+
print "--------------------------------- \n"
|
|
104
|
+
system("git pull origin #{branch}")
|
|
105
|
+
system("git add .")
|
|
106
|
+
system("git commit -am '#{comment}'")
|
|
107
|
+
system("git push origin #{branch}")
|
|
108
|
+
print "--------------------------------- \n"
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def pull_branch(name)
|
|
112
|
+
print "--------------------------------- \n"
|
|
113
|
+
system("git pull origin #{name}")
|
|
114
|
+
print "--------------------------------- \n"
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def check_branch(name)
|
|
118
|
+
if (`git status` =~ /#{name}/) != nil
|
|
119
|
+
return true
|
|
120
|
+
else
|
|
121
|
+
ui.error("USAGE: you must be in the #{name} branch.")
|
|
122
|
+
exit 1
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def parse_name_args!
|
|
127
|
+
if name_args.empty?
|
|
128
|
+
ui.error("USAGE: knife promote ENVIRONMENT COOKBOOK COOKBOOK ...")
|
|
129
|
+
exit 1
|
|
130
|
+
else
|
|
131
|
+
return name_args
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def find_version(name)
|
|
136
|
+
loader = Chef::CookbookLoader.new(@cookbook_path)
|
|
137
|
+
return loader[name].version
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def increment_version(version)
|
|
141
|
+
current_version = version.split(".").map{|i| i.to_i}
|
|
142
|
+
current_version[2] = current_version[2] + 1
|
|
143
|
+
return current_version.join('.')
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def replace_version(search_string, replace_string, file)
|
|
147
|
+
open_file = File.open(file, "r")
|
|
148
|
+
body_of_file = open_file.read
|
|
149
|
+
open_file.close
|
|
150
|
+
body_of_file.gsub!(search_string, replace_string)
|
|
151
|
+
File.open(file, "w") { |file| file << body_of_file }
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
end
|
|
156
|
+
end
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
#
|
|
2
|
+
## Author:: Johnlouis Petitbon (<jpetitbon@mdsol.com>)
|
|
3
|
+
##
|
|
4
|
+
## Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
## you may not use this file except in compliance with the License.
|
|
6
|
+
## You may obtain a copy of the License at
|
|
7
|
+
##
|
|
8
|
+
## http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
##
|
|
10
|
+
## Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
## distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
## See the License for the specific language governing permissions and
|
|
14
|
+
## limitations under the License.
|
|
15
|
+
##
|
|
16
|
+
#
|
|
17
|
+
|
|
18
|
+
require 'chef/knife'
|
|
19
|
+
|
|
20
|
+
module KnifeFlow
|
|
21
|
+
class Release < Chef::Knife
|
|
22
|
+
|
|
23
|
+
deps do
|
|
24
|
+
require 'chef/cookbook_loader'
|
|
25
|
+
require 'chef/cookbook_uploader'
|
|
26
|
+
require 'chef/environment'
|
|
27
|
+
require 'chef/knife/core/object_loader'
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
banner "knife release ENVIRONMENT TAG"
|
|
31
|
+
|
|
32
|
+
WORKING_BRANCH = "develop"
|
|
33
|
+
CANDIDATE_ENVIRONMENT = "candidate"
|
|
34
|
+
|
|
35
|
+
def run
|
|
36
|
+
|
|
37
|
+
all_args = parse_name_args!
|
|
38
|
+
env_name = all_args[0]
|
|
39
|
+
tag_name = all_args[1]
|
|
40
|
+
|
|
41
|
+
self.config = Chef::Config.merge!(config)
|
|
42
|
+
|
|
43
|
+
switch_org(env_name)
|
|
44
|
+
|
|
45
|
+
self.config = Chef::Config.merge!(config)
|
|
46
|
+
|
|
47
|
+
if !config[:cookbook_path]
|
|
48
|
+
raise ArgumentError, "Default cookbook_path is not specified in the knife.rb config file, and a value to -o is not provided. Nowhere to write the new cookbook to."
|
|
49
|
+
end
|
|
50
|
+
@cookbook_path = Array(config[:cookbook_path]).first
|
|
51
|
+
|
|
52
|
+
if check_branch(WORKING_BRANCH)
|
|
53
|
+
|
|
54
|
+
pull_branch(WORKING_BRANCH)
|
|
55
|
+
|
|
56
|
+
system("git fetch --tags")
|
|
57
|
+
|
|
58
|
+
# 1) start a new git-flow release
|
|
59
|
+
system("git flow release start #{tag_name}")
|
|
60
|
+
|
|
61
|
+
candidate_json = load_env_file(CANDIDATE_ENVIRONMENT)
|
|
62
|
+
candidate_data = JSON.parse(candidate_json)
|
|
63
|
+
|
|
64
|
+
env_json = load_env_file(env_name)
|
|
65
|
+
env_data = JSON.parse(env_json)
|
|
66
|
+
|
|
67
|
+
cb_a = []
|
|
68
|
+
candidate_data.cookbook_versions.each do | book_data |
|
|
69
|
+
cb_a << book_data[0]
|
|
70
|
+
|
|
71
|
+
# 2) add or update the cookbook in the environment cookbook_versions list
|
|
72
|
+
env_data.cookbook_versions.merge!(book_data[0] => book_data[1])
|
|
73
|
+
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# 3) write the environment to file
|
|
77
|
+
File.open("environments/#{env_name}.json","w") do |f|
|
|
78
|
+
f.write(JSON.pretty_generate(env_data))
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# 4) upload cookbooks to chef server
|
|
82
|
+
cookbook_up = Chef::Knife::CookbookUpload.new
|
|
83
|
+
cookbook_up.name_args = cb_a
|
|
84
|
+
cookbook_up.config[:freeze] = true
|
|
85
|
+
cookbook_up.run
|
|
86
|
+
|
|
87
|
+
# 5) upload environment to chef server
|
|
88
|
+
knife_environment_from_file = Chef::Knife::EnvironmentFromFile.new
|
|
89
|
+
knife_environment_from_file.name_args = ["#{env_name}.json"]
|
|
90
|
+
output = knife_environment_from_file.run
|
|
91
|
+
|
|
92
|
+
# 6) commit all changes and finish the git-flow release
|
|
93
|
+
system("git commit -am 'the candidate environemnt is now in production and tagged #{tag_name}'")
|
|
94
|
+
system("git flow release finish -m 'testing' #{tag_name}")
|
|
95
|
+
|
|
96
|
+
system("git push origin #{WORKING_BRANCH} --tags")
|
|
97
|
+
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def switch_org(env_name)
|
|
103
|
+
# TODO - someone smarter than me can switch the organization without requiring 2 different knife.rb files
|
|
104
|
+
current_dir = File.dirname(__FILE__)
|
|
105
|
+
case env_name
|
|
106
|
+
when "innovate"
|
|
107
|
+
Chef::Config[:config_file] = "#{current_dir}/../../knife-production.rb"
|
|
108
|
+
when "production"
|
|
109
|
+
Chef::Config[:config_file] = "#{current_dir}/../../knife-production.rb"
|
|
110
|
+
when "candidate"
|
|
111
|
+
Chef::Config[:config_file] = "#{current_dir}/../../knife.rb"
|
|
112
|
+
end
|
|
113
|
+
::File::open(config[:config_file]) { |f| apply_config(f.path) }
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def load_env_file(env_name)
|
|
117
|
+
if File.exist?("environments/#{env_name}.json")
|
|
118
|
+
File.read("environments/#{env_name}.json")
|
|
119
|
+
else
|
|
120
|
+
# TODO - we should handle the creation of the environment.json file if it doesn't exist.
|
|
121
|
+
raise ArgumentError, "environments/#{env_name}.json was not found; please create the environment file manually.#{env_name}"
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def apply_config(config_file_path)
|
|
126
|
+
Chef::Config.from_file(config_file_path)
|
|
127
|
+
Chef::Config.merge!(config)
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def commit_and_push_branch(branch, comment)
|
|
131
|
+
print "--------------------------------- \n"
|
|
132
|
+
system("git pull origin #{branch}")
|
|
133
|
+
system("git add .")
|
|
134
|
+
system("git commit -am '#{comment}'")
|
|
135
|
+
system("git push origin #{branch}")
|
|
136
|
+
print "--------------------------------- \n"
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def checkout_branch(name)
|
|
140
|
+
print "--------------------------------- \n"
|
|
141
|
+
system("git checkout #{name}")
|
|
142
|
+
print "--------------------------------- \n"
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def checkout_tag(name)
|
|
146
|
+
print "--------------------------------- \n"
|
|
147
|
+
system("git checkout #{name}")
|
|
148
|
+
print "--------------------------------- \n"
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def pull_branch(name)
|
|
152
|
+
print "--------------------------------- \n"
|
|
153
|
+
system("git pull origin #{name}")
|
|
154
|
+
print "--------------------------------- \n"
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def check_branch(name)
|
|
158
|
+
if (`git status` =~ /#{name}/) != nil
|
|
159
|
+
return true
|
|
160
|
+
else
|
|
161
|
+
ui.error("USAGE: you must be in the #{name} branch.")
|
|
162
|
+
exit 1
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def parse_name_args!
|
|
167
|
+
if name_args.empty?
|
|
168
|
+
ui.error("USAGE: knife promote ENVIRONMENT COOKBOOK COOKBOOK ...")
|
|
169
|
+
exit 1
|
|
170
|
+
else
|
|
171
|
+
return name_args
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def find_version(name)
|
|
176
|
+
loader = Chef::CookbookLoader.new(@cookbook_path)
|
|
177
|
+
return loader[name].version
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def increment_version(version)
|
|
181
|
+
current_version = version.split(".").map{|i| i.to_i}
|
|
182
|
+
current_version[2] = current_version[2] + 1
|
|
183
|
+
return current_version.join('.')
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def replace_version(search_string, replace_string, file)
|
|
187
|
+
open_file = File.open(file, "r")
|
|
188
|
+
body_of_file = open_file.read
|
|
189
|
+
open_file.close
|
|
190
|
+
body_of_file.gsub!(search_string, replace_string)
|
|
191
|
+
File.open(file, "w") { |file| file << body_of_file }
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
end
|
|
195
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: knife-flow
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
hash: 29
|
|
5
|
+
prerelease:
|
|
6
|
+
segments:
|
|
7
|
+
- 0
|
|
8
|
+
- 0
|
|
9
|
+
- 1
|
|
10
|
+
version: 0.0.1
|
|
11
|
+
platform: ruby
|
|
12
|
+
authors:
|
|
13
|
+
- Johnlouis Petitbon
|
|
14
|
+
- Jacob Zimmerman
|
|
15
|
+
- Aaron Suggs
|
|
16
|
+
autorequire:
|
|
17
|
+
bindir: bin
|
|
18
|
+
cert_chain: []
|
|
19
|
+
|
|
20
|
+
date: 2011-07-09 00:00:00 -04:00
|
|
21
|
+
default_executable:
|
|
22
|
+
dependencies: []
|
|
23
|
+
|
|
24
|
+
description: The main reason for having a workflow around the development and promotion of cookbooks is to ensure quality, reliability and administrative security of the process.
|
|
25
|
+
email:
|
|
26
|
+
- jpetitbon@mdsol.com
|
|
27
|
+
executables: []
|
|
28
|
+
|
|
29
|
+
extensions: []
|
|
30
|
+
|
|
31
|
+
extra_rdoc_files: []
|
|
32
|
+
|
|
33
|
+
files:
|
|
34
|
+
- .gitignore
|
|
35
|
+
- Gemfile
|
|
36
|
+
- README.md
|
|
37
|
+
- Rakefile
|
|
38
|
+
- knife-flow.gemspec
|
|
39
|
+
- lib/chef/knife/increment.rb
|
|
40
|
+
- lib/chef/knife/promote.rb
|
|
41
|
+
- lib/chef/knife/release.rb
|
|
42
|
+
- lib/knife-flow/version.rb
|
|
43
|
+
has_rdoc: true
|
|
44
|
+
homepage: https://github.com/mdsol/knife-flow
|
|
45
|
+
licenses: []
|
|
46
|
+
|
|
47
|
+
post_install_message:
|
|
48
|
+
rdoc_options: []
|
|
49
|
+
|
|
50
|
+
require_paths:
|
|
51
|
+
- lib
|
|
52
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
53
|
+
none: false
|
|
54
|
+
requirements:
|
|
55
|
+
- - ">="
|
|
56
|
+
- !ruby/object:Gem::Version
|
|
57
|
+
hash: 3
|
|
58
|
+
segments:
|
|
59
|
+
- 0
|
|
60
|
+
version: "0"
|
|
61
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
62
|
+
none: false
|
|
63
|
+
requirements:
|
|
64
|
+
- - ">="
|
|
65
|
+
- !ruby/object:Gem::Version
|
|
66
|
+
hash: 3
|
|
67
|
+
segments:
|
|
68
|
+
- 0
|
|
69
|
+
version: "0"
|
|
70
|
+
requirements: []
|
|
71
|
+
|
|
72
|
+
rubyforge_project: knife-flow
|
|
73
|
+
rubygems_version: 1.5.3
|
|
74
|
+
signing_key:
|
|
75
|
+
specification_version: 3
|
|
76
|
+
summary: A collection of Chef plugins for managing the migration of cookbooks to environments in different Opscode organizations.
|
|
77
|
+
test_files: []
|
|
78
|
+
|