clc-promote 0.4.5 → 0.7.8

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.
@@ -13,18 +13,22 @@ module Promote
13
13
  @uploader = Uploader.new(@config)
14
14
  @promoter = Promoter.new(@config)
15
15
  yield self if block_given?
16
- define_version_cookbook
17
- define_version_cookbooks
18
- define_version_environment
19
- define_version_environments
16
+ define_constrain_environment
17
+ define_promote_environment
18
+ define_promote_environments
20
19
  define_sync_berksfile
21
20
  define_sync_berksfiles
22
- define_upload_cookbooks
23
21
  define_upload_cookbook
24
- define_upload_environment
22
+ define_upload_cookbooks
25
23
  define_upload_data_bags
26
- define_constrain_environment
27
- define_promote_environment
24
+ define_upload_environment
25
+ define_upload_roles
26
+ define_version_cookbook
27
+ define_version_cookbooks
28
+ define_version_environment
29
+ define_version_environments
30
+ define_version_role
31
+ define_version_roles
28
32
  end
29
33
 
30
34
  private
@@ -95,7 +99,17 @@ module Promote
95
99
  def define_promote_environment
96
100
  namespace "Promote" do
97
101
  desc "Promote one environment from another"
98
- task "promote_environment", :source_environment, :destination_environment do |task, args|
102
+ task "promote_environment", :source_environment, :destination_environments do |task, args|
103
+ puts "Promoting constraints in #{args.source_environment} to #{args.destination_environments}"
104
+ @promoter.monitor_promotion(args.source_environment, args.destination_environments, 60 * 5)
105
+ end
106
+ end
107
+ end
108
+
109
+ def define_promote_environments
110
+ namespace "Promote" do
111
+ desc "Promote a list of environments from another"
112
+ task "promote_environments", :source_environment, :destination_environments do |task, args|
99
113
  puts "Promoting constraints in #{args.source_environment} to #{args.destination_environment}"
100
114
  deps = @promoter.promote_to(args.source_environment, args.destination_environment)
101
115
  end
@@ -114,6 +128,27 @@ module Promote
114
128
  end
115
129
  end
116
130
 
131
+ def define_version_role
132
+ namespace "Promote" do
133
+ desc "Version a role"
134
+ task "version_role", :role do |task, args|
135
+ @versioner.version_role(args.role)
136
+ end
137
+ end
138
+ end
139
+
140
+ def define_version_roles
141
+ namespace "Promote" do
142
+ desc "Version all roles"
143
+ task "version_roles" do
144
+ puts "Version stamping changed roles..."
145
+ @versioner.version_roles.each do |result|
146
+ puts "Versioned role: #{result[:artifact]} v#{result[:version]}"
147
+ end
148
+ end
149
+ end
150
+ end
151
+
117
152
  def define_upload_cookbooks
118
153
  namespace "Promote" do
119
154
  desc "Upload all cookbooks in an environment to the chef server"
@@ -144,15 +179,25 @@ module Promote
144
179
  end
145
180
  end
146
181
 
147
- def define_upload_data_bags
148
- namespace "Promote" do
149
- desc "Upload data_bags to the chef server"
150
- task "upload_data_bags" do
151
- file_uploaded = @uploader.upload_data_bags
152
- puts "Uploading #{file_uploaded} to #{@uploader.config.chef_server_url} as #{@uploader.config.node_name} using #{@uploader.config.client_key}"
153
- end
154
- end
155
- end
182
+ def define_upload_roles
183
+ namespace "Promote" do
184
+ desc "Upload roles to the chef server"
185
+ task "upload_roles" do
186
+ file_uploaded = @uploader.upload_roles
187
+ puts "Uploading #{file_uploaded} to #{@uploader.config.chef_server_url} as #{@uploader.config.node_name} using #{@uploader.config.client_key}"
188
+ end
189
+ end
190
+ end
191
+
192
+ def define_upload_data_bags
193
+ namespace "Promote" do
194
+ desc "Upload data_bags to the chef server"
195
+ task "upload_data_bags" do
196
+ file_uploaded = @uploader.upload_data_bags
197
+ puts "Uploading #{file_uploaded} to #{@uploader.config.chef_server_url} as #{@uploader.config.node_name} using #{@uploader.config.client_key}"
198
+ end
199
+ end
200
+ end
156
201
 
157
202
  end
158
203
  end
