dollhouse 0.1.2 → 0.2.0.beta.1

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.
data/bin/dollhouse CHANGED
@@ -6,45 +6,29 @@ require 'dollhouse'
6
6
  require 'main'
7
7
 
8
8
  Main do
9
- mode 'deploy' do
10
- argument('deployment') { required }
11
- argument('prefix') { optional }
12
- def run
13
- Dollhouse.launch_from(Dir.pwd)
14
- Dollhouse.initiate_deployment(params['deployment'].value.to_sym, :prefix => params['prefix'].value)
15
- end
16
- end
17
-
18
- mode 'exec' do
19
- argument('server_name') { required }
20
- argument('cmd') { required }
21
- def run
22
- Dollhouse.launch_from(Dir.pwd)
23
- Dollhouse.instances[params['server_name'].value].instance_eval params['cmd'].value
24
- end
25
- end
26
-
27
- mode 'destroy' do
9
+ mode 'run' do
28
10
  argument('server_name') { required }
11
+ argument('task_name') { required }
29
12
  def run
30
13
  Dollhouse.launch_from(Dir.pwd)
31
- Dollhouse.cloud_adapter.destroy params['server_name'].value
14
+ Dollhouse.run(params['server_name'].value, params['task_name'].value)
32
15
  end
33
16
  end
34
17
 
35
18
  mode 'list' do
36
19
  def run
37
20
  Dollhouse.launch_from(Dir.pwd)
38
- p Dollhouse.cloud_adapter.list
21
+ puts Dollhouse.instances.list
39
22
  end
40
23
  end
41
24
 
42
- mode 'run' do
25
+ # bit hax
26
+ mode 'exec' do
43
27
  argument('server_name') { required }
44
- argument('task_name') { required }
28
+ argument('cmd') { required }
45
29
  def run
46
30
  Dollhouse.launch_from(Dir.pwd)
47
- Dollhouse.instances[params['server_name'].value].run_task(params['task_name'].value)
31
+ Dollhouse.execute(params['server_name'].value, params['cmd'].value)
48
32
  end
49
33
  end
50
34
 
@@ -18,22 +18,6 @@ module Dollhouse
18
18
  end
19
19
 
20
20
  class ServerBuilder < Struct.new(:name)
21
- def instance_type t
22
- @instance_type = t
23
- end
24
-
25
- def os o
26
- @os = o
27
- end
28
-
29
- def from_latest_snapshot snapshot_name
30
- @snapshot = snapshot_name
31
- end
32
-
33
- def first_boot &blk
34
- callbacks[:first_boot] = blk
35
- end
36
-
37
21
  def task name, &blk
38
22
  callbacks[name.to_s] = blk
39
23
  end
@@ -16,13 +16,6 @@ module Dollhouse
16
16
  end
17
17
  end
18
18
 
19
- def server_online cloud_name, server
20
- online_server = OnlineServer[cloud_name, self.name, server.name, :running]
21
- Dollhouse.instances.server_came_online online_server
22
- online_server.bootstrap
23
- online_server.instance_eval &server.callbacks[:first_boot]
24
- end
25
-
26
19
  def self.[](deployment)
27
20
  raise "Unknown deployment #{deployment}" unless all.has_key? deployment.to_s
28
21
  all[deployment.to_s]
@@ -1,18 +1,23 @@
1
1
  module Dollhouse
2
- def self.launch_from(dir)
3
- self.root = dir
4
- # may need something cleverer in the future
5
- require dir + '/config/dollhouse/config.rb'
6
- Dir.glob(dir + '/config/dollhouse/auth.rb') { |f| require f } #optional require
7
- Dir.glob(dir + '/config/dollhouse/deployments/*.rb') { |f| require f }
8
- end
2
+ class << self
3
+ attr_accessor :root, :instances
9
4
 
