linecook-gem 0.6.10 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,62 @@
1
+ require 'aws-sdk'
2
+
3
+ module Linecook
4
+ module Route53
5
+ extend self
6
+
7
+ def upsert_record(name, ami, region)
8
+ ami_config = Linecook.config[:packager][:ami]
9
+
10
+ zone = [ami_config[:zone], ami_config[:regions][region.to_sym], ami_config[:domain]].compact.join('.')
11
+ record = "#{name}.#{zone}"
12
+
13
+ resp = client.list_hosted_zones_by_name({
14
+ dns_name: zone,
15
+ max_items: 1,
16
+ })
17
+
18
+ if resp.hosted_zones.size < 1
19
+ puts "Failed to find dns zone: #{resp.dns_name}"
20
+ return false
21
+ end
22
+
23
+
24
+ zone_id = resp.hosted_zones[0].id
25
+ client.change_resource_record_sets({
26
+ hosted_zone_id: zone_id,
27
+ change_batch: {
28
+ comment: "create #{ami}",
29
+ changes: [
30
+ {
31
+ action: "UPSERT",
32
+ resource_record_set: {
33
+ name: record,
34
+ type: 'TXT',
35
+ ttl: 1,
36
+ resource_records: [
37
+ {
38
+ value: "\"#{ami}\"",
39
+ },
40
+ ],
41
+ },
42
+ },
43
+ ],
44
+ },
45
+ })
46
+ puts "Saved #{ami} to #{record}"
47
+ rescue Aws::Route53::Errors::ServiceError => e
48
+ puts "AWS Error: #{e.code} #{e.context.http_response.body_contents}"
49
+ return false
50
+ end
51
+
52
+ private
53
+
54
+ def client
55
+ @client ||= begin
56
+ Aws.config[:credentials] = Aws::Credentials.new(Linecook.config[:aws][:access_key], Linecook.config[:aws][:secret_key])
57
+ Aws.config[:region] = 'us-east-1'
58
+ Aws::Route53::Client.new
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,51 @@
1
+ require 'mkmf'
2
+ require 'fileutils'
3
+ require 'tmpdir'
4
+
5
+ require 'linecook-gem/image'
6
+
7
+ module Linecook
8
+ class Squashfs
9
+
10
+ EXCLUDE_PROFILES = {
11
+ common: [
12
+ 'dev/*',
13
+ 'sys/*',
14
+ 'proc/*',
15
+ 'run/*',
16
+ 'tmp/*',
17
+ 'home/kitchen',
18
+ 'etc/sudoers.d/kitchen',
19
+ '.docker*',
20
+ ],
21
+ ubuntu: [
22
+ 'usr/src',
23
+ 'var/lib/apt/lists/archive*',
24
+ 'var/cache/apt/archives*'
25
+ ]
26
+ }.freeze
27
+
28
+ def initialize(config)
29
+ @excludes = []
30
+ @excludes << EXCLUDE_PROFILES[:common]
31
+ @excludes << EXCLUDE_PROFILES[config[:distro]] if config[:distro]
32
+ @excludes << config[:excludes] if config[:excludes]
33
+ @excludes.flatten!
34
+ @outdir = config[:outdir] || Dir.pwd
35
+ end
36
+
37
+ def package(image)
38
+ FileUtils.mkdir_p(@outdir)
39
+ tmpdir = Dir.mktmpdir("#{image.id}-squashfs")
40
+ outfile = File.join(@outdir, "#{image.id}.squashfs")
41
+ puts "Extracting #{image.id} to temporary directory #{tmpdir}..."
42
+ system("sudo tar -C #{tmpdir} -xpf #{image.path}")
43
+ system("sudo mksquashfs #{tmpdir} #{outfile} -noappend -wildcards -e #{@excludes.map { |e| "'#{e}'" }.join(' ')}")
44
+ puts "Squashed image is at #{outfile}"
45
+ ensure
46
+ puts "Cleaning up #{tmpdir}..."
47
+ system("sudo rm -rf #{tmpdir}")
48
+ end
49
+
50
+ end
51
+ end
@@ -5,18 +5,14 @@ require 'securerandom'
5
5
  require 'zip'
6
6
  require 'ruby-progressbar'
7
7
 
8
- require 'linecook-gem/image/crypt'
9
-
10
8
  module Linecook
