hawser 0.1.1 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cf941e79bf69e2c5a377996a0b8bec222e65232a
4
- data.tar.gz: 3905483927606e26b00f4cade2fff9f6535d9f08
3
+ metadata.gz: f37eabe7ab5a93f7ac12ae94512c90d3d5f92b5b
4
+ data.tar.gz: 897451652af6a7277f9f993ea68edd25b51a1b08
5
5
  SHA512:
6
- metadata.gz: 0e82f6e9fa6e2ae598f2a8b4eac50893c41f5be524edc2a93e8cb92175b828ac03cc4011d49bf17cc3f5c8f019964c68dafbbc0259d44ff251a723fe57186329
7
- data.tar.gz: c8790b49b61e5863e12e5fa7527cb8dfb3431e16f17d52d88af884a647bff68988a52b7b33b7443d091c6f9fdb6c26c69153d5dc4da81d387f39b7d912fac42d
6
+ metadata.gz: b3a8730daffd3c68e99eb12e3d6d3db06e505fb5181bb993b5e72e146b85073c05e068a49b0c562280e6928b782826d799bf0e1e23d868dc4daa6af89d036acd
7
+ data.tar.gz: 6b08518ebf9b91e8a670d5106b63e395dc8f43f8169904452d6a4928d2fa795fff00da35eda1ec6ecb4975479b1a57b5a46952000f598f869101a92c292efa2b
@@ -9,6 +9,13 @@ module Hawser
9
9
 
10
10
  setting :region, "us-west-1"
11
11
 
12
+ setting :block_mappings, {
13
+ "ami" => "sda1",
14
+ "root" => "/dev/sda1",
15
+ "ephemeral0" => "sda2",
16
+ "swap" => "sda3"
17
+ }
18
+
12
19
  dir(:ephemeral_dir, "mnt",
13
20
  dir(:keyfile_dir, "keys",
14
21
  path(:private_key, "pk.pem"),
@@ -56,6 +63,10 @@ module Hawser
56
63
  bundle.options += ["-k", private_key.abspath ]
57
64
  bundle.options += ["-c", certificate_file.abspath ]
58
65
  bundle.options += ["--user", aws_account_id ]
66
+ bundle.options += ["--block-device-mapping", block_mappings.map do |name, dev|
67
+ "#{name}=#{dev}"
68
+ end.join(",")
69
+ ]
59
70
 
60
71
  bundle.options += ["--destination", ephemeral_dir.abspath ]
61
72
  bundle.options += ["--prefix", prefix ]
@@ -79,6 +90,12 @@ module Hawser
79
90
  register.options += ["--region", region]
80
91
  register.options += ["--aws-access-key", access_key]
81
92
  register.options += ["--aws-secret-key", secret_key]
93
+ }) &
94
+ (cmd("rm") {|rm|
95
+ rm.options = ["-rf", keyfile_dir.abspath]
96
+ }) &
97
+ (cmd("rm") {|rm|
98
+ rm.options = ["-f", File::join(ephemeral_dir.abspath, prefix || "no-such-file"), File::join(ephemeral_dir.abspath, prefix || "no-such-file") + ".part.*" ]
82
99
  })
83
100
  end
84
101
  end
@@ -2,6 +2,7 @@ require 'mattock'
2
2
  require 'hawser/credentialing'
3
3
  require 'hawser/baking'
4
4
  require 'hawser/servers'
5
+ require 'hawser/volumes'
5
6
 
6
7
  module Hawser
7
8
  # Represents a cluster of servers on AWS
@@ -47,12 +48,25 @@ module Hawser
47
48
  creds.credentials.proxy_settings_to(servers)
48
49
  end
49
50
 
51
+ Hawser::Volumes.new do |volumes|
52
+ copy_settings_to(volumes)
53
+ volumes.cluster_name = name
54
+ creds.copy_settings_to(volumes)
55
+ creds.credentials.proxy_settings_to(volumes)
56
+ end
57
+
50
58
  namespace :baking do
51
- task :bake => "credentials:establish"
59
+ task :copy_key => "credentials:establish"
60
+ task :copy_cert => "credentials:establish"
52
61
  end
53
62
 
54
63
  namespace :servers do
55
64
  task :list => "credentials:establish"
65
+ task :view => "credentials:establish"
66
+ end
67
+
68
+ namespace :volume do
69
+ task :clone => "credentials:establish"
56
70
  end
57
71
 
58
72
  desc "Make an AMI copy of the running instance at :target named :name"
@@ -72,10 +72,11 @@ module Hawser
72
72
 
73
73
  cert = OpenSSL::X509::Certificate.new
74
74
  cert.version = 2