10
- def self.initiate_deployment(deployment, opts = {})
11
- Deployment[deployment].initiate(opts)
12
- end
5
+ def launch_from(dir)
6
+ self.root = dir
7
+ # may need something cleverer in the future
8
+ raise "You should be running this in your application root, or at least somewhere with a config/dollhouse subdirectory" if !File.exists?(File.join(dir, 'config', 'dollhouse'))
9
+ Dir.glob(dir + '/config/dollhouse/config.rb') { |f| require f } #optional require
10
+ Dir.glob(dir + '/config/dollhouse/auth.rb') { |f| require f } #optional require
11
+ Dir.glob(dir + '/config/dollhouse/deployments/*.rb') { |f| require f }
12
+ end
13
13
 
14
- class << self
15
- attr_accessor :root, :cloud_adapter, :instances
14
+ def run(server_name, task_name)
15
+ instances[server_name].run_task task_name
16
+ end
17
+
18
+ def execute(server_name, cmd)
19
+ instances[server_name].instance_eval cmd
20
+ end
16
21
 
17
22
  def instances
18
23
  @instances ||= Instances.new
@@ -1,35 +1,31 @@
1
1
  module Dollhouse
2
- class OnlineServer < Struct.new(:name_in_cloud, :deployment_name, :server_name, :status, :ip)
2
+ class Instance < Struct.new(:instance_name, :deployment_name, :server_name, :ip)
3
3
  attr_accessor :user, :password
4
4
 
5
5
  def bootstrap
6
- Dollhouse.cloud_adapter.execute(name_in_cloud, %Q{bash -c "`wget -O- babushka.me/up/hard`"}, default_opts)
6
+ cloud_adapter.execute(instance_name, %Q{bash -c "`wget -O- babushka.me/up/hard`"}, default_opts)
7
7
  end
8
8
 
9
9
  def babushka taskname, vars = {}
10
10
  # not used yet, but this makes sense. --defaults (or headless) is the default!
11
11
  if vars == :no_defaults
12
- Dollhouse.cloud_adapter.execute(name_in_cloud, "babushka '#{taskname}'", default_opts)
12
+ cloud_adapter.execute(instance_name, "babushka '#{taskname}'", default_opts)
13
13
  else
14
14
  if !vars.empty?
15
15
  write_file(".babushka/vars/#{taskname}", {
16
16
  :vars => vars.map_keys(&:to_s).map_values { |v| {:value => v} }
17
17
  }.to_yaml)
18
18
  end
19
- Dollhouse.cloud_adapter.execute(name_in_cloud, "babushka '#{taskname}' --defaults", default_opts)
19
+ cloud_adapter.execute(instance_name, "babushka '#{taskname}' --defaults", default_opts)
20
20
  end
21
21
  end
22
22
 
23
23
  def shell cmd, opts = {}
24
- Dollhouse.cloud_adapter.execute(name_in_cloud, cmd, default_opts.merge(opts))
24
+ cloud_adapter.execute(instance_name, cmd, default_opts.merge(opts))
25
25
  end
26
26
 
27
27
  def write_file path, content, opts = {}
28
- Dollhouse.cloud_adapter.write_file(name_in_cloud, path, content, default_opts.merge(opts))
29
- end
30
-
31
- def destroy
32
- Dollhouse.cloud_adapter.destroy(name_in_cloud)
28
+ cloud_adapter.write_file(instance_name, path, content, default_opts.merge(opts))
33
29
  end
34
30
 
35
31
  def as user, opts = {}, &blk
@@ -42,10 +38,6 @@ module Dollhouse
42
38
  self.password = old_password
43
39
  end
44
40
 
45
- def take_snapshot name
46
- Dollhouse.cloud_adapter.take_snapshot(name_in_cloud, name + "-" + Time.now.strftime("%Y%M%d-%H%M%S"))
47
- end
48
-
49
41
  def server
50
42
  deployment.servers.find { |s| s.name == server_name }
51
43
  end
@@ -58,6 +50,16 @@ module Dollhouse
58
50
  instance_eval &server.callbacks[task_name]
59
51
  end
60
52
 
