bosh-stemcell 1.2922.0 → 1.2941.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e63abd8e3e4094e14eb2055f037830ebf0fdfb8b
4
- data.tar.gz: 4adef86bd8f5af990a1bd68f19a487e22f89c99a
3
+ metadata.gz: 23245ec8c50d7c96d9a78f715e36370ededb3c3c
4
+ data.tar.gz: 536b9148c3ba2bd1c2b4da7d74f942a80c15e4ac
5
5
  SHA512:
6
- metadata.gz: 883740b6c50493eb018fad4ec6cf2c3012c46aff7d5e4c0aad8f4e7dd9ca645a8715bac54c254e0eae4f654cd7e214abd0e1de59951f720feec68ca194a25087
7
- data.tar.gz: 317890a2a52246297e56c4b87d1b5cd7800e7dfd58d652d295727be725822acf4ba7b0283187635119c9ce51b2655dd2553cd46bf390f3c1d42c34398aa3b657
6
+ metadata.gz: 91d2d26a75df2d1b5d3778438e58c496e1dc45be4e11f779896c9ee3cacf714ce7968382d34ca7f34430ea4f2644504b167e4c9dd9563d92efe2ccfd510f6301
7
+ data.tar.gz: e38fd4b4de070bbbdd837d9212f6efaccaf363f2b555ba8fe4ffa3a0f1d3e309df97475c9ff29a8af5401d00e7abf83e3e634dbd9e759d1d25bf02c5295d3887
@@ -34,11 +34,7 @@ module Bosh::Stemcell
34
34
  end
35
35
 
36
36
  def light?
37
- infrastructure == 'aws' && ami_id
38
- end
39
-
40
- def ami_id(region = Aws::Region::DEFAULT)
41
- cloud_properties.fetch('ami', {}).fetch(region, nil)
37
+ infrastructure == 'aws' && has_ami?
42
38
  end
43
39
 
44
40
  def extract(tar_options = {}, &block)
@@ -54,6 +50,10 @@ module Bosh::Stemcell
54
50
 
55
51
  private
56
52
 
53
+ def has_ami?
54
+ cloud_properties.has_key? 'ami'
55
+ end
56
+
57
57
  def cloud_properties
58
58
  manifest.fetch('cloud_properties')
59
59
  end
