vagrant-rackspace 0.1.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.
@@ -0,0 +1,126 @@
1
+ require "fog"
2
+ require "log4r"
3
+
4
+ require 'vagrant/util/retryable'
5
+
6
+ module VagrantPlugins
7
+ module Rackspace
8
+ module Action
9
+ # This creates the Rackspace server.
10
+ class CreateServer
11
+ include Vagrant::Util::Retryable
12
+
13
+ def initialize(app, env)
14
+ @app = app
15
+ @logger = Log4r::Logger.new("vagrant_rackspace::action::create_server")
16
+ end
17
+
18
+ def call(env)
19
+ # Get the configs
20
+ config = env[:machine].provider_config
21
+
22
+ # Find the flavor
23
+ env[:ui].info(I18n.t("vagrant_rackspace.finding_flavor"))
24
+ flavor = find_matching(env[:rackspace_compute].flavors.all, config.flavor)
25
+ raise Errors::NoMatchingFlavor if !flavor
26
+
27
+ # Find the image
28
+ env[:ui].info(I18n.t("vagrant_rackspace.finding_image"))
29
+ image = find_matching(env[:rackspace_compute].images.all, config.image)
30
+ raise Errors::NoMatchingImage if !image
31
+
32
+ # Figure out the name for the server
33
+ server_name = config.server_name || env[:machine].name
34
+
35
+ # If we're using the default keypair, then show a warning
36
+ default_key_path = Vagrant.source_root.join("keys/vagrant.pub").to_s
37
+ public_key_path = File.expand_path(config.public_key_path, env[:root_path])
38
+
39
+ if default_key_path == public_key_path
40
+ env[:ui].warn(I18n.t("vagrant_rackspace.warn_insecure_ssh"))
41
+ end
42
+
43
+ # Output the settings we're going to use to the user
44
+ env[:ui].info(I18n.t("vagrant_rackspace.launching_server"))
45
+ env[:ui].info(" -- Flavor: #{flavor.name}")
46
+ env[:ui].info(" -- Image: #{image.name}")
47
+ env[:ui].info(" -- Name: #{server_name}")
48
+
49
+ # Build the options for launching...
50
+ options = {
51
+ :flavor_id => flavor.id,
52
+ :image_id => image.id,
53
+ :name => server_name,
54
+ :personality => [
55
+ {
56
+ :path => "/root/.ssh/authorized_keys",
57
+ :contents => Base64.encode64(File.read(public_key_path))
58
+ }
59
+ ]
60
+ }
61
+
62
+ # Create the server
63
+ server = env[:rackspace_compute].servers.create(options)
64
+
65
+ # Store the ID right away so we can track it
66
+ env[:machine].id = server.id
67
+
68
+ # Wait for the server to finish building
69
+ env[:ui].info(I18n.t("vagrant_rackspace.waiting_for_build"))
70
+ retryable(:on => Fog::Errors::TimeoutError, :tries => 200) do
71
+ # If we're interrupted don't worry about waiting
72
+ next if env[:interrupted]
73
+
74
+ # Set the progress
75
+ env[:ui].clear_line
76
+ env[:ui].report_progress(server.progress, 100, false)
77
+
78
+ # Wait for the server to be ready
79
+ begin
80
+ server.wait_for(5) { ready? }
81
+ rescue RuntimeError => e
82
+ # If we don't have an error about a state transition, then
83
+ # we just move on.
84
+ raise if e.message !~ /should have transitioned/
85
+ raise Errors::CreateBadState, :state => server.state
86
+ end
87
+ end
88
+
89
+ if !env[:interrupted]
90
+ # Clear the line one more time so the progress is removed
91
+ env[:ui].clear_line
92
+
93
+ # Wait for SSH to become available
94
+ env[:ui].info(I18n.t("vagrant_rackspace.waiting_for_ssh"))
95
+ while true
96
+ # If we're interrupted then just back out
97
+ break if env[:interrupted]
98
+ break if env[:machine].communicate.ready?
99
+ sleep 2
100
+ end
101
+
102
+ env[:ui].info(I18n.t("vagrant_rackspace.ready"))
103
+ end
104
+
105
+ @app.call(env)
106
+ end
107
+
108
+ protected
109
+
110
+ # This method finds a matching _thing_ in a collection of
111
+ # _things_. This works matching if the ID or NAME equals to
112
+ # `name`. Or, if `name` is a regexp, a partial match is chosen
113
+ # as well.
114
+ def find_matching(collection, name)
115
+ collection.each do |single|
116
+ return single if single.id == name
117
+ return single if single.name == name
118
+ return single if name.is_a?(Regexp) && name =~ single.name
119
+ end
120
+
121
+ nil
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,26 @@
1
+ require "log4r"
2
+
3
+ module VagrantPlugins
4
+ module Rackspace
5
+ module Action
6
+ # This deletes the running server, if there is one.
7
+ class DeleteServer
8
+ def initialize(app, env)
9
+ @app = app
10
+ @logger = Log4r::Logger.new("vagrant_rackspace::action::delete_server")
11
+ end
12
+
13
+ def call(env)
14
+ if env[:machine].id
15
+ env[:ui].info(I18n.t("vagrant_rackspace.deleting_server"))
16
+ server = env[:rackspace_compute].servers.get(env[:machine].id)
17
+ server.destroy
18
+ env[:machine].id = nil
19
+ end
20
+
21
+ @app.call(env)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,16 @@
1
+ module VagrantPlugins
2
+ module Rackspace
3
+ module Action
4
+ class IsCreated
5
+ def initialize(app, env)
6
+ @app = app
7
+ end
8
+
9
+ def call(env)
10
+ env[:result] = env[:machine].state.id != :not_created
11
+ @app.call(env)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ module VagrantPlugins
2
+ module Rackspace
3
+ module Action
4
+ class MessageAlreadyCreated
5
+ def initialize(app, env)
6
+ @app = app
7
+ end
8
+
9
+ def call(env)
10
+ env[:ui].info(I18n.t("vagrant_rackspace.already_created"))
11
+ @app.call(env)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ module VagrantPlugins
2
+ module Rackspace
3
+ module Action
4
+ class MessageNotCreated
5
+ def initialize(app, env)
6
+ @app = app
7
+ end
8
+
9
+ def call(env)
10
+ env[:ui].info(I18n.t("vagrant_rackspace.not_created"))
11
+ @app.call(env)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,42 @@
1
+ require "log4r"
2
+
3
+ module VagrantPlugins
4
+ module Rackspace
5
+ module Action
6
+ # This action reads the SSH info for the machine and puts it into the
7
+ # `:machine_ssh_info` key in the environment.
8
+ class ReadSSHInfo
9
+ def initialize(app, env)
10
+ @app = app
11
+ @logger = Log4r::Logger.new("vagrant_rackspace::action::read_ssh_info")
12
+ end
13
+
14
+ def call(env)
15
+ env[:machine_ssh_info] = read_ssh_info(env[:rackspace_compute], env[:machine])
16
+
17
+ @app.call(env)
18
+ end
19
+
20
+ def read_ssh_info(rackspace, machine)
21
+ return nil if machine.id.nil?
22
+
23
+ # Find the machine
24
+ server = rackspace.servers.get(machine.id)
25
+ if server.nil?
26
+ # The machine can't be found
27
+ @logger.info("Machine couldn't be found, assuming it got destroyed.")
28
+ machine.id = nil
29
+ return nil
30
+ end
31
+
32
+ # Read the DNS info
33
+ return {
34
+ :host => server.ipv4_address,
35
+ :port => 22,
36
+ :username => "root"
37
+ }
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,38 @@
1
+ require "log4r"
2
+
3
+ module VagrantPlugins
4
+ module Rackspace
5
+ module Action
6
+ # This action reads the state of the machine and puts it in the
7
+ # `:machine_state_id` key in the environment.
8
+ class ReadState
9
+ def initialize(app, env)
10
+ @app = app
11
+ @logger = Log4r::Logger.new("vagrant_rackspace::action::read_state")
12
+ end
13
+
14
+ def call(env)
15
+ env[:machine_state_id] = read_state(env[:rackspace_compute], env[:machine])
16
+
17
+ @app.call(env)
18
+ end
19
+
20
+ def read_state(rackspace, machine)
21
+ return :not_created if machine.id.nil?
22
+
23
+ # Find the machine
24
+ server = rackspace.servers.get(machine.id)
25
+ if server.nil? || server.state == "DELETED"
26
+ # The machine can't be found
27
+ @logger.info("Machine not found or deleted, assuming it got destroyed.")
28
+ machine.id = nil
29
+ return :not_created
30
+ end
31
+
32
+ # Return the state
33
+ return server.state.downcase.to_sym
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,57 @@
1
+ require "log4r"
2
+
3
+ require "vagrant/util/subprocess"
4
+
5
+ module VagrantPlugins
6
+ module Rackspace
7
+ module Action
8
+ # This middleware uses `rsync` to sync the folders over to the
9
+ # remote instance.
10
+ class SyncFolders
11
+ def initialize(app, env)
12
+ @app = app
13
+ @logger = Log4r::Logger.new("vagrant_rackspace::action::sync_folders")
14
+ end
15
+
16
+ def call(env)
17
+ @app.call(env)
18
+
19
+ ssh_info = env[:machine].ssh_info
20
+
21
+ env[:machine].config.vm.synced_folders.each do |id, data|
22
+ hostpath = File.expand_path(data[:hostpath], env[:root_path])
23
+ guestpath = data[:guestpath]
24
+
25
+ # Make sure there is a trailing slash on the host path to
26
+ # avoid creating an additional directory with rsync
27
+ hostpath = "#{hostpath}/" if hostpath !~ /\/$/
28
+
29
+ env[:ui].info(I18n.t("vagrant_rackspace.rsync_folder",
30
+ :hostpath => hostpath,
31
+ :guestpath => guestpath))
32
+
33
+ # Create the guest path
34
+ env[:machine].communicate.sudo("mkdir -p '#{guestpath}'")
35
+ env[:machine].communicate.sudo(
36
+ "chown #{ssh_info[:username]} '#{guestpath}'")
37
+
38
+ # Rsync over to the guest path using the SSH info
39
+ command = [
40
+ "rsync", "--verbose", "--archive", "-z",
41
+ "-e", "ssh -p #{ssh_info[:port]} -i '#{ssh_info[:private_key_path]}'",
42
+ hostpath,
43
+ "#{ssh_info[:username]}@#{ssh_info[:host]}:#{guestpath}"]
44
+
45
+ r = Vagrant::Util::Subprocess.execute(*command)
46
+ if r.exit_code != 0
47
+ raise Errors::RsyncError,
48
+ :guestpath => guestpath,
49
+ :hostpath => hostpath,
50
+ :stderr => r.stderr
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,19 @@
1
+ module VagrantPlugins
2
+ module Rackspace
3
+ module Action
4
+ class WarnNetworks
5
+ def initialize(app, env)
6
+ @app = app
7
+ end
8
+
9
+ def call(env)
10
+ if env[:machine].config.vm.networks.length > 0
11
+ env[:ui].warn(I18n.t("vagrant_rackspace.warn_networks"))
12
+ end
13
+
14
+ @app.call(env)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,79 @@
1
+ require "vagrant"
2
+
3
+ module VagrantPlugins
4
+ module Rackspace
5
+ class Config < Vagrant.plugin("2", :config)
6
+ # The API key to access RackSpace.
7
+ #
8
+ # @return [String]
9
+ attr_accessor :api_key
10
+
11
+ # The endpoint to access RackSpace. If nil, it will default
12
+ # to DFW.
13
+ #
14
+ # @return [String]
15
+ attr_accessor :endpoint
16
+
17
+ # The flavor of server to launch, either the ID or name. This
18
+ # can also be a regular expression to partially match a name.
19
+ attr_accessor :flavor
20
+
21
+ # The name or ID of the image to use. This can also be a regular
22
+ # expression to partially match a name.
23
+ attr_accessor :image
24
+
25
+ # The path to the public key to set up on the remote server for SSH.
26
+ # This should match the private key configured with `config.ssh.private_key_path`.
27
+ #
28
+ # @return [String]
29
+ attr_accessor :public_key_path
30
+
31
+ # The name of the server. This defaults to the name of the machine
32
+ # defined by Vagrant (via `config.vm.define`), but can be overriden
33
+ # here.
34
+ attr_accessor :server_name
35
+
36
+ # The username to access RackSpace.
37
+ #
38
+ # @return [String]
39
+ attr_accessor :username
40
+
41
+ def initialize
42
+ @api_key = UNSET_VALUE
43
+ @endpoint = UNSET_VALUE
44
+ @flavor = UNSET_VALUE
45
+ @image = UNSET_VALUE
46
+ @public_key_path = UNSET_VALUE
47
+ @server_name = UNSET_VALUE
48
+ @username = UNSET_VALUE
49
+ end
50
+
51
+ def finalize!
52
+ @api_key = nil if @api_key == UNSET_VALUE
53
+ @endpoint = nil if @endpoint == UNSET_VALUE
54
+ @flavor = /512MB/ if @flavor == UNSET_VALUE
55
+ @image = /Ubuntu/ if @image == UNSET_VALUE
56
+ @server_name = nil if @server_name == UNSET_VALUE
57
+ @username = nil if @username == UNSET_VALUE
58
+
59
+ if @public_key_path == UNSET_VALUE
60
+ @public_key_path = Vagrant.source_root.join("keys/vagrant.pub")
61
+ end
62
+ end
63
+
64
+ def validate(machine)
65
+ errors = []
66
+
67
+ errors << I18n.t("vagrant_rackspace.config.api_key_required") if !@api_key
68
+ errors << I18n.t("vagrant_rackspace.config.username_required") if !@username
69
+
70
+ public_key_path = File.expand_path(@public_key_path, machine.env.root_path)
71
+ if !File.file?(public_key_path)
72
+ errors << I18n.t("vagrant_rackspace.config.public_key_not_found")
73
+ end
74
+
75
+ { "RackSpace Provider" => errors }
76
+ end
77
+ end
78
+ end
79
+ end