@@ -0,0 +1,26 @@
1
+ require 'json'
2
+
3
+ module Promote
4
+ class RoleFile
5
+ attr_accessor :name
6
+
7
+ def initialize(role_name, config)
8
+ @name = role_name
9
+ @config = config
10
+ end
11
+
12
+ def file_path
13
+ File.join(@config.role_directory, "#{name}.json")
14
+ end
15
+
16
+ private
17
+
18
+ def content
19
+ @content ||= get_role_content
20
+ end
21
+
22
+ def get_role_content
23
+ JSON.parse(File.read(file_path))
24
+ end
25
+ end
26
+ end
@@ -3,10 +3,11 @@ require 'chef/chef_fs/parallelizer'
3
3
  require 'chef/chef_fs/config'
4
4
  require 'chef/chef_fs/file_pattern'
5
5
  require 'chef/chef_fs/file_system'
6
+ require 'chef/chef_fs/file_system/chef_repository_file_system_root_dir'
6
7
  require 'chef/config'
7
8
  require 'chef/chef_fs/path_utils'
8
9
  require 'chef/knife'
9
- unless defined? Chef::Knife::CookbookUpload
10
+ unless defined? Chef::Knife::CookbookUpload
10
11
  require 'chef/knife/cookbook_upload'
11
12
  end
12
13
 
@@ -41,14 +42,19 @@ module Promote
41
42
 
42
43
  upload_filtered_cookbooks(dirs, environment)
43
44
  end
44
-
45
- def upload_cookbook_directory(directory)
46
- if !Dir.glob(File.join(config.cookbook_directory, "*")).empty?
45
+
46
+ def upload_cookbook_directory(directory, ui = nil)
47
+ if !Dir.glob(File.join(directory, "*")).empty?
48
+ if ui
49
+ ui.info "Uploading cookbooks from #{directory} to #{Chef::Config[:chef_server_url]}"
50
+ end
47
51
  knife = Chef::Knife::CookbookUpload.new()
48
52
  knife.config[:all] = true
49
- knife.config[:freeze] = true
53
+ knife.config[:freeze] = true
50
54
  knife.config[:cookbook_path] = directory
51
55
  knife.run
56
+ elsif ui
57
+ ui.info "No cookbooks found in #{directory}"
52
58
  end
53
59
  end
54
60
 
@@ -60,8 +66,29 @@ module Promote
60
66
  upload_file("/environments/*.json")
61
67
  end
62
68
 
69
+ def upload_roles
70
+ upload_file("/roles/*.json")
71
+ end
72
+
63
73
  def upload_data_bags
64
- upload_file("/data_bags/**/*.json")
74
+ data_bag_directory = File.join(config.temp_directory, "data_bags")
75
+ chef_fs_directory = Chef::ChefFS::FileSystem::ChefRepositoryFileSystemRootDir.new(
76
+ {
77
+ 'data_bags' => [data_bag_directory]
78
+ }
79
+ )
80
+
81
+ config.reset_temp_dir
82
+
83
+ Dir.glob(File.join(config.data_bag_directory,'**/*.json')).
84
+ reject{ |file| file.end_with?("_keys.json")}.each do |file|
85
+ new_path = file.sub(config.repo_root, config.temp_directory)
86
+ new_dir = File.dirname(new_path)
87
+ FileUtils.mkdir_p(new_dir) unless Dir.exist?(new_dir)
88
+ FileUtils.cp(file, new_path)
89
+ end
90
+
91
+ upload_file("/data_bags/**/*.json", chef_fs_directory)
65
92
  end
66
93
 
67
94
  attr_accessor :config
@@ -70,7 +97,7 @@ module Promote
70
97
 
71
98
  def upload_filtered_cookbooks(dirs, environment = nil)
72
99
  anything_to_upload = false
73
-
100
+
74
101
  server_cookbooks = Utils.chef_server_cookbooks(config)
75
102
  if environment.nil?
76
103
  env_versions = nil
@@ -78,8 +105,7 @@ module Promote
78
105
  env_versions = EnvironmentFile.new(environment, config).cookbook_versions
79
106
  end
80
107
 
81
- FileUtils.rm_rf(config.temp_directory) if Dir.exist?(config.temp_directory)
82
- Dir.mkdir(config.temp_directory)
108
+ config.reset_temp_dir
83
109
 
84
110
  dirs.each do | dir |
85
111
  anything_to_upload = cookbooks_copied?(dir, server_cookbooks, env_versions) || anything_to_upload
@@ -108,10 +134,16 @@ module Promote
108
134
  end
109
135
  end
110
136
 
111
- def upload_file(file_path)
112
- fs_config = Chef::ChefFS::Config.new
137
+ def upload_file(file_path, src = Chef::ChefFS::Config.new.local_fs)
113
138
  pattern = Chef::ChefFS::FilePattern.new(file_path)