@@ -0,0 +1,143 @@
1
+ require 'cloud'
2
+ require 'bosh_aws_cpi'
3
+ require 'ostruct'
4
+ require 'yaml'
5
+ require 'rake'
6
+
7
+ module Bosh::Stemcell::Aws
8
+ class AmiCollection
9
+ MAX_COPY_IMAGE_WAIT_ATTEMPTS = 360
10
+
11
+ attr_reader :stemcell
12
+
13
+ def initialize(stemcell, regions, virtualization_type)
14
+ @stemcell = stemcell
15
+ @seed_region = regions.first
16
+ @dest_regions = regions - [@seed_region]
17
+ @virtualization_type = virtualization_type
18
+
19
+ @access_key_id = ENV['BOSH_AWS_ACCESS_KEY_ID']
20
+ @secret_access_key = ENV['BOSH_AWS_SECRET_ACCESS_KEY']
21
+ end
22
+
23
+ def publish
24
+ logger = Logger.new('ami.log')
25
+ cloud_config = OpenStruct.new(logger: logger, task_checkpoint: nil)
26
+ Bosh::Clouds::Config.configure(cloud_config)
27
+ cloud = Bosh::Clouds::Provider.create(cloud_options, 'fake-director-uuid')
28
+
29
+ region_ami_mapping = {}
30
+ @stemcell.extract do |tmp_dir, stemcell_manifest|
31
+ cloud_properties = stemcell_manifest['cloud_properties'].merge(
32
+ 'virtualization_type' => @virtualization_type
33
+ )
34
+
35
+ seed_ami_id = cloud.create_stemcell("#{tmp_dir}/image", cloud_properties)
36
+ seed_ami = cloud.ec2.images[seed_ami_id]
37
+ seed_ami.public = true
38
+ region_ami_mapping = copy_to_regions(logger, seed_ami_id, seed_ami.name, seed_ami.tags)
39
+ region_ami_mapping[@seed_region] = seed_ami_id
40
+ end
41
+
42
+ region_ami_mapping
43
+ end
44
+
45
+ private
46
+
47
+ def copy_to_regions(logger, source_id, source_name, source_tags)
48
+ threads = []
49
+ mutex = Mutex.new
50
+ region_ami_mapping = {}
51
+
52
+ @dest_regions.each do |dest_region|
53
+ threads << Thread.new do
54
+ copied_ami_id = copy_to_region(logger, source_id, source_name, source_tags, @seed_region, dest_region)
55
+ mutex.synchronize { region_ami_mapping[dest_region] = copied_ami_id }
56
+ end
57
+ end
58
+
59
+ threads.each { |t| t.join }
60
+ region_ami_mapping
61
+ end
62
+
63
+ def copy_to_region(logger, source_ami_id, source_ami_name, source_ami_tags, source_region, dest_region)
64
+ logger.info "Copying AMI '#{source_ami_id}' from region '#{source_region}' to region '#{dest_region}'"
65
+
66
+ client_options = {
67
+ :access_key_id => @access_key_id,
68
+ :secret_access_key => @secret_access_key,
69
+ :region => dest_region
70
+ }
71
+ query_client = AWS::EC2::Client.new(client_options)
72
+ ec2_client = AWS::EC2.new(client_options)
73
+
74
+ copied_ami_id = copy_image(ec2_client, query_client, source_region, source_ami_id, source_ami_name)
75
+ set_image_attributes(ec2_client, copied_ami_id, source_ami_tags)
76
+ logger.info "Finished copying AMI '#{source_ami_id}' from region '#{source_region}'" +
77
+ " to AMI '#{copied_ami_id}' in region '#{dest_region}'"
78
+
79
+ copied_ami_id
80
+ end
81
+
82
+ def copy_image(ec2_client, query_client, source_region, source_ami_id, source_ami_name)
83
+ copy_image_options = {
84
+ source_region: source_region,
85
+ source_image_id: source_ami_id,
86
+ name: source_ami_name
87
+ }
88
+
89
+ copied_ami_id = query_client.copy_image(copy_image_options)[:image_id]
90
+ # we have to wait for the image to be available in order to set attributes on it
91
+ wait_for_ami_to_be_available(ec2_client, copied_ami_id)
92
+ copied_ami_id
93
+ end
94
+
95
+ def set_image_attributes(ec2_client, ami_id, ami_tags)
96
+ ami = ec2_client.images[ami_id]
97
+
98
+ ami.public = true
99
+ ami.add_tag('Name', :value => ami_tags['Name'])
100
+ end
101
+
102
+ def wait_for_ami_to_be_available(ec2, ami_id)
103
+ # AMI is likely to be in state :pending or it may not be found (NotFound error).
104
+ image_state = lambda {
105
+ begin
106
+ ec2.images[ami_id].state
107
+ rescue AWS::EC2::Errors::InvalidAMIID::NotFound
108
+ :not_found
109
+ end
110
+ }
111
+
112
+ attempts = 0
113
+ until image_state.call == :available
114
+ if attempts > MAX_COPY_IMAGE_WAIT_ATTEMPTS
115
+ raise "Timed out waiting for AMI '#{ami_id}' to reach 'available' state"
116
+ end
117
+ attempts += 1
118
+ sleep(0.5*attempts)
119
+ end
120
+ end
121
+
122
+ # At some point we should extract the logic in cloud.create_stemcell into a library which can be used here
123
+ # it doesn't make a lot of sense to new up a set of options of the registry.
124
+ def cloud_options
125
+ {
126
+ 'plugin' => 'aws',
127
+ 'properties' => {
128
+ 'aws' => {
129
+ 'access_key_id' => @access_key_id,
130
+ 'secret_access_key' => @secret_access_key,
131
+ 'region' => @seed_region,
132
+ 'default_key_name' => 'fake'
133
+ },
134
+ 'registry' => {
135
+ 'endpoint' => 'http://fake.registry',
136
+ 'user' => 'fake',
137
+ 'password' => 'fake'
138
+ }
139
+ }
140
+ }
141
+ end
142
+ end
143
+ end
@@ -1,53 +1,52 @@
1
1
  require 'rake/file_utils'