75
- cert.serial = 2
75
+ cert.serial = OpenSSL::Random.random_bytes(16).each_byte.inject(0){|sum, byte| (sum << 8) + byte}
76
76
  cert.public_key = key.public_key
77
77
  cert.not_before = Time.now
78
78
  cert.not_after = cert.not_before + self.cert.lifetime.total_seconds
79
+ cert.sign(key, OpenSSL::Digest::SHA256.new)
79
80
 
80
81
  cert.to_pem
81
82
  end
@@ -126,12 +127,21 @@ module Hawser
126
127
  in_namespace do
127
128
  directory user_dir.abspath
128
129
 
129
- file signing_cert.abspath => signing_key.abspath do |task|
130
+ task :umask do
131
+ File::umask(0077)
132
+ end
133
+
134
+ file signing_cert.abspath => [:umask, signing_key.abspath] do |task|
135
+ require 'base64'
136
+
130
137
  key = File::read(signing_key.abspath)
131
- File.write(task.name, signing_cert_content(key))
138
+ cert_pem = signing_cert_content(key)
139
+ File.open(task.name, "wb") do |file|
140
+ file.print cert_pem
141
+ end
132
142
  end
133
143
 
134
- file signing_key.abspath do |task|
144
+ file signing_key.abspath => :umask do |task|
135
145
  File.write(task.name, signing_key_content)
136
146
  end
137
147
 
@@ -141,14 +151,16 @@ module Hawser
141
151
  end
142
152
  end
143
153
 
144
- task :store do
154
+ task :store => :umask do
145
155
  require 'yaml'
146
156
 
157
+ puts "Storing credentialing info at #{config_yaml.abspath}"
147
158
  File::open(config_yaml.abspath, "w") do |config|
148
159
  config.write YAML.dump(Hash[credentials.to_hash.map do |key,value|
149
160
  [key.to_s, value]
150
161
  end])
151
162
  end
163
+
152
164
  end
153
165
 
154
166
  task :iam => "get:access" do
@@ -160,9 +172,10 @@ module Hawser
160
172
  end
161
173
 
162
174
  namespace :get do
163
- task :access => :load do
175
+ task :access => [:umask, :load] do
164
176
  if credentials.access_key.nil? or credentials.secret_key.nil?
165
177
  load_from_csv(File.read(creds_csv.abspath))
178
+ puts "Loaded access key id and key secret from CSV at #{creds_csv.abspath}"
166
179
  end
167
180
  end
168
181
 
@@ -181,11 +194,12 @@ module Hawser
181
194
  namespace :set do
182
195
  task :password => :iam_user do
183
196
  unless credentials.password.nil?
197
+ puts "Setting login password"
184
198
  iam_user.login_policy.password = credentials.password
185
199
  end
186
200
  end
187
201
 
188
- task :certificate => [:iam_user, signing_cert.abspath, "get:certificate_id"] do
202
+ task :certificate => [:umask, :iam_user, signing_cert.abspath, "get:certificate_id"] do
189
203
  if !credentials.certificate_id.nil?
190
204
  begin
191
205
  iam_user.signing_certificates[credentials.certificate_id].contents
@@ -194,6 +208,7 @@ module Hawser
194
208
  end
195
209
  end
196
210
 
211
+ puts "Uploading signing certificate at #{signing_cert.abspath}"
197
212
  cert = iam_user.signing_certificates.upload(File::read(signing_cert.abspath))
198
213
  credentials.certificate_id = cert.id
199
214
  end
@@ -31,6 +31,30 @@ module Hawser
31
31
  "key_name" => instance.key_name }
32
32
  end))
33
33
  end
34
+
35
+ desc "View details for a server for #{cluster_name}"
36
+ task :view, [:id] do |task, args|
37
+ if args[:id].nil?
38
+ fail ":id is required"
39
+ end
40
+ require 'yaml'
41
+ ec2 = AWS::EC2.new(:region => region, :access_key_id => access_key, :secret_access_key => secret_key)
42
+
43
+ instance = ec2.instances.find do |inst|
44
+ inst.instance_id == args[:id]
45
+ end
46
+
47
+ if instance.nil?
48
+ fail "Couldn't find instance with id #{args[:id]} in #{ec2.instances.map{|inst| inst.instance_id}}"
49
+ end
50
+
51
+ require 'pp'
52
+ pp instance
53
+ pp instance.class.ancestors
54
+ puts instance.to_yaml
55
+ pp instance.block_device_mappings
56
+
57
+ end
34
58
  end
35
59
  end
36
60
  end
