linecook-gem 0.7.35 → 0.7.36
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/linecook-gem/image/s3.rb +1 -1
- data/lib/linecook-gem/packager/packer.rb +4 -1
- data/lib/linecook-gem/packager/packer/ami.rb +89 -0
- data/lib/linecook-gem/packager/packer/base.rb +126 -0
- data/lib/linecook-gem/packager/packer/gcp.rb +118 -0
- data/lib/linecook-gem/version.rb +1 -1
- metadata +4 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4c609eabae7f16453cf3a38d0de4637acc199f84
|
4
|
+
data.tar.gz: 6406d3fe9102552f5ee59886f38cb55514245015
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f3f8e661860c24c3933737251b06c2477646f184ca2d78af8b84acb2d208de4845793a8587875d7be5ef3172c37d03ed45d9ab0552d1dd535a05cce6b5ae1f5f
|
7
|
+
data.tar.gz: 6e1584143c306beb4d32f211080fd08d2ae70301f72e39087b6249d29d9220322b07806513695d7350933d72f93543f22b2eb561da25b2a095b3a9c8eb649d71
|
@@ -39,7 +39,7 @@ module Linecook
|
|
39
39
|
fid = File.basename(path)
|
40
40
|
pbar = ProgressBar.create(title: fid, total: file.size)
|
41
41
|
common_opts = { bucket: Linecook.config[:aws][:s3][:bucket], key: File.join([PREFIX, group, fid].compact) }
|
42
|
-
resp = client.create_multipart_upload(storage_class: '
|
42
|
+
resp = client.create_multipart_upload(storage_class: 'STANDARD', server_side_encryption: 'AES256', **common_opts)
|
43
43
|
id = resp.upload_id
|
44
44
|
part = 0
|
45
45
|
total = 0
|
@@ -61,7 +61,10 @@ module Linecook
|
|
61
61
|
'update-grub',
|
62
62
|
'rm -f /etc/init/fake-container-events.conf', # HACK
|
63
63
|
'mkdir -p /run/resolvconf/interface',
|
64
|
-
'
|
64
|
+
'echo "resolvconf resolvconf/linkify-resolvconf boolean true" | debconf-set-selections', # write debconf
|
65
|
+
'dpkg-reconfigure -f noninteractive resolvconf', # re-linkify resolvconf
|
66
|
+
'truncate --size 0 /etc/resolv.conf', # clear build resolvconf config
|
67
|
+
'truncate --size 0 /etc/resolvconf/resolv.conf.d/original' # clear build resolvconf config
|
65
68
|
]
|
66
69
|
|
67
70
|
def initialize(config)
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'linecook-gem/packager/packer/base'
|
2
|
+
require 'linecook-gem/packager/route53'
|
3
|
+
|
4
|
+
module Linecook
|
5
|
+
class AmiPacker < Linecook::Packer
|
6
|
+
|
7
|
+
ROOT_DEVICE_MAP = {
|
8
|
+
device_name: 'xvda',
|
9
|
+
delete_on_termination: true
|
10
|
+
}
|
11
|
+
|
12
|
+
BUILDER_CONFIG = {
|
13
|
+
type: 'amazon-chroot',
|
14
|
+
access_key: '{{ user `aws_access_key` }}',
|
15
|
+
secret_key: '{{ user `aws_secret_key` }}',
|
16
|
+
ami_name: 'packer-image.{{ user `image_name` }} {{timestamp}}',
|
17
|
+
from_scratch: true,
|
18
|
+
root_device_name: ROOT_DEVICE_MAP[:device_name],
|
19
|
+
ami_block_device_mappings: [ ROOT_DEVICE_MAP ],
|
20
|
+
pre_mount_commands: PRE_MOUNT_COMMANDS,
|
21
|
+
post_mount_commands: POST_MOUNT_COMMANDS,
|
22
|
+
}.freeze
|
23
|
+
|
24
|
+
|
25
|
+
def initialize(config)
|
26
|
+
system("#{packer_path} --version")
|
27
|
+
@hvm = config[:hvm] || true
|
28
|
+
@root_size = config[:root_size] || 10
|
29
|
+
@region = config[:region] || 'us-east-1'
|
30
|
+
@copy_regions = config[:copy_regions] || []
|
31
|
+
@accounts = config[:account_ids] || []
|
32
|
+
@write_txt = Linecook.config[:packager] && Linecook.config[:packager][:ami] && Linecook.config[:packager][:ami][:update_txt]
|
33
|
+
end
|
34
|
+
|
35
|
+
def package(image, directory)
|
36
|
+
super(image, directory)
|
37
|
+
extract_amis_from_output
|
38
|
+
end
|
39
|
+
private
|
40
|
+
|
41
|
+
# TO DO:
|
42
|
+
# support for multiple accounts, multiple regions
|
43
|
+
# code to extract ami name(s) from output
|
44
|
+
# amis = `grep "amazon-ebs,artifact,0,id" packer.log`.chomp.split(',')[5].split('%!(PACKER_COMMA)')
|
45
|
+
# route53 TXT record integration
|
46
|
+
|
47
|
+
def generate_config(packager)
|
48
|
+
packager ||= {}
|
49
|
+
config = {
|
50
|
+
variables: {
|
51
|
+
aws_access_key: Linecook.config[:aws][:access_key],
|
52
|
+
aws_secret_key: Linecook.config[:aws][:secret_key],
|
53
|
+
image_name: "linecook-#{@image.id}",
|
54
|
+
source_image_path: @image.path
|
55
|
+
},
|
56
|
+
builders: [
|
57
|
+
BUILDER_CONFIG.merge(
|
58
|
+
ami_users: @accounts,
|
59
|
+
ami_regions: @copy_regions,
|
60
|
+
ami_virtualization_type: virt_type,
|
61
|
+
root_volume_size: @root_size
|
62
|
+
).deep_merge(packager[:builder] || {})
|
63
|
+
],
|
64
|
+
provisioners: build_provisioner(CHROOT_COMMANDS)
|
65
|
+
}
|
66
|
+
|
67
|
+
unless config[:builders].first[:ami_block_device_mappings].find { |x| x[:device_name] == ROOT_DEVICE_MAP[:device_name] }
|
68
|
+
config[:builders].first[:ami_block_device_mappings].prepend ROOT_DEVICE_MAP
|
69
|
+
end
|
70
|
+
JSON.pretty_generate(config)
|
71
|
+
end
|
72
|
+
|
73
|
+
def extract_amis_from_output
|
74
|
+
amis = @output.grep(/amazon-chroot,artifact,0,id/).first.chomp.split(',')[5].split('%!(PACKER_COMMA)')
|
75
|
+
amis.each do |info_str|
|
76
|
+
ami_info = info_str.split(':')
|
77
|
+
ami_region = ami_info[0]
|
78
|
+
ami_id = ami_info[1]
|
79
|
+
puts "Built #{ami_id} for #{ami_region}"
|
80
|
+
Linecook::Route53.upsert_record(@image.name, ami_id, ami_region) if @write_txt
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def virt_type
|
85
|
+
@hvm ? 'hvm' : 'paravirtual'
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'mkmf'
|
3
|
+
require 'fileutils'
|
4
|
+
require 'open-uri'
|
5
|
+
require 'tempfile'
|
6
|
+
require 'tmpdir'
|
7
|
+
require 'pty'
|
8
|
+
|
9
|
+
require 'linecook-gem/image'
|
10
|
+
require 'linecook-gem/util/downloader'
|
11
|
+
require 'linecook-gem/util/locking'
|
12
|
+
require 'linecook-gem/util/common'
|
13
|
+
|
14
|
+
module Linecook
|
15
|
+
class Packer
|
16
|
+
|
17
|
+
include Downloader
|
18
|
+
include Locking
|
19
|
+
|
20
|
+
SOURCE_URL = 'https://releases.hashicorp.com/packer/'
|
21
|
+
PACKER_VERSION = '0.12.0'
|
22
|
+
PACKER_PATH = File.join(Linecook::Config::LINECOOK_HOME, 'bin', 'packer')
|
23
|
+
|
24
|
+
PRE_MOUNT_COMMANDS = [
|
25
|
+
'parted -s {{.Device}} mklabel msdos',
|
26
|
+
'parted -s {{.Device}} mkpart primary ext2 0% 100%',
|
27
|
+
'mkfs.ext4 {{.Device}}1',
|
28
|
+
'tune2fs -L cloudimg-rootfs {{.Device}}1',
|
29
|
+
]
|
30
|
+
|
31
|
+
POST_MOUNT_COMMANDS = [
|
32
|
+
'tar -C {{.MountPath}} -xpf {{ user `source_image_path` }}',
|
33
|
+
'cp /etc/resolv.conf {{.MountPath}}/etc',
|
34
|
+
'echo "LABEL=cloudimg-rootfs / ext4 defaults,discard 0 0" > {{.MountPath}}/etc/fstab',
|
35
|
+
'grub-install --root-directory={{.MountPath}} {{.Device}}',
|
36
|
+
'rm -rf {{.MountPath}}/etc/network',
|
37
|
+
'cp -r /etc/network {{.MountPath}}/etc/',
|
38
|
+
]
|
39
|
+
|
40
|
+
CHROOT_COMMANDS = [
|
41
|
+
'apt-get update',
|
42
|
+
'DEBIAN_FRONTEND=noninteractive apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" -y --force-yes --no-upgrade install grub-pc grub-legacy-ec2', # FIXME - ec2 specific
|
43
|
+
'update-grub',
|
44
|
+
'rm -f /etc/init/fake-container-events.conf', # HACK
|
45
|
+
'mkdir -p /run/resolvconf/interface',
|
46
|
+
'DEBIAN_FRONTEND=noninteractive dpkg-reconfigure resolvconf' # re-linkify resolvconf
|
47
|
+
]
|
48
|
+
|
49
|
+
def initialize
|
50
|
+
raise 'Not implemented'
|
51
|
+
end
|
52
|
+
|
53
|
+
def package(image, directory)
|
54
|
+
@image = image
|
55
|
+
kitchen_config = load_config(directory).send(:data).instance_variable_get(:@data)
|
56
|
+
image_config = kitchen_config[:suites].find{ |x| x[:name] == image.name }
|
57
|
+
if image_config && image_config[:packager]
|
58
|
+
packager = image_config[:packager] || {}
|
59
|
+
end
|
60
|
+
conf_file = Tempfile.new("#{@image.id}-packer.json")
|
61
|
+
config = generate_config(packager)
|
62
|
+
conf_file.write(config)
|
63
|
+
conf_file.close
|
64
|
+
@output = []
|
65
|
+
PTY.spawn("sudo #{PACKER_PATH} build -machine-readable #{conf_file.path}") do |stdout, _, _|
|
66
|
+
begin
|
67
|
+
stdout.each do |line|
|
68
|
+
@output << line if line =~ /artifact/
|
69
|
+
tokens = line.split(',')
|
70
|
+
if tokens.length > 4
|
71
|
+
out = tokens[4].gsub('%!(PACKER_COMMA)', ',')
|
72
|
+
time = DateTime.strptime(tokens[0], '%s').strftime('%c')
|
73
|
+
puts "#{time} | #{out}"
|
74
|
+
else
|
75
|
+
puts "unexpected output format"
|
76
|
+
puts tokens
|
77
|
+
end
|
78
|
+
end
|
79
|
+
rescue Errno::EIO
|
80
|
+
puts "Packer finshed executing"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
ensure
|
84
|
+
conf_file.close
|
85
|
+
conf_file.unlink
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
def generate_config(packager)
|
91
|
+
raise 'Not implemented'
|
92
|
+
end
|
93
|
+
|
94
|
+
def build_provisioner(chroot_commands)
|
95
|
+
provisioner = [
|
96
|
+
{
|
97
|
+
type: 'shell',
|
98
|
+
inline: chroot_commands
|
99
|
+
}
|
100
|
+
]
|
101
|
+
end
|
102
|
+
|
103
|
+
def packer_path
|
104
|
+
@path ||= begin
|
105
|
+
found = File.exists?(PACKER_PATH) ? PACKER_PATH : find_executable('packer')
|
106
|
+
path = if found
|
107
|
+
version = `#{found} --version`
|
108
|
+
Gem::Version.new(version) >= Gem::Version.new(PACKER_VERSION) ? found : nil
|
109
|
+
end
|
110
|
+
path ||= get_packer
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def get_packer
|
115
|
+
puts "packer too old (<#{PACKER_VERSION}) or not present, getting latest packer"
|
116
|
+
arch = 1.size == 8 ? 'amd64' : '386'
|
117
|
+
|
118
|
+
FileUtils.rm_f(Dir[File.join(File.dirname(PACKER_PATH), "*")])
|
119
|
+
path = File.join(File.dirname(PACKER_PATH), 'packer.zip')
|
120
|
+
url = File.join(SOURCE_URL, PACKER_VERSION, "packer_#{PACKER_VERSION}_linux_#{arch}.zip")
|
121
|
+
download(url, path)
|
122
|
+
unzip(path)
|
123
|
+
PACKER_PATH
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
require 'fog/google'
|
2
|
+
|
3
|
+
require 'linecook-gem/packager/packer/base'
|
4
|
+
|
5
|
+
module Linecook
|
6
|
+
class GCPPacker < Linecook::Packer
|
7
|
+
|
8
|
+
BUILDER_CONFIG = {
|
9
|
+
type: 'null',
|
10
|
+
}.freeze
|
11
|
+
|
12
|
+
# run with 'shell-local'
|
13
|
+
PRE_MOUNT_COMMANDS = [
|
14
|
+
|
15
|
+
# create a sparse image with dd
|
16
|
+
"dd if=/dev/zero of=#{image_path} bs=1 count=0 seek=#{image_size}",
|
17
|
+
"parted -s $(losetup | grep #{image_path} | awk '{print $1}') mklabel msdos",
|
18
|
+
"parted -s $(losetup | grep #{image_path} | awk '{print $1}') mkpart primary ext4 0% 100%",
|
19
|
+
"mkfs.ext4 $(losetup | grep #{image_path} | awk '{print $1}')p1",
|
20
|
+
"tune2fs -L cloudimg-rootfs $(losetup | grep #{image_path} | awk '{print $1}')p1",
|
21
|
+
"mount $(losetup | grep #{image_path} | awk '{print $1}')p1 /mnt/#{build_uuid}"
|
22
|
+
]
|
23
|
+
|
24
|
+
CHROOT_SETUP = [
|
25
|
+
# tar -C "${MOUNT_PATH}" -xpf "${TAR_PATH}"
|
26
|
+
#
|
27
|
+
#mount --bind /dev "${MOUNT_PATH}"/dev
|
28
|
+
#mount --bind /proc "${MOUNT_PATH}"/proc
|
29
|
+
#mount --bind /sys "${MOUNT_PATH}"/sys
|
30
|
+
#
|
31
|
+
#echo "LABEL=cloudimg-rootfs / ext4 defaults,discard 0 0" >> "${MOUNT_PATH}"/etc/fstab
|
32
|
+
]
|
33
|
+
|
34
|
+
CHROOT_COMMNANDS_EXTRA = [
|
35
|
+
#APT_PACKAGES=(
|
36
|
+
# grub-pc
|
37
|
+
# cloud-init
|
38
|
+
# cloud-initramfs-growroot
|
39
|
+
# gce-daemon
|
40
|
+
# gce-startup-scripts
|
41
|
+
# gce-image-bundle
|
42
|
+
# gce-cloud-config
|
43
|
+
#)
|
44
|
+
#
|
45
|
+
#DEBIAN_FRONTEND=noninteractive apt-get -o Dpkg::Options::="--force-confdef" \
|
46
|
+
# -o Dpkg::Options::="--force-confold" -y --force-yes --no-upgrade install "${APT_PACKAGES}"
|
47
|
+
#
|
48
|
+
#rm -f /etc/hostname
|
49
|
+
#ln -s /usr/share/google/set-hostname /etc/dhcp/dhclient-exit-hooks.d/
|
50
|
+
#
|
51
|
+
#echo "169.254.169.254 metadata.google.internal metadata" >> /etc/hosts
|
52
|
+
#echo "127.0.0.1 localhost" >> /etc/hosts
|
53
|
+
]
|
54
|
+
|
55
|
+
CHROOT_UNMOUNT = [
|
56
|
+
"umount /mnt/#{build_uuid}/dev",
|
57
|
+
"umount /mnt/#{build_uuid}/sys",
|
58
|
+
"umount /mnt/#{build_uuid}/proc",
|
59
|
+
"umount /mnt/#{build_uuid}"
|
60
|
+
]
|
61
|
+
|
62
|
+
COMPRESS_IMAGE = [
|
63
|
+
"losetup -d $(losetup | grep #{image_path} | awk '{print $1}')",
|
64
|
+
"mkdir -p /tmp/#{build_uuid}",
|
65
|
+
"mv #{image_path} /tmp/#{build_uuid}/disk.raw", #must be called disk.raw
|
66
|
+
"cd /tmp/#{build_uuid} && tar -czvf #{build_uuid}.tar.gz disk.raw",
|
67
|
+
"rm /tmp#{build_uuid}/disk.raw"
|
68
|
+
]
|
69
|
+
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def upload
|
74
|
+
connection = Fog::Storage::Google.new
|
75
|
+
|
76
|
+
image_source = File.open("/tmp/#{build_uuid}/#{build_uuid}.tar.gz")
|
77
|
+
connection.put_object("bucket", "#{image_name}-#{build_uuid}.tar.gz", image_source)
|
78
|
+
image_source.close
|
79
|
+
image_source.unlink
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
def create_gcp_image
|
84
|
+
connection = Fog::Compute.new(:provider => "Google")
|
85
|
+
|
86
|
+
rawdisk = {
|
87
|
+
source: "gs://#{bucket}/#{image_slug}",
|
88
|
+
container_type: "TAR"
|
89
|
+
}
|
90
|
+
|
91
|
+
|
92
|
+
img = connection.images.create(name: "test-image", # FIXME - from config
|
93
|
+
description: "Test image (via fog)", # FIXME - from config
|
94
|
+
raw_disk: rawdisk)
|
95
|
+
|
96
|
+
img.reload # will raise if image was not saved correctly
|
97
|
+
end
|
98
|
+
|
99
|
+
# run with 'shell-local' and "execute_command"
|
100
|
+
# https://www.packer.io/docs/provisioners/shell-local.html
|
101
|
+
# to wrap everything with chroot
|
102
|
+
|
103
|
+
# Rather than use the 'googlecloud' provider in packer, which would require us to spin up a VM
|
104
|
+
# We post-process the image locally, and upload it to google cloud. Google is able to deal with tarballs
|
105
|
+
# directly, so there's no need for a fancy chroot builder.
|
106
|
+
#
|
107
|
+
# Gist of how it works:
|
108
|
+
# 1. Use a null builder to post-process a linecook image into an acceptable format for google
|
109
|
+
# 2. Snapshot that image as a tarball
|
110
|
+
# 3. Upload that image to google storage
|
111
|
+
# 4. Create a google compute image from the tarball URL. https://cloud.google.com/compute/docs/images/import-existing-image
|
112
|
+
|
113
|
+
|
114
|
+
# https://github.com/Shopify/google-cloud-images/blob/master/deps/chroot-commands.sh
|
115
|
+
# https://github.com/Shopify/google-cloud-images/blob/master/deps/generate-image.sh
|
116
|
+
|
117
|
+
end
|
118
|
+
end
|
data/lib/linecook-gem/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: linecook-gem
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.7.
|
4
|
+
version: 0.7.36
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dale Hamel
|
@@ -283,6 +283,9 @@ files:
|
|
283
283
|
- lib/linecook-gem/image/s3.rb
|
284
284
|
- lib/linecook-gem/packager.rb
|
285
285
|
- lib/linecook-gem/packager/packer.rb
|
286
|
+
- lib/linecook-gem/packager/packer/ami.rb
|
287
|
+
- lib/linecook-gem/packager/packer/base.rb
|
288
|
+
- lib/linecook-gem/packager/packer/gcp.rb
|
286
289
|
- lib/linecook-gem/packager/route53.rb
|
287
290
|
- lib/linecook-gem/packager/squashfs.rb
|
288
291
|
- lib/linecook-gem/util/common.rb
|