53
+ def to_yaml
54
+ {instance_name => {'deployment_name' => deployment_name, 'server_name' => server_name, 'ip' => ip}}
55
+ end
56
+
57
+ def self.from_yaml(hash)
58
+ hash.map_values_with_keys { |k,v|
59
+ Instance[k, v['deployment_name'], v['server_name'], v['ip']]
60
+ }
61
+ end
62
+
61
63
  private
62
64
 
63
65
  def default_opts
@@ -66,5 +68,10 @@ module Dollhouse
66
68
  opts.merge!({:sudo_password => password}) if password
67
69
  opts
68
70
  end
71
+
72
+ # This could return different adapters, that connect to servers in different ways. For now we have a simple
73
+ def cloud_adapter
74
+ @cloud_adapter ||= ManualConfig.new
75
+ end
69
76
  end
70
77
  end
@@ -15,12 +15,16 @@ module Dollhouse
15
15
 
16
16
  def online_servers
17
17
  @online_servers = if File.exists? "#{Dollhouse.root}/config/dollhouse/instances/servers.yml"
18
- YAML::load_file("#{Dollhouse.root}/config/dollhouse/instances/servers.yml") or {}
18
+ Instance.from_yaml(YAML::load_file("#{Dollhouse.root}/config/dollhouse/instances/servers.yml") || {})
19
19
  else
20
20
  {}
21
21
  end
22
22
  end
23
23
 
24
+ def list
25
+ online_servers.inspect
26
+ end
27
+
24
28
  private
25
29
 
26
30
  def save!
@@ -1,22 +1,13 @@
1
1
  module Dollhouse
2
- class ManualConfig < CloudAdapter
2
+ class ManualConfig
3
3
  def execute(name, cmd, opts = {})
4
4
  #nasty, but sudo_password isn't valid for starting a connection
5
5
  sudo_password = opts.delete(:sudo_password)
6
6
  ssh_conn(Dollhouse.instances[name].ip, opts[:user] || 'root', opts) do
7
- p "Executing: #{cmd}"
8
7
  exec cmd, {:sudo_password => sudo_password}
9
8
  end
10
9
  end
11
10
 
12
- def boot_new_server(name, callback, opts)
13
- raise "You can't, you fool!"
14
- end
15
-
16
- def list
17
- Dollhouse.instances.online_servers.values.select { |i| i.status == :running }
18
- end
19
-
20
11
  def write_file(name, path, content, opts)
21
12
  ssh_conn(Dollhouse.instances[name].ip, opts[:user] || 'root', opts) do
22
13
  write_file(path) do |out|
@@ -1,4 +1,4 @@
1
- # Let it be known, dgoodlad is a profase.
1
+ # Let it be known, @dgoodlad is a profase.
2
2
 
3
3
  require 'net/ssh'
4
4
  require 'net/sftp'
@@ -48,7 +48,7 @@ module Dollhouse
48
48
  output = ''
49
49
  status_code = nil
50
50
 
51
- puts "Executing:\n#{command}"
51
+ puts "## Executing: #{command}"
52
52
 
53
53
  ch.exec(command) do |ch, success|
54
54
  raise "Failed to start execution!" unless success
@@ -1,3 +1,3 @@
1
1
  module Dollhouse
2
- VERSION = "0.1.2" unless defined?(Dollhouse::VERSION)
2
+ VERSION = "0.2.0.beta.1" unless defined?(Dollhouse::VERSION)
3
3
  end
metadata CHANGED
@@ -1,13 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dollhouse
3
3
  version: !ruby/object:Gem::Version
4
- hash: 31
5
- prerelease: false
4
+ hash: 62196353
5
+ prerelease: true
6
6
  segments:
7
7
  - 0
8
- - 1
9
8
  - 2
10
- version: 0.1.2
9
+ - 0
10
+ - beta
11
+ - 1
12
+ version: 0.2.0.beta.1
11
13
  platform: ruby
12
14
  authors:
13
15
  - Glen Maddern
@@ -15,7 +17,7 @@ autorequire:
15
17
  bindir: bin
16
18
  cert_chain: []
17
19
 
18
- date: 2010-11-08 00:00:00 +11:00
20
+ date: 2010-11-12 00:00:00 +11:00
19
21
  default_executable:
