bosh-stemcell 1.2922.0 → 1.2941.0

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,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