bosh-stemcell 1.5.0.pre.1113
Sign up to get free protection for your applications and to get access to all the features.
- data/.rspec +3 -0
- data/README.md +104 -0
- data/Vagrantfile +37 -0
- data/bosh-stemcell.gemspec +28 -0
- data/lib/bosh/stemcell.rb +4 -0
- data/lib/bosh/stemcell/archive.rb +59 -0
- data/lib/bosh/stemcell/archive_filename.rb +29 -0
- data/lib/bosh/stemcell/aws/ami.rb +58 -0
- data/lib/bosh/stemcell/aws/light_stemcell.rb +44 -0
- data/lib/bosh/stemcell/aws/region.rb +15 -0
- data/lib/bosh/stemcell/builder_command.rb +174 -0
- data/lib/bosh/stemcell/builder_options.rb +85 -0
- data/lib/bosh/stemcell/disk_image.rb +61 -0
- data/lib/bosh/stemcell/infrastructure.rb +49 -0
- data/lib/bosh/stemcell/operating_system.rb +31 -0
- data/lib/bosh/stemcell/stage_collection.rb +154 -0
- data/lib/bosh/stemcell/stage_runner.rb +53 -0
- data/lib/bosh/stemcell/version.rb +5 -0
- data/lib/monkeypatch/serverspec/backend/exec.rb +86 -0
- data/spec/assets/fake-stemcell-aws.tgz +0 -0
- data/spec/assets/fake-stemcell-vsphere.tgz +0 -0
- data/spec/assets/light-fake-stemcell-aws.tgz +0 -0
- data/spec/bosh/monkeypatch/serverspec/backend/exec_spec.rb +46 -0
- data/spec/bosh/stemcell/archive_filename_spec.rb +42 -0
- data/spec/bosh/stemcell/archive_spec.rb +98 -0
- data/spec/bosh/stemcell/aws/ami_spec.rb +30 -0
- data/spec/bosh/stemcell/aws/light_stemcell_spec.rb +94 -0
- data/spec/bosh/stemcell/aws/region_spec.rb +12 -0
- data/spec/bosh/stemcell/builder_command_spec.rb +241 -0
- data/spec/bosh/stemcell/builder_options_spec.rb +201 -0
- data/spec/bosh/stemcell/disk_image_spec.rb +163 -0
- data/spec/bosh/stemcell/infrastructure_spec.rb +66 -0
- data/spec/bosh/stemcell/operating_system_spec.rb +47 -0
- data/spec/bosh/stemcell/stage_collection_spec.rb +213 -0
- data/spec/bosh/stemcell/stage_runner_spec.rb +141 -0
- data/spec/bosh/stemcell/version_spec.rb +12 -0
- data/spec/bosh/stemcell_spec.rb +6 -0
- data/spec/spec_helper.rb +6 -0
- data/spec/stemcells/aws_spec.rb +9 -0
- data/spec/stemcells/centos_spec.rb +131 -0
- data/spec/stemcells/openstack_spec.rb +9 -0
- data/spec/stemcells/ubuntu_spec.rb +143 -0
- data/spec/stemcells/vsphere_spec.rb +9 -0
- data/spec/support/rspec_fire.rb +9 -0
- data/spec/support/serverspec.rb +4 -0
- data/spec/support/spec_assets.rb +11 -0
- data/spec/support/stemcell_image.rb +26 -0
- data/spec/support/stemcell_shared_examples.rb +43 -0
- data/spec/support/stub_env.rb +5 -0
- metadata +236 -0
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'rbconfig'
|
2
|
+
require 'bosh_agent/version'
|
3
|
+
require 'bosh/stemcell/archive_filename'
|
4
|
+
|
5
|
+
module Bosh::Stemcell
|
6
|
+
class BuilderOptions
|
7
|
+
def initialize(env, options)
|
8
|
+
@environment = env
|
9
|
+
@infrastructure = options.fetch(:infrastructure)
|
10
|
+
@operating_system = options.fetch(:operating_system)
|
11
|
+
|
12
|
+
@stemcell_version = options.fetch(:stemcell_version)
|
13
|
+
@image_create_disk_size = options.fetch(:disk_size, infrastructure.default_disk_size)
|
14
|
+
@bosh_micro_release_tgz_path = options.fetch(:tarball)
|
15
|
+
end
|
16
|
+
|
17
|
+
def default
|
18
|
+
{
|
19
|
+
'stemcell_name' => "bosh-#{infrastructure.name}-#{infrastructure.hypervisor}-#{operating_system.name}",
|
20
|
+
'stemcell_tgz' => archive_filename.to_s,
|
21
|
+
'stemcell_image_name' => stemcell_image_name,
|
22
|
+
'stemcell_version' => stemcell_version,
|
23
|
+
'stemcell_hypervisor' => infrastructure.hypervisor,
|
24
|
+
'stemcell_infrastructure' => infrastructure.name,
|
25
|
+
'stemcell_operating_system' => operating_system.name,
|
26
|
+
'bosh_protocol_version' => Bosh::Agent::BOSH_PROTOCOL,
|
27
|
+
'ruby_bin' => ruby_bin,
|
28
|
+
'bosh_release_src_dir' => File.join(source_root, 'release/src/bosh'),
|
29
|
+
'bosh_agent_src_dir' => File.join(source_root, 'bosh_agent'),
|
30
|
+
'image_create_disk_size' => image_create_disk_size
|
31
|
+
}.merge(bosh_micro_options).merge(environment_variables).merge(vsphere_options)
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
attr_reader(
|
37
|
+
:environment,
|
38
|
+
:infrastructure,
|
39
|
+
:operating_system,
|
40
|
+
:stemcell_version,
|
41
|
+
:image_create_disk_size,
|
42
|
+
:bosh_micro_release_tgz_path
|
43
|
+
)
|
44
|
+
|
45
|
+
def vsphere_options
|
46
|
+
if infrastructure.name == 'vsphere'
|
47
|
+
{ 'image_vsphere_ovf_ovftool_path' => environment['OVFTOOL'] }
|
48
|
+
else
|
49
|
+
{}
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def environment_variables
|
54
|
+
{
|
55
|
+
'UBUNTU_ISO' => environment['UBUNTU_ISO'],
|
56
|
+
'UBUNTU_MIRROR' => environment['UBUNTU_MIRROR'],
|
57
|
+
}
|
58
|
+
end
|
59
|
+
|
60
|
+
def bosh_micro_options
|
61
|
+
{
|
62
|
+
'bosh_micro_enabled' => 'yes',
|
63
|
+
'bosh_micro_package_compiler_path' => File.join(source_root, 'bosh-release'),
|
64
|
+
'bosh_micro_manifest_yml_path' => File.join(source_root, 'release', 'micro', "#{infrastructure.name}.yml"),
|
65
|
+
'bosh_micro_release_tgz_path' => bosh_micro_release_tgz_path,
|
66
|
+
}
|
67
|
+
end
|
68
|
+
|
69
|
+
def archive_filename
|
70
|
+
ArchiveFilename.new(stemcell_version, infrastructure, operating_system, 'bosh-stemcell', false)
|
71
|
+
end
|
72
|
+
|
73
|
+
def stemcell_image_name
|
74
|
+
"#{infrastructure.name}-#{infrastructure.hypervisor}-#{operating_system.name}.raw"
|
75
|
+
end
|
76
|
+
|
77
|
+
def ruby_bin
|
78
|
+
environment['RUBY_BIN'] || File.join(RbConfig::CONFIG['bindir'], RbConfig::CONFIG['ruby_install_name'])
|
79
|
+
end
|
80
|
+
|
81
|
+
def source_root
|
82
|
+
File.expand_path('../../../../..', __FILE__)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'bosh/core/shell'
|
2
|
+
require 'tmpdir'
|
3
|
+
|
4
|
+
module Bosh::Stemcell
|
5
|
+
class DiskImage
|
6
|
+
|
7
|
+
attr_reader :image_mount_point
|
8
|
+
|
9
|
+
def initialize(options)
|
10
|
+
@image_file_path = options.fetch(:image_file_path)
|
11
|
+
@image_mount_point = options.fetch(:image_mount_point, Dir.mktmpdir)
|
12
|
+
@verbose = options.fetch(:verbose, false)
|
13
|
+
@shell = Bosh::Core::Shell.new
|
14
|
+
end
|
15
|
+
|
16
|
+
def mount
|
17
|
+
device_path = stemcell_loopback_device_name
|
18
|
+
mount_command = "sudo mount #{device_path} #{image_mount_point}"
|
19
|
+
shell.run(mount_command, output_command: verbose)
|
20
|
+
rescue => e
|
21
|
+
raise e unless e.message.include?(mount_command)
|
22
|
+
|
23
|
+
sleep 0.5
|
24
|
+
shell.run(mount_command, output_command: verbose)
|
25
|
+
end
|
26
|
+
|
27
|
+
def unmount
|
28
|
+
shell.run("sudo umount #{image_mount_point}", output_command: verbose)
|
29
|
+
ensure
|
30
|
+
unmap_image
|
31
|
+
end
|
32
|
+
|
33
|
+
def while_mounted
|
34
|
+
mount
|
35
|
+
yield self
|
36
|
+
ensure
|
37
|
+
unmount
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
attr_reader :image_file_path, :verbose, :shell, :device
|
43
|
+
|
44
|
+
def stemcell_loopback_device_name
|
45
|
+
split_output = map_image.split(' ')
|
46
|
+
device_name = split_output[2]
|
47
|
+
|
48
|
+
File.join('/dev/mapper', device_name)
|
49
|
+
end
|
50
|
+
|
51
|
+
def map_image
|
52
|
+
@device = shell.run("sudo losetup --show --find #{image_file_path}", output_command: verbose)
|
53
|
+
shell.run("sudo kpartx -av #{device}", output_command: verbose)
|
54
|
+
end
|
55
|
+
|
56
|
+
def unmap_image
|
57
|
+
shell.run("sudo kpartx -dv #{device}", output_command: verbose)
|
58
|
+
shell.run("sudo losetup -dv #{device}", output_command: verbose)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Bosh::Stemcell
|
2
|
+
module Infrastructure
|
3
|
+
def self.for(name)
|
4
|
+
case name
|
5
|
+
when 'openstack'
|
6
|
+
OpenStack.new
|
7
|
+
when 'aws'
|
8
|
+
Aws.new
|
9
|
+
when 'vsphere'
|
10
|
+
Vsphere.new
|
11
|
+
else
|
12
|
+
raise ArgumentError.new("invalid infrastructure: #{name}")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class Base
|
17
|
+
attr_reader :name, :hypervisor, :default_disk_size
|
18
|
+
|
19
|
+
def initialize(options = {})
|
20
|
+
@name = options.fetch(:name)
|
21
|
+
@supports_light_stemcell = options.fetch(:supports_light_stemcell, false)
|
22
|
+
@hypervisor = options.fetch(:hypervisor)
|
23
|
+
@default_disk_size = options.fetch(:default_disk_size)
|
24
|
+
end
|
25
|
+
|
26
|
+
def light?
|
27
|
+
@supports_light_stemcell
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class OpenStack < Base
|
32
|
+
def initialize
|
33
|
+
super(name: 'openstack', hypervisor: 'kvm', default_disk_size: 10240)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class Vsphere < Base
|
38
|
+
def initialize
|
39
|
+
super(name: 'vsphere', hypervisor: 'esxi', default_disk_size: 2048)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class Aws < Base
|
44
|
+
def initialize
|
45
|
+
super(name: 'aws', hypervisor: 'xen', supports_light_stemcell: true, default_disk_size: 2048)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Bosh::Stemcell
|
2
|
+
module OperatingSystem
|
3
|
+
def self.for(operating_system_name)
|
4
|
+
case operating_system_name
|
5
|
+
when 'centos' then Centos.new
|
6
|
+
when 'ubuntu' then Ubuntu.new
|
7
|
+
else raise ArgumentError.new("invalid operating system: #{operating_system_name}")
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class Base
|
12
|
+
attr_reader :name
|
13
|
+
|
14
|
+
def initialize(options = {})
|
15
|
+
@name = options.fetch(:name)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class Centos < Base
|
20
|
+
def initialize
|
21
|
+
super(name: 'centos')
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class Ubuntu < Base
|
26
|
+
def initialize
|
27
|
+
super(name: 'ubuntu')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,154 @@
|
|
1
|
+
require 'bosh/stemcell/infrastructure'
|
2
|
+
require 'bosh/stemcell/operating_system'
|
3
|
+
|
4
|
+
module Bosh::Stemcell
|
5
|
+
class StageCollection
|
6
|
+
|
7
|
+
def initialize(options)
|
8
|
+
@infrastructure = options.fetch(:infrastructure)
|
9
|
+
@operating_system = options.fetch(:operating_system)
|
10
|
+
end
|
11
|
+
|
12
|
+
def operating_system_stages
|
13
|
+
case operating_system
|
14
|
+
when OperatingSystem::Centos then
|
15
|
+
[:base_centos, :base_yum] + hacked_centos_common
|
16
|
+
when OperatingSystem::Ubuntu then
|
17
|
+
[:base_debootstrap, :base_apt] + common_stages
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def infrastructure_stages
|
22
|
+
case infrastructure
|
23
|
+
when Infrastructure::Aws then
|
24
|
+
aws_stages
|
25
|
+
when Infrastructure::OpenStack then
|
26
|
+
openstack_stages
|
27
|
+
when Infrastructure::Vsphere then
|
28
|
+
operating_system.instance_of?(OperatingSystem::Centos) ? hacked_centos_vsphere : vsphere_stages
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
attr_reader :infrastructure, :operating_system
|
35
|
+
|
36
|
+
def hacked_centos_common
|
37
|
+
[
|
38
|
+
# Bosh steps
|
39
|
+
:bosh_users,
|
40
|
+
:bosh_monit,
|
41
|
+
:bosh_ruby,
|
42
|
+
:bosh_agent,
|
43
|
+
#:bosh_sysstat,
|
44
|
+
#:bosh_sysctl,
|
45
|
+
#:bosh_ntpdate,
|
46
|
+
:bosh_sudoers,
|
47
|
+
# Micro BOSH
|
48
|
+
:bosh_micro,
|
49
|
+
# Install GRUB/kernel/etc
|
50
|
+
:system_grub,
|
51
|
+
#:system_kernel,
|
52
|
+
]
|
53
|
+
end
|
54
|
+
|
55
|
+
def hacked_centos_vsphere
|
56
|
+
[
|
57
|
+
#:system_open_vm_tools,
|
58
|
+
:system_parameters,
|
59
|
+
:bosh_clean,
|
60
|
+
#:bosh_harden,
|
61
|
+
#:bosh_dpkg_list,
|
62
|
+
:image_create,
|
63
|
+
:image_install_grub,
|
64
|
+
:image_vsphere_vmx,
|
65
|
+
:image_vsphere_ovf,
|
66
|
+
:image_vsphere_prepare_stemcell,
|
67
|
+
:stemcell
|
68
|
+
]
|
69
|
+
end
|
70
|
+
|
71
|
+
def common_stages
|
72
|
+
[
|
73
|
+
# Bosh steps
|
74
|
+
:bosh_users,
|
75
|
+
:bosh_monit,
|
76
|
+
:bosh_ruby,
|
77
|
+
:bosh_agent,
|
78
|
+
:bosh_sysstat,
|
79
|
+
:bosh_sysctl,
|
80
|
+
:bosh_ntpdate,
|
81
|
+
:bosh_sudoers,
|
82
|
+
# Micro BOSH
|
83
|
+
:bosh_micro,
|
84
|
+
# Install GRUB/kernel/etc
|
85
|
+
:system_grub,
|
86
|
+
:system_kernel,
|
87
|
+
]
|
88
|
+
end
|
89
|
+
|
90
|
+
def aws_stages
|
91
|
+
[
|
92
|
+
# Misc
|
93
|
+
:system_aws_network,
|
94
|
+
:system_aws_clock,
|
95
|
+
:system_aws_modules,
|
96
|
+
:system_parameters,
|
97
|
+
# Finalisation
|
98
|
+
:bosh_clean,
|
99
|
+
:bosh_harden,
|
100
|
+
:bosh_harden_ssh,
|
101
|
+
:bosh_dpkg_list,
|
102
|
+
# Image/bootloader
|
103
|
+
:image_create,
|
104
|
+
:image_install_grub,
|
105
|
+
:image_aws_update_grub,
|
106
|
+
:image_aws_prepare_stemcell,
|
107
|
+
# Final stemcell
|
108
|
+
:stemcell
|
109
|
+
]
|
110
|
+
end
|
111
|
+
|
112
|
+
def openstack_stages
|
113
|
+
[
|
114
|
+
# Misc
|
115
|
+
:system_openstack_network,
|
116
|
+
:system_openstack_clock,
|
117
|
+
:system_openstack_modules,
|
118
|
+
:system_parameters,
|
119
|
+
# Finalisation,
|
120
|
+
:bosh_clean,
|
121
|
+
:bosh_harden,
|
122
|
+
:bosh_harden_ssh,
|
123
|
+
:bosh_dpkg_list,
|
124
|
+
# Image/bootloader
|
125
|
+
:image_create,
|
126
|
+
:image_install_grub,
|
127
|
+
:image_openstack_qcow2,
|
128
|
+
:image_openstack_prepare_stemcell,
|
129
|
+
# Final stemcell
|
130
|
+
:stemcell_openstack
|
131
|
+
]
|
132
|
+
end
|
133
|
+
|
134
|
+
def vsphere_stages
|
135
|
+
[
|
136
|
+
:system_open_vm_tools,
|
137
|
+
# Misc
|
138
|
+
:system_parameters,
|
139
|
+
# Finalisation
|
140
|
+
:bosh_clean,
|
141
|
+
:bosh_harden,
|
142
|
+
:bosh_dpkg_list,
|
143
|
+
# Image/bootloader
|
144
|
+
:image_create,
|
145
|
+
:image_install_grub,
|
146
|
+
:image_vsphere_vmx,
|
147
|
+
:image_vsphere_ovf,
|
148
|
+
:image_vsphere_prepare_stemcell,
|
149
|
+
# Final stemcell
|
150
|
+
:stemcell
|
151
|
+
]
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'bosh/core/shell'
|
2
|
+
|
3
|
+
module Bosh::Stemcell
|
4
|
+
class StageRunner
|
5
|
+
def initialize(options)
|
6
|
+
@build_path = options.fetch(:build_path)
|
7
|
+
@command_env = options.fetch(:command_env)
|
8
|
+
@settings_file = options.fetch(:settings_file)
|
9
|
+
@work_path = options.fetch(:work_path)
|
10
|
+
end
|
11
|
+
|
12
|
+
def configure_and_apply(stages)
|
13
|
+
configure(stages)
|
14
|
+
apply(stages)
|
15
|
+
end
|
16
|
+
|
17
|
+
def configure(stages)
|
18
|
+
stages.each do |stage|
|
19
|
+
stage_config_script = File.join(build_path, 'stages', stage.to_s, 'config.sh')
|
20
|
+
|
21
|
+
puts "=== Configuring '#{stage}' stage ==="
|
22
|
+
if File.exists?(stage_config_script) && File.executable?(stage_config_script)
|
23
|
+
run_sudo_with_command_env("#{stage_config_script} #{settings_file}")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def apply(stages)
|
29
|
+
work_directory = File.join(work_path, 'work')
|
30
|
+
|
31
|
+
stages.each do |stage|
|
32
|
+
FileUtils.mkdir_p(work_directory)
|
33
|
+
|
34
|
+
puts "=== Applying '#{stage}' stage ==="
|
35
|
+
puts "== Started #{Time.now.strftime('%a %b %e %H:%M:%S %Z %Y')} =="
|
36
|
+
|
37
|
+
stage_apply_script = File.join(build_path, 'stages', stage.to_s, 'apply.sh')
|
38
|
+
|
39
|
+
run_sudo_with_command_env("#{stage_apply_script} #{work_directory}")
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
attr_reader :stages, :build_path, :command_env, :settings_file, :work_path
|
46
|
+
|
47
|
+
def run_sudo_with_command_env(command)
|
48
|
+
shell = Bosh::Core::Shell.new
|
49
|
+
|
50
|
+
shell.run("sudo #{command_env} #{command} 2>&1")
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|