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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d3cf921c31e786054ae969f8e6c1a90353d29425
4
- data.tar.gz: dd9d3643c179ea74141cb2758b62274caff13d8b
3
+ metadata.gz: 4c609eabae7f16453cf3a38d0de4637acc199f84
4
+ data.tar.gz: 6406d3fe9102552f5ee59886f38cb55514245015
5
5
  SHA512:
6
- metadata.gz: 530ee97b09e4364cd13f05c09dbd68e8e0f2e55025a9e0473ae2e3aebccc45548f7f31400897385cc0f4299c8e71724e1ed193c19cd813d74af1cabeee1e2b06
7
- data.tar.gz: ff3bfd89ba139e6e3d0f43a3b5368e897d6e53d8cf4e57e3eb431f4b58591694dfa1c8d0279c9c4d5500fad6788e9f01af42af8ad43fedaed924fac0087ddd2e
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: 'REDUCED_REDUNDANCY', server_side_encryption: 'AES256', **common_opts)
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
- 'DEBIAN_FRONTEND=noninteractive dpkg-reconfigure resolvconf' # re-linkify resolvconf
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
@@ -1,3 +1,3 @@
1
1
  module Linecook
2
- VERSION = '0.7.35'
2
+ VERSION = '0.7.36'
3
3
  end
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.35
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