114
- Chef::ChefFS::FileSystem.copy_to(pattern, fs_config.local_fs, fs_config.chef_fs, 1, Chef::Config)
139
+
140
+ Chef::ChefFS::FileSystem.copy_to(
141
+ pattern,
142
+ src,
143
+ Chef::ChefFS::Config.new.chef_fs,
144
+ nil,
145
+ Chef::Config
146
+ )
115
147
  file_path
116
148
  end
117
149
 
@@ -127,4 +159,4 @@ module Promote
127
159
  end
128
160
  end
129
161
  end
130
- end
162
+ end
@@ -1,3 +1,3 @@
1
1
  module Promote
2
- VERSION = '0.4.5'
3
- end
2
+ VERSION = '0.7.8'
3
+ end
@@ -13,9 +13,9 @@ module Promote
13
13
  if cookbook.version.to_s != version
14
14
  cookbook.version = Semverse::Version.new(version)
15
15
  cookbook.stamp_commit(repo.sha1)
16
- return {
17
- :cookbook => cookbook_name,
18
- :version => version,
16
+ return {
17
+ :cookbook => cookbook_name,
18
+ :version => version,
19
19
  :sha1 => repo.sha1
20
20
  }
21
21
  end
@@ -49,6 +49,34 @@ module Promote
49
49
  results
50
50
  end
51
51
 
52
+ def version_role(role_name)
53
+ # if role doesn't include an override_attributes key, create it
54
+ file = File.join(config.role_directory, "#{role_name}.json")
55
+ role = JSON.parse(File.read(file))
56
+ if !role.has_key?("override_attributes")
57
+ overrides_hash = { "override_attributes" => {} }
58
+ role.merge!(overrides_hash)
59
+ File.open(file, 'w') do |out|
60
+ out << JSON.pretty_generate(role)
61
+ end
62
+ end
63
+
64
+ version_json config.role_directory, role_name do | content |
65
+ content['override_attributes']
66
+ end
67
+ end
68
+
69
+ def version_roles
70
+ results = []
71
+ Dir.glob(File.join(config.role_directory, "*.json")).each do |file|
72
+ result = version_role(File.basename(file ,File.extname(file)))
73
+ if !result.nil?
74
+ results << result
75
+ end
76
+ end
77
+ results
78
+ end
79
+
52
80
  def constrain_environment(environment_name, cookbook_name)
53
81
  dependencies = Cookbook.new(cookbook_name, config).dependencies
54
82
  env_file = EnvironmentFile.new(environment_name, config)
@@ -56,12 +84,18 @@ module Promote
56
84
  dependencies
57
85
  end
58
86
 
59
- def is_dirty(source_environment, target_environment, cookbook_name)
87
+ def is_dirty(source_environment, target_environment, cookbook_name, dependency_hash = nil)
60
88
  target_env_file = EnvironmentFile.new(target_environment, config)
61
89
  return true unless target_env_file.cookbook_versions.has_key?(cookbook_name)
62
-
90
+
63
91
  source_env_file = EnvironmentFile.new(source_environment, config)
64
- return source_env_file.cookbook_versions[cookbook_name] != target_env_file.cookbook_versions[cookbook_name]
92
+ target_version_parts = target_env_file.cookbook_versions[cookbook_name].split('.')
93
+ target_version = target_version_parts[0..2].join('.')
94
+ target_hash = nil
95
+ if target_version_parts.count > 3
96
+ target_hash = target_version_parts[3]
97
+ end
98
+ return source_env_file.cookbook_versions[cookbook_name] != target_version || dependency_hash != target_hash
65
99
  end
66
100
 
67
101
  attr_accessor :config
@@ -92,12 +126,13 @@ module Promote
92
126
  File.open(file, 'w') do |out|
93
127
  out << JSON.pretty_generate(content)
94
128
  end
95
- {
96
- :artifact => file_name,
97
- :version => version,
129
+ {
130
+ :artifact => file_name,
131
+ :version => version,
98
132
  :sha1 => repo.sha1
99
133
  }
100
134
  end
135
+
101
136
  end
102
137
  end
103
138
  end
@@ -1,15 +1,17 @@
1
1
  require 'promote'
2
2
 
3
3
  describe Promote::Config do
4
- let(:opts) {{
5
- :repo_root => "root",
6
- :cookbook_directory => "cookbooks",
7
- :environment_directory => "environments",
8
- :data_bag_directory => "data_bags",
9
- :temp_directory => "temp",
10
- :node_name => "user",
11
- :client_key => "key",
12
- :chef_server_url => "url"}}
4
+ let(:opts) {{
5
+ :repo_root => "root",
6
+ :cookbook_directory => "cookbooks",
7
+ :environment_directory => "environments",
8
+ :data_bag_directory => "data_bags",
9
+ :role_directory => "roles",
10
+ :temp_directory => "temp",
11
+ :node_name => "user",
12
+ :client_key => "key",
13
+ :chef_server_url => "url",
14
+ :bags => ['foo']}}
13
15
  subject { Promote::Config.new(opts) }
14
16
 
15
17
  it "assigns options to node_name attribute" do
@@ -33,20 +35,25 @@ describe Promote::Config do
33
35
  it "assigns options to environment_directory attribute" do
34
36
  expect(subject.environment_directory).to eq(opts[:environment_directory])
35
37
  end
38
+ it "assigns options to role_directory attribute" do
39
+ expect(subject.role_directory).to eq(opts[:role_directory])
40
+ end
36
41
  it "assigns options to temp_directory attribute" do
37
42
  expect(subject.temp_directory).to eq(opts[:temp_directory])
38
43
  end
44
+ it "assigns options to bags attribute" do
45
+ expect(subject.bags).to eq(opts[:bags])
46
+ end
39
47
  it "can correctly convert to a hash" do
40
48
  hash = subject.to_hash
41
49
  expect(hash[:repo_root]).to eq(opts[:repo_root])
42
50
  end
43
51
 
44
52
  context "directories are not in options" do
45
- let(:opts) {{
46
- :node_name => "user",
47
- :client_key => "key",
53
+ let(:opts) {{
54
+ :node_name => "user",
55
+ :client_key => "key",
48
56
  :chef_server_url => "url"}}
49
- subject { Promote::Config.new(opts) }
50
57
 
51
58
  it "assigns repo_root to pwd" do
52
59
  expect(subject.repo_root).to eq(Dir.pwd)
@@ -60,18 +67,31 @@ describe Promote::Config do
60
67
  it "assigns environment_directory to environments off root" do
61
68
  expect(subject.environment_directory).to eq(File.join(subject.repo_root, "environments"))
62
69
  end
70
+ it "assigns role_directory to roles off root" do
71
+ expect(subject.role_directory).to eq(File.join(subject.repo_root, "roles"))
72
+ end
63
73
  it "assigns temp_directory to tmp" do
64
74
  expect(subject.temp_directory).to eq("/tmp/promote")
65
75
  end
66
76
  end
67
77
 
78
+ context "no --data-bag option is specified" do
79
+ let(:opts) {{
80
+ :node_name => "user",
81
+ :client_key => "key",
82
+ :chef_server_url => "url"}}
83
+
84
+ it "defaults to secrets_*" do
85
+ expect(subject.bags).to eq(['secrets_*'])
86
+ end
87
+ end
88
+
68
89
  context "directories are not in options but repo root is" do
69
- let(:opts) {{
90
+ let(:opts) {{
70
91
  :repo_root => "root",
71
- :node_name => "user",
72
- :client_key => "key",
92
+ :node_name => "user",
93
+ :client_key => "key",
73
94
  :chef_server_url => "url"}}
74
- subject { Promote::Config.new(opts) }
75
95
 
76
96
  it "assigns repo_root to pwd" do
77
97
  expect(subject.repo_root).to eq(opts[:repo_root])
@@ -85,8 +105,40 @@ describe Promote::Config do
85
105
  it "assigns environment_directory to environments off root" do
86
106
  expect(subject.environment_directory).to eq(File.join(subject.repo_root, "environments"))
87
107
  end
108
+ it "assigns role_directory to roles off root" do
109
+ expect(subject.role_directory).to eq(File.join(subject.repo_root, "roles"))
110
+ end
88
111
  it "assigns temp_directory to tmp" do
89
112
  expect(subject.temp_directory).to eq("/tmp/promote")
90
113
  end
91
114
  end
92
- end
115
+
116
+ context "reset_temp_dir" do
117
+ after {
118
+ FileUtils.rm_rf(opts[:temp_directory])
119
+ }
120
+
121
+ context "temp dir is populated" do
122
+ before {
123
+ opts[:temp_directory] = "/tmp/promote_tests"
124
+ Dir.mkdir(opts[:temp_directory])
125
+ FileUtils.touch(File.join(opts[:temp_directory], 'file.txt'))
126
+ }
127
+
128
+ it "empties the temp directory" do
129
+ subject.reset_temp_dir
130
+
131
+ expect(Dir[File.join(subject.temp_directory, '*')]).to be_empty
132
+ end
133
+ end
134
+
135
+ context "temp dir is populated" do
136
+
137
+ it "creates the temp directory" do
138
+ subject.reset_temp_dir
139
+
140
+ expect(Dir).to exist(subject.temp_directory)
141
+ end
142
+ end
143
+ end
144
+ end