20
22
  dependencies:
21
23
  - !ruby/object:Gem::Dependency
@@ -98,26 +100,10 @@ dependencies:
98
100
  version: 0.10.3
99
101
  type: :runtime
100
102
  version_requirements: *id005
101
- - !ruby/object:Gem::Dependency
102
- name: bundler
103
- prerelease: false
104
- requirement: &id006 !ruby/object:Gem::Requirement
105
- none: false
106
- requirements:
107
- - - ~>
108
- - !ruby/object:Gem::Version
109
- hash: 17
110
- segments:
111
- - 1
112
- - 0
113
- - 3
114
- version: 1.0.3
115
- type: :development
116
- version_requirements: *id006
117
103
  - !ruby/object:Gem::Dependency
118
104
  name: cucumber
119
105
  prerelease: false
120
- requirement: &id007 !ruby/object:Gem::Requirement
106
+ requirement: &id006 !ruby/object:Gem::Requirement
121
107
  none: false
122
108
  requirements:
123
109
  - - ~>
@@ -129,11 +115,11 @@ dependencies:
129
115
  - 3
130
116
  version: 0.9.3
131
117
  type: :development
132
- version_requirements: *id007
118
+ version_requirements: *id006
133
119
  - !ruby/object:Gem::Dependency
134
120
  name: rake
135
121
  prerelease: false
136
- requirement: &id008 !ruby/object:Gem::Requirement
122
+ requirement: &id007 !ruby/object:Gem::Requirement
137
123
  none: false
138
124
  requirements:
139
125
  - - ~>
@@ -145,11 +131,11 @@ dependencies:
145
131
  - 7
146
132
  version: 0.8.7
147
133
  type: :development
148
- version_requirements: *id008
134
+ version_requirements: *id007
149
135
  - !ruby/object:Gem::Dependency
150
136
  name: rspec
151
137
  prerelease: false
152
- requirement: &id009 !ruby/object:Gem::Requirement
138
+ requirement: &id008 !ruby/object:Gem::Requirement
153
139
  none: false
154
140
  requirements:
155
141
  - - ~>
@@ -161,7 +147,7 @@ dependencies:
161
147
  - 0
162
148
  version: 2.0.0
163
149
  type: :development
164
- version_requirements: *id009
150
+ version_requirements: *id008
165
151
  description: Dollhouse is a way to deploy servers. It is designed to be used with Babushka.
166
152
  email: glen.maddern@gmail.com
167
153
  executables:
@@ -173,14 +159,12 @@ extra_rdoc_files: []
173
159
  files:
174
160
  - bin/dollhouse
175
161
  - lib/core_ext/hash.rb
176
- - lib/dollhouse/cloud_adapter.rb
177
162
  - lib/dollhouse/config_loader.rb
178
163
  - lib/dollhouse/deployment.rb
179
164
  - lib/dollhouse/dollhouse.rb
165
+ - lib/dollhouse/instance.rb
180
166
  - lib/dollhouse/instances.rb
181
167
  - lib/dollhouse/manual_config.rb
182
- - lib/dollhouse/online_server.rb
183
- - lib/dollhouse/rackspace_cloud_adapter.rb
184
168
  - lib/dollhouse/remote_server.rb
185
169
  - lib/dollhouse/server.rb
186
170
  - lib/dollhouse/version.rb
