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 +4 -4
- data/lib/bosh/stemcell/archive.rb +5 -5
- data/lib/bosh/stemcell/aws/ami_collection.rb +143 -0
- data/lib/bosh/stemcell/aws/light_stemcell.rb +21 -22
- data/lib/bosh/stemcell/aws/region.rb +4 -4
- data/lib/bosh/stemcell/stage_collection.rb +3 -0
- data/lib/bosh/stemcell/version.rb +1 -1
- metadata +7 -7
- data/lib/bosh/stemcell/aws/ami.rb +0 -65
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 23245ec8c50d7c96d9a78f715e36370ededb3c3c
|
4
|
+
data.tar.gz: 536b9148c3ba2bd1c2b4da7d74f942a80c15e4ac
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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' &&
|
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
|
-
|
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
|
-
|
39
|
-
|
34
|
+
# this method has heavy side effects
|
40
35
|
def manifest
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
manifest['cloud_properties']['ami'] =
|
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
|
-
|
10
|
-
|
11
|
-
|
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
|
|
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.
|
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-
|
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.
|
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.
|
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.
|
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.
|
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/
|
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
|