2
2
  require 'yaml'
3
3
  require 'common/deep_copy'
4
+ require 'bosh/stemcell/aws/ami_collection'
4
5
  require 'bosh/stemcell/aws/region'
5
- require 'bosh/stemcell/aws/ami'
6
6
 
7
7
  module Bosh::Stemcell::Aws
8
8
  HVM_VIRTUALIZATION = 'hvm'
9
9
 
10
10
  class LightStemcell
11
- def initialize(stemcell, virtualization_type)
11
+ def initialize(stemcell, virtualization_type, regions=Region::REGIONS)
12
12
  @stemcell = stemcell
13
13
  @virtualization_type = virtualization_type
14
+ @regions = regions
14
15
  end
15
16
 
16
17
  def write_archive
17
- stemcell.extract(exclude: 'image') do |extracted_stemcell_dir|
18
+ @stemcell.extract(exclude: 'image') do |extracted_stemcell_dir|
18
19
  Dir.chdir(extracted_stemcell_dir) do
19
20
  FileUtils.touch('image', verbose: true)
20
-
21
- File.open('stemcell.MF', 'w') do |out|
22
- Psych.dump(manifest, out)
23
- end
24
-
21
+ File.write('stemcell.MF', Psych.dump(manifest))
25
22
  Rake::FileUtilsExt.sh("sudo tar cvzf #{path} *")
26
23
  end
27
24
  end
28
25
  end
29
26
 
30
27
  def path
31
- stemcell_name = File.basename(stemcell.path)
32
- stemcell_name = stemcell_name.gsub("xen", "xen-hvm") if virtualization_type == HVM_VIRTUALIZATION
33
- File.join(File.dirname(stemcell.path), "light-#{stemcell_name}")
28
+ stemcell_name = adjust_hvm_name(File.basename(@stemcell.path))
29
+ File.join(File.dirname(@stemcell.path), "light-#{stemcell_name}")
34
30
  end
35
31
 
36
32
  private
37
33
 
38
- attr_reader :stemcell, :virtualization_type
39
-
34
+ # this method has heavy side effects
40
35
  def manifest
41
- region = Region.new
42
- ami = Ami.new(stemcell, region, virtualization_type)
43
- ami_id = ami.publish
44
- manifest = Bosh::Common::DeepCopy.copy(stemcell.manifest)
45
- if virtualization_type == HVM_VIRTUALIZATION
46
- manifest['name'] = manifest['name'].gsub("xen", "xen-hvm")
47
- manifest['cloud_properties']['name'] = manifest['cloud_properties']['name'].gsub("xen", "xen-hvm")
48
- end
49
- manifest['cloud_properties']['ami'] = { region.name => ami_id }
36
+ manifest = Bosh::Common::DeepCopy.copy(@stemcell.manifest)
37
+ manifest['name'] = adjust_hvm_name(manifest['name'])
38
+ manifest['cloud_properties']['name'] = adjust_hvm_name(manifest['cloud_properties']['name'])
39
+
40
+ ami_collection = AmiCollection.new(@stemcell, @regions, @virtualization_type)
41
+
42
+ # Light stemcell contains AMIs for all regions
43
+ # so that CPI can pick one based on its configuration
44
+ manifest['cloud_properties']['ami'] = ami_collection.publish
50
45
  manifest
51
46
  end
47
+
48
+ def adjust_hvm_name(name)
49
+ @virtualization_type == HVM_VIRTUALIZATION ? name.gsub("xen", "xen-hvm") : name
50
+ end
52
51
  end
53
52
  end
@@ -5,10 +5,10 @@ module Bosh
5
5
  module Aws
6
6
  class Region
7
7
  DEFAULT = 'us-east-1'
8
-
9
- def name
10
- Net::HTTP.get('169.254.169.254', '/latest/meta-data/placement/availability-zone').chop
11
- end
8
+ REGIONS = %w{
9
+ us-east-1 us-west-1 us-west-2 eu-west-1 eu-central-1
10
+ ap-southeast-1 ap-southeast-2 ap-northeast-1 sa-east-1
11
+ }
12
12
  end
13
13
  end
14
14
  end
@@ -201,6 +201,7 @@ module Bosh::Stemcell
201
201
  :rsyslog_config,