11
9
  module Downloader
12
10
  LOCK_WAIT_TIMEOUT = 180
13
11
 
14
- def self.download(url, path, encrypted: false)
15
- acquire_lock(path)
12
+ def download(url, path)
16
13
  FileUtils.mkdir_p(File.dirname(path))
17
14
  cryptfile = "#{File.basename(path)}-encrypted-#{SecureRandom.hex(4)}"
18
- destination = encrypted ? File.join('/tmp', cryptfile) : path
19
- File.open(destination, 'w') do |f|
15
+ File.open(path, 'w') do |f|
20
16
  pbar = ProgressBar.create(title: File.basename(path), total: nil)
21
17
  IO.copy_stream(open(url,
22
18
  content_length_proc: lambda do|t|
@@ -26,17 +22,9 @@ module Linecook
26
22
  pbar.progress = s
27
23
  end), f)
28
24
  end
29
-
30
- if encrypted
31
- Linecook::Crypto.new.decrypt_file(destination, dest: path)
32
- FileUtils.rm_f(destination)
33
- end
34
- ensure
35
- unlock(path)
36
25
  end
37
26
 
38
-
39
- def self.unzip(source, dest: nil)
27
+ def unzip(source, dest: nil)
40
28
  puts "Extracting #{source}..."
41
29
  dest ||= File.dirname(source)
42
30
  Zip::File.open(source) do |zip_file|
@@ -47,32 +35,5 @@ module Linecook
47
35
  end
48
36
  end
49
37
  end
50
-
51
- private
52
-
53
- def self.acquire_lock(path)
54
- attempts = 0
55
- while attempts < LOCK_WAIT_TIMEOUT
56
- return lock(path) unless locked?(path)
57
- attempts += 1
58
- sleep(1)
59
- end
60
- end
61
-
62
- def self.locked?(path)
63
- File.exists?(lockfile(path)) && (true if Process.kill(0, File.read(lockfile(path))) rescue false)
64
- end
65
-
66
- def self.lock(path)
67
- File.write(lockfile(path), Process.pid.to_s)
68
- end
69
-
70
- def self.unlock(path)
71
- FileUtils.rm_f(lockfile(path))
72
- end
73
-
74
- def self.lockfile(path)
75
- "/tmp/#{File.basename(path)}-flock"
76
- end
77
38
  end
78
39
  end
@@ -0,0 +1,47 @@
1
+ require 'json'
2
+
3
+ require 'kitchen/configurable'
4
+
5
+ # FIXME - overhaul linecook config
6
+ # be able to read kitchen configs
7
+
8
+ module Linecook
9
+ class Secrets
10
+
11
+ SECRETS_PATH = File.join(Dir.pwd, 'secrets.ejson').freeze
12
+
13
+ include Configurable
14
+
15
+ def initialize(config = {})
16
+ init_config(config)
17
+ end
18
+
19
+ # CONFIG_PATH = File.join(Dir.pwd, 'linecook.yml').freeze # File.expand_path('../../../config/config.yml', __FILE__)
20
+ # LINECOOK_HOME = File.expand_path('~/.linecook').freeze
21
+ # DEFAULT_CONFIG = {
22
+ # packager: {
23
+ # provider: :ebs,
24
+ # ebs: {
25
+ # hvm: true,
26
+ # size: 10,
27
+ # region: 'us-east-1',
28
+ # copy_regions: [],
29
+ # account_ids: []
30
+ # }
31
+ # },
32
+ # }
33
+
34
+ def secrets
35
+ @secrets ||= begin
36
+ secrets_path = ENV['LINECOOK_SECRETS_PATH'] || SECRETS_PATH
37
+ if File.exists?(secrets_path)
38
+ ejson_path = File.join(Gem::Specification.find_by_name('ejson').gem_dir, 'build', "#{Linecook::Config.platform}-amd64", 'ejson' )
39
+ command = "#{ejson_path} decrypt #{secrets_path}"
40
+ secrets = JSON.load(`sudo #{command}`)
41
+ secrets.deep_symbolize_keys
42
+ else
43
+ {}
44
+ end
45
+ end
46
+ end
47
+ end
@@ -1,3 +1,3 @@
1
1
  module Linecook
2
- VERSION = '0.6.10'
2
+ VERSION = '0.7.0'
3
3
  end
data/man/LINECOOK.1 CHANGED
@@ -1,139 +1,170 @@
1
- .TH LINECOOK 1 "December 2015" Unix "User Manuals"
1
+ .TH LINECOOK 1 "June 2016" Unix "User Manuals"
2
2
  .SH NAME
3
3
  .PP
4
- linecook \- Linux system image builder
4
+ linecook \- Linux system image builder based on test kitchen
5
5
  .SH SYNOPSIS
6
6
  .PP
7
- linecook setup \- interactive setup
8
- .PP
9
7
  linecook help [\fB\fCCOMMAND\fR]\- for specific command help
10
8
  .SH DESCRIPTION
11
9
  .PP
12
- Linecook builds system images utilizing overlayfs, squashfs, and linux containers via LXC. Currently, linecook only natively supports chef for provisioning, but using packer with a null resource, any of the mechanisms supported by packer are also supported by linecook.
10
+ Linecook is a workflow tool that allows you to use test kitchen to build generic system images. Linecook works with arbitrary test\-kitchen provisioners, and generations a neutral format that can be packaged into specific output formats.
11
+ .PP
12
+ Currently, linecook supports the following test kitchen drivers:
13
+ .RS
14
+ .IP \(bu 2
15
+ kitchen\-docker
16
+ .RE
17
+ .PP
18
+ And linecook uses packer to generate output. It currently supports:
19
+ .RS
20
+ .IP \(bu 2
21
+ AMIs via packer's ebs_chroot builder.
22
+ .RS
23
+ .IP \(bu 2
24
+ The amis may also update a TXT record in a route53 zone once the build is complete
25
+ .RE
26
+ .IP \(bu 2
27
+ squashfs, a provider neutral format.
28
+ .RE
13
29
  .PP
14
- Linecook is intended to serve 3 main purposes:
30
+ Linecook builds may be saved and annotated according to the folliwng convention:
15
31
  .RS
16
32
  .IP \(bu 2
17
- Providing a simple, portable image building process that is useable both in baremetal and cloud deployments.
33
+ name \- a descriptive name for the build, based on the name of the test kitchen suite.
18
34
  .IP \(bu 2
19
- Enabling a means of simple local image development with high production efficacy on Linux and OS X.
35
+ group \- an arbitrary grouping of suites, intended to group builds by branches.
20
36
  .IP \(bu 2
21
- Simplifying continuous integration and testing of linux systems.
37
+ tag \- a numeric tag for a build, intended to increment. If 'latest' is specified when resolving a build, the latest uploaded build is used.
22
38
  .RE
39
+ .PP
40
+ These three attributes are composed to make a build id in a very simple manor:
41
+ .RS
42
+ .IP \(bu 2
43
+ name is always required
44
+ .IP \(bu 2
45
+ if group is specified, it will be joined with name using a '\-' character.
46
+ .IP \(bu 2
47
+ if tag is specified, it will be joined with the name and the gorup using a '\-' character.
48
+ .IP \(bu 2
49
+ For example, the resulting id for a base build on the master group, with id of '5' would be 'base\-master\-5'. If this is the latest build for the base\-master group, 'base\-master\-latest' will resolve to this.
50
+ .RE
51
+ .PP
52
+ If linecook uploads a build, it will always encrypt it using rbnacl.
23
53
  .SH USAGE
24
54
  .PP
55
+ To test linecook builds locally, it is best to use test kitchen directly:
56
+ .PP
25
57
  .RS
26
58
  .nf
27
- linecook bake SPEC [\-n \-\-name `NAME`] [\-s \-\-snapshot]
28
- \-\-name \- The name
29
- \-\-snapshot \- Snapshot the resulting image for later use
30
- \-\-encrypt \- Encrypt the snapshot using the configured key. Implies snapshot.
31
- \-\-upload \- Upload the resulting image to the configured destination. Implies snapshot.
32
- \-\-all \- Snapshot, encrypt, and upload the resulting image.
33
- Build a linecook image defined by SPEC, with an optional name to help identify it. The default will be the SPEC name
34
- linecook builder
35
- start \- start a new builder
36
- stop \- stop a running builder
37
- info \- show the info about the builder
38
- ip \- show the builder's ip
39
- linecook config
40
- setup
41
- check \- validate config
42
- show
43
- linecook build
44
- list
45
- info NAME
46
- ip NAME
47
- stop NAME
48
- linecook image
49
- list
50
- keygen \- generate a new secret key for image encryption
51
- fetch
52
- find [`REGEX`] \- list available remote images filtered by an optional regex
53
- linecook ami [`image`] [\-r \-\-region `REGION1,REGION2`] [\-x \-\-xen\-type `PV|HVM`] [\-r \-\-root\-size GIGABYTES] \- create an AMI (Amazon Machine Image) from a snapshot.
59
+ bundle exec kitchen converge [SUITE NAME]
54
60
  .fi
55
61
  .RE
56
- .SH CONFIGURATION
57
62
  .PP
58
- Describe config file here once it's been determined
59
- .SH PROVISIONERS
63
+ For more specific usage, use \fIlinecook help\fP
64
+ .SH CONFIGURATION
60
65
  .PP
61
- Linecook includes an embedded chef\-zero server, and uses the chef\-provisioner
62
- \[la]https://rubygems.org/gems/chef-provisioner\[ra] and chefdepartie
63
- \[la]https://rubygems.org/gems/chefdepartie\[ra] gems to have first\-class support for local chef\-zero builds.
66
+ See test kitchen's documentation for configuring suites and provisioners.
67
+ .SH KITCHEN EXTENSIONS
64
68
  .PP
65
- However, if you're not using chef or don't want to use chef\-zero, linecook can be used seamlessly with packer
66
- \[la]https://www.packer.io\[ra], and supports any of the Linux\-based provisioners. This includes:
69
+ kitchen.yml is extended to support the following additional attributes:
70
+ .TP
71
+ \fBinherit\fP
72
+ Inherit from a previous linecook build. This saves time if there are several builds based on the same ancestor.
67
73
  .RS
68
74
  .IP \(bu 2
69
- Chef\-solo
75
+ name \- the name of the build to inherit
70
76
  .IP \(bu 2
71
- Chef\-client (with a real chef server)
77
+ group \- the group / branch of the build to inherit
72
78
  .IP \(bu 2
73
- Ansible
79
+ tag \- the explicit tag, or 'latest' to discovery the latest tag.
80
+ .RE
81
+ .SH PACKAGER
82
+ .PP
83
+ Right now there are two packagers supported. The interface may change.
84
+ .TP
85
+ \fBsquashfs\fP
86
+ Package the resulting build as a squashfs image.
87
+ .RS
74
88
  .IP \(bu 2
75
- Puppet (masterless or server)
89
+ \fIexcludes\fP \- a list of glob expressions to exclude from the archive
76
90
  .IP \(bu 2
77
- Salt
91
+ \fIdistro\fP \- inherit a specific set of presets for paths to exclude by distro. Currently only ubuntu is supported.
78
92
  .IP \(bu 2
79
- Plain old shell scripts
93
+ outdir \- the output directory for the image
80
94
  .RE
81
- .PP
82
- See the packer documentation for how to configure these provisioners.
83
- .PP
84
- To use a packerfile with linecook, just leave out the 'builder' section, or have the builder section be an empty array. You need only specify the 'provisioner' section, and other sections may cause errors. Linecook will automatically insert a null builder with the appropriate connection string for you.
85
- .PP
86
- Linecook with packer is a powerful combination, as it allows you to leverage packer's 'null builder' to take advantage of all of the provisioners packer already has really good support for. The result is an intermediate image format (squashfs) that can be easily applied to any target.
87
- .SH FILES
88
95
  .TP
89
- \fI\&./linecook.yml\fP
90
- Local config file. Gets deep merged over the system config file. If not explicitly specified, found from current directory if exists.
91
- .TP
92
- \fI~/linecook/config.yml\fP
93
- The system wide configuration file, base or 'common' configuration. Other configurations get deep merged on top of this.
94
- .SH DEPENDENCIES
95
- .PP
96
- Ruby 2.0 or greater, gem, and bundler.
97
- .PP
98
- Does not work and will never work on Windows.
99
- .SS Linux
100
- .PP
101
- Only tested on Gentoo and Ubuntu
96
+ \fBpacker\fP
97
+ Package an AMI using packer. Currently only AMIs are supported, but any packer builder could be implemented relatively easily.
102
98
  .RS
103
99
  .IP \(bu 2
104
- lxc >= 1.0.7
100
+ hvm \- build an HVM instance (defaults to true).
105
101
  .IP \(bu 2
106
- brutils
102
+ root_size \- the size of the root volume to snapshot for the AMI (in GB).
107
103
  .IP \(bu 2
108
- dnsmasq
104
+ region \- the region to build the AMI in.
109
105
  .IP \(bu 2
110
- iptables with masquerade support
106
+ copy_regions \- additional regions to copy the AMI to.
111
107
  .IP \(bu 2
112
- Linux 3.19 or greater with support for cgroups, and netfilter as described by lxc and iptables for NAT.
108
+ account_ids \- a list of account ids that are permitted to launch this AMI.
109
+ .IP \(bu 2
110
+ ami \- details for storing the AMI ID in a DNS TXT record on route53.
111
+ .RS
112
+ .IP \(bu 2
113
+ update_txt \- should a TXT record be written? (true or false)
114
+ .IP \(bu 2
115
+ regions \- a dictionary of regional aliases
116
+ .IP \(bu 2
117
+ domain \- the route53 domain to write to
118
+ .IP \(bu 2
119
+ zone \- the zone within the domain.
120
+ .RE
113
121
  .RE
114
- .SS OS X
122
+ .SH SECRETS
123
+ .PP
124
+ Linecook will look for secrets in config.ejson. In particular:
125
+ .TP
126
+ \fBimagekey\fP
127
+ the key to use when encrypting images. Generate one with the \fIimage keygen\fP command.
128
+ .TP
129
+ \fBaws\fP
130
+ This is used access to S3, as well as to create EBS based AMIs and update TXT records on route53. A sample IAM policy is provided in the github repo.
115
131
  .RS
116
132
  .IP \(bu 2
117
- OS X 10.10 or later (Hypervisor.framework required for Xhyve)
133
+ { "s3": { "bucket" : "name" } } can be used to set the name of the bucket
134
+ .IP \(bu 2
135
+ { "access_key" : "ACCESS_KEY" } can be used to set the access key for the IAM user associated with the profile with the necessary access.
136
+ .IP \(bu 2
137
+ { "secret_key" : "ACCESS_KEY" } can be used to set the secret key for the IAM user associated with the profile with the necessary access.
118
138
  .RE
119
- .SH QUIRKS
120
- .SS Xhyve
139
+ .TP
140
+ \fBchef\fP
141
+ To decrypt data bags securely, you can set the \fIencrypted_data_bag_secret\fP here. Make sure any newlines are replaced with \[rs]n.
142
+ .SH PROVISIONERS
143
+ .PP
144
+ Currently only the docker driver is supported for provisioning. You must have docker installed to use this provisioner.
145
+ .SH DEPENDENCIES
146
+ .PP
147
+ \fBCommon\fP
121
148
  .RS
122
149
  .IP \(bu 2
123
- Xhyve requires root privileges until
124
- \[la]https://github.com/mist64/xhyve/issues/60\[ra] is resolved. Linecook will setuid on the xhyve binary.
150
+ Ruby 2.0 or greater, gem, and bundler.
125
151
  .RE
126
- .SS Overlayfs
152
+ .PP
153
+ \fBLinux\fP
127
154
  .RS
128
155
  .IP \(bu 2
129
- Overlayfs doesn't support unix domain sockets (yet), so anything using a unix domain socket outside of the /run tree should do manually symlink to /run.
156
+ mksquashfs \- to generate squashfs output.
157
+ .RE
158
+ .PP
159
+ \fBOS X\fP
160
+ .RS
130
161
  .IP \(bu 2
131
- Config file will allow you to explicitly mount tmpfs over things that don't do /run if you need to create unix domain sockets
162
+ docker for mac
132
163
  .RE
133
164
  .SH BUGS
134
165
  .PP
135
- Report bugs against github.com/dalehamel/linecook
166
+ Report bugs against github.com/shopify/linecook\-gem
136
167
  .SH AUTHOR
137
168
  .PP
138
169
  Dale Hamel
139
- \[la]dale.hamel@srvthe.net\[ra]
170
+ \[la]dale.hamel@shopify.com\[ra]