@@ -1,21 +0,0 @@
1
- module Dollhouse
2
- class CloudAdapter
3
- def initialize
4
- raise NotImplementedError, %Q{
5
- Must implement the following methods:
6
-
7
- boot_new_server(name, callback, opts)
8
- - name is the unique id for the server in this cloud
9
- - callback is a lambda to be fired_off when that server comes online
10
- - generally, opts has :machine_id, :ram_size, :data_center, :backup_image_id
11
-
12
- execute(server_name, cmd, opts)
13
-
14
- write_file(server_name, path, content, opts)
15
-
16
- list
17
-
18
- } unless [:boot_new_server, :execute, :write_file, :list].all? { |m| self.class.method_defined? m }
19
- end
20
- end
21
- end
@@ -1,101 +0,0 @@
1
- module Dollhouse
2
- class RackspaceCloudAdapter < CloudAdapter
3
- FLAVORS = {"256mb" => 1, "512mb" => 2, "1024mb" => 3, "2048mb" => 4}
4
- IMAGES = {"Ubuntu 10.04" => 49}
5
-
6
- def conn
7
- require 'fog'
8
- @conn ||= Fog::Rackspace::Servers.new(
9
- :rackspace_api_key => Auth::Rackspace::API_KEY,
10
- :rackspace_username => Auth::Rackspace::USERNAME
11
- )
12
- end
13
-
14
- def boot_new_server(name, callback, opts)
15
- flavor_num = FLAVORS[opts[:instance_type]]
16
- raise "Unknown instance_type of #{opts[:instance_type].inspect}. Permitted values are #{FLAVORS.keys.inspect}" unless flavor_num
17
- image_num = if opts[:snapshot]
18
- image = conn.images.select { |i| i.created_at && i.name =~ Regexp.new(Regexp.escape(opts[:snapshot])) }.sort_by { |i| i.created_at }.last
19
- raise "Snapshot name of #{opts[:snapshot]} doesn't match any images!" unless image
20
- puts "Booting from image: #{image.inspect}"
21
- image.id
22
- else
23
- raise "Unknown os of #{opts[:os].inspect}. Permitted values are #{IMAGES.keys.inspect}" unless IMAGES[opts[:os]]
24
- IMAGES[opts[:os]]
25
- end
26
-
27
- puts "Booting server #{name}"
28
- server = conn.servers.create(:flavor_id => flavor_num, :image_id => image_num, :name => name)
29
-
30
- puts "Server booted: #{server.inspect}"
31
- # make this asynch soon
32
- server.wait_for { ready? }
33
- puts "Server #{name} online. Adding our private key"
34
- server.public_key_path = Auth::KEYPAIR + ".pub"
35
- server.setup
36
- puts "Done. Ready to go!"
37
-
38
- callback.call
39
- end
40
-
41
- def execute(name, cmd, opts = {})
42
- #nasty, but sudo_password isn't valid for starting a connection
43
- sudo_password = opts.delete(:sudo_password)
44
- ssh_conn(name, opts) do
45
- p "Executing: #{cmd}"
46
- exec cmd, {:sudo_password => sudo_password}
47
- end
48
- end
49
-
50
- def write_file(name, path, content, opts = {})
51
- ssh_conn(name, opts) do
52
- write_file(path) do |out|
53
- out.puts content
54
- end
55
- end
56
- end
57
-
58
- def destroy name
59
- server = get_server name
60
- puts "Killing server #{server.inspect}"
61
- server.destroy
62
- puts "Done."
63
- end
64
-
65
- def take_snapshot name, snapshot_name
66
- response = conn.create_image get_server(name).id, 'name' => snapshot_name
67
- puts "Created image: #{response.body['image'].inspect}"
68
- end
69
-
70
- def list
71
- conn.servers
72
- end
73
-
74
- private
75
-
76
- def ssh_conn(name, opts, &blk)
77
- #nasty, but sudo_password isn't valid for starting a connection
78
- opts.delete(:sudo_password)
79
- ssh_conns[[name, opts]].instance_eval(&blk)
80
- end
81
-
82
- def ssh_conns
83
- @ssh_conns ||= Hash.new { |h, (name, opts)|
84
- puts "Establishing connection to #{name}:"
85
- #change this to use instances.yml, or something
86
- server = get_server name
87
- host = server.addresses['public'].first
88
- user = opts[:user] || 'root'
89
- puts "Connecting to #{host} as #{user}..."
90
-
91
- h[[name, opts]] = RemoteServer.new(host, user, {:forward_agent => true}.merge(opts))
92
- }
93
- end
94
-
95
- def get_server name
96
- server = conn.servers.find { |s| s.name == name }
97
- raise "Can't find server #{name}" if server.nil?
98
- server
99
- end
100
- end
101
- end