202
202
  :delay_monit_start,
203
203
  :system_grub,
204
+ :cron_config,
204
205
  ].flatten
205
206
 
206
207
  if operating_system.version.to_f < 7
@@ -220,6 +221,7 @@ module Bosh::Stemcell
220
221
  :delay_monit_start,
221
222
  :system_grub,
222
223
  :rhel_unsubscribe,
224
+ :cron_config,
223
225
  ].flatten
224
226
  end
225
227
 
@@ -240,6 +242,7 @@ module Bosh::Stemcell
240
242
  :delay_monit_start,
241
243
  :system_grub,
242
244
  :vim_tiny,
245
+ :cron_config,
243
246
  ].flatten
244
247
  end
245
248
 
@@ -1,5 +1,5 @@
1
1
  module Bosh
2
2
  module Stemcell
3
- VERSION = '1.2922.0'
3
+ VERSION = '1.2941.0'
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bosh-stemcell
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2922.0
4
+ version: 1.2941.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pivotal
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-04-10 00:00:00.000000000 Z
11
+ date: 2015-04-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bosh_aws_cpi
@@ -16,28 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 1.2922.0
19
+ version: 1.2941.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 1.2922.0
26
+ version: 1.2941.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bosh-core
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 1.2922.0
33
+ version: 1.2941.0
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 1.2922.0
40
+ version: 1.2941.0
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: fakefs
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -176,7 +176,7 @@ files:
176
176
  - lib/bosh/stemcell/archive.rb
177
177
  - lib/bosh/stemcell/archive_filename.rb
178
178
  - lib/bosh/stemcell/archive_handler.rb
179
- - lib/bosh/stemcell/aws/ami.rb
179
+ - lib/bosh/stemcell/aws/ami_collection.rb
180
180
  - lib/bosh/stemcell/aws/light_stemcell.rb
181
181
  - lib/bosh/stemcell/aws/region.rb
182
182
  - lib/bosh/stemcell/build_environment.rb
@@ -1,65 +0,0 @@
1
- require 'cloud'
2
- require 'bosh_aws_cpi'
3
- require 'ostruct'
4
- require 'yaml'
5
- require 'rake'
6
- require 'bosh/stemcell/aws/region'
7
-
8
- module Bosh::Stemcell::Aws
9
- class Ami
10
- attr_reader :stemcell
11
-
12
- def initialize(stemcell, region, virtualization_type)
13
- @stemcell = stemcell
14
- @region = region
15
- @virtualization_type = virtualization_type || 'paravirtual'
16
- end
17
-
18
- def publish
19
- cloud_config = OpenStruct.new(logger: Logger.new('ami.log'), task_checkpoint: nil)
20
- Bosh::Clouds::Config.configure(cloud_config)
21
-
22
- cloud = Bosh::Clouds::Provider.create(options, 'fake-director-uuid')
23
-
24
- stemcell.extract do |tmp_dir, stemcell_manifest|
25
- cloud_properties = stemcell_manifest['cloud_properties'].merge(
26
- 'virtualization_type' => virtualization_type
27
- )
28
- ami_id = cloud.create_stemcell("#{tmp_dir}/image", cloud_properties)
29
- cloud.ec2.images[ami_id].public = true
30
- ami_id
31
- end
32
- end
33
-
34
- private
35
-
36
- attr_reader :region, :virtualization_type
37
-
38
- def options
39
- # just fake the registry struct, as we don't use it
40
- {
41
- 'plugin' => 'aws',
42
- 'properties' => {
43
- 'aws' => aws,
44
- 'registry' => {
45
- 'endpoint' => 'http://fake.registry',
46
- 'user' => 'fake',
47
- 'password' => 'fake'
48
- }
49
- }
50
- }
51
- end
52
-
53
- def aws
54
- access_key_id = ENV['BOSH_AWS_ACCESS_KEY_ID']
55
- secret_access_key = ENV['BOSH_AWS_SECRET_ACCESS_KEY']
56
-
57
- {
58
- 'default_key_name' => 'fake',
59
- 'region' => region.name,
60
- 'access_key_id' => access_key_id,
61
- 'secret_access_key' => secret_access_key
62
- }
63
- end
64
- end
65
- end