@@ -0,0 +1,102 @@
1
+ require 'mattock'
2
+ require 'aws-sdk'
3
+
4
+ module Hawser
5
+ class Volumes < Mattock::Tasklib
6
+ default_namespace :volume
7
+
8
+ setting :cluster_name
9
+ setting :access_key
10
+ setting :secret_key
11
+ setting :region, "us-west-1"
12
+
13
+ def define
14
+ in_namespace do
15
+ desc "Clone <from_dev> on <from_instance> to <to_dev> on <to_instance>"
16
+ task :clone, [:from_instance, :from_dev, :to_instance, :to_dev] do |task, args|
17
+ missing = [:from_instance, :from_dev, :to_instance].find_all do |key|
18
+ args[key].nil?
19
+ end
20
+
21
+ unless missing.empty?
22
+ fail "Missing required arguments: #{missing.inspect}"
23
+ end
24
+
25
+ to_dev = args[:to_dev] || args[:from_dev]
26
+
27
+ ec2 = AWS::EC2.new(:region => region, :access_key_id => access_key, :secret_access_key => secret_key)
28
+
29
+ instances = ec2.instances
30
+ from_instance = instances.find do |inst|
31
+ inst.instance_id == args[:from_instance]
32
+ end
33
+
34
+ to_instance = instances.find do |inst|
35
+ inst.instance_id == args[:to_instance]
36
+ end
37
+
38
+ missing_instances = []
39
+ if from_instance.nil?
40
+ missing_instances << "Missing instance for #{args[:from_instance].inspect}"
41
+ end
42
+ if to_instance.nil?
43
+ missing_instances << "Missing instance for #{args[:to_instance].inspect}"
44
+ end
45
+ unless missing_instances.empty?
46
+ fail "Missing instances: #{missing_instances.join.inspect}"
47
+ end
48
+
49
+ require 'pp'
50
+ from_device = from_instance.block_devices.find do |dev|
51
+ dev[:device_name] == args[:from_dev]
52
+ end
53
+ unless from_device
54
+ fail "No device mapped to #{args[:from_instance]} on #{args[:from_dev]}"
55
+ end
56
+
57
+ if to_instance.block_devices.any?{|dev| dev[:device_name] == to_dev}
58
+ fail "A device is already mapped to #{args[:to_instance]} on #{to_dev}"
59
+ end
60
+
61
+ from_volume = ec2.volumes.find do |vol|
62
+ from_device[:ebs][:volume_id] == vol.id
63
+ end
64
+
65
+ unless from_volume
66
+ fail "No volume matches #{from_device[:ebs][:volume_id].inspect}"
67
+ end
68
+
69
+ snapshot_desc = from_volume.tags["Name"] || "From #{args[:from_instance]}:#{args[:from_dev]}"
70
+
71
+ intermediate_snapshot = from_volume.create_snapshot(snapshot_desc)
72
+ at_exit{ intermediate_snapshot.delete }
73
+
74
+ wait_for_status("intermediate snapshot", intermediate_snapshot, :completed)
75
+
76
+ new_volume = intermediate_snapshot.create_volume(to_instance.availability_zone)
77
+
78
+ wait_for_status("volume creation", new_volume, :available)
79
+
80
+ new_volume.attach_to(to_instance, to_dev)
81
+
82
+ wait_for_status("volume attachment", new_volume, :in_use)
83
+
84
+ puts "Done"
85
+ end
86
+ end
87
+
88
+ end
89
+
90
+ def wait_for_status(name, resource, goal)
91
+ puts "Waiting for #{name}"
92
+ until [goal, :error].include?(resource.status)
93
+ print "."
94
+ sleep 1
95
+ end
96
+
97
+ puts "\n #{name} complete. Status: #{resource.status.inspect}"
98
+ fail if resource.status != goal
99
+ end
100
+
101
+ end
102
+ end
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hawser
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Judson Lester
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-08-22 00:00:00.000000000 Z
11
+ date: 2015-01-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '>'
17
+ - - <
18
18
  - !ruby/object:Gem::Version
19
- version: '0'
19
+ version: '2.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: '0'
26
+ version: '2.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: mattock
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -52,6 +52,7 @@ files:
52
52
  - lib/hawser/servers.rb
53
53
  - lib/hawser/baking-command.rb
54
54
  - lib/hawser/baking.rb
55
+ - lib/hawser/volumes.rb
55
56
  - spec/hawser_spec.rb
56
57
  - spec_help/gem_test_suite.rb
57
58
  homepage: http://nyarly.github.com/hawser
@@ -64,7 +65,7 @@ rdoc_options:
64
65
  - --main
65
66
  - doc/README
66
67
  - --title
67
- - hawser-0.1.1 Documentation
68
+ - hawser-0.2.0 Documentation
68
69
  require_paths:
69
70
  - lib/
70
71
  required_ruby_version: !ruby/object:Gem::Requirement