vagrant-profitbricks 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +25 -0
  3. data/Appraisals +35 -0
  4. data/CHANGELOG.md +3 -0
  5. data/Gemfile +18 -0
  6. data/LICENSE +202 -0
  7. data/README.md +268 -0
  8. data/RELEASE.md +15 -0
  9. data/Rakefile +21 -0
  10. data/Vagrantfile +30 -0
  11. data/bootstrap.cmd +16 -0
  12. data/dummy.box +36 -0
  13. data/example_box/README.md +13 -0
  14. data/example_box/metadata.json +3 -0
  15. data/features/provision.feature +36 -0
  16. data/features/steps/sdk_steps.rb +13 -0
  17. data/features/steps/server_steps.rb +25 -0
  18. data/features/support/env.rb +35 -0
  19. data/features/support/fog_mock.rb +17 -0
  20. data/features/vagrant-profitbricks.feature +66 -0
  21. data/lib/vagrant-profitbricks.rb +53 -0
  22. data/lib/vagrant-profitbricks/action.rb +166 -0
  23. data/lib/vagrant-profitbricks/action/connect_profitbricks.rb +39 -0
  24. data/lib/vagrant-profitbricks/action/create_image.rb +53 -0
  25. data/lib/vagrant-profitbricks/action/create_server.rb +194 -0
  26. data/lib/vagrant-profitbricks/action/delete_server.rb +43 -0
  27. data/lib/vagrant-profitbricks/action/is_created.rb +16 -0
  28. data/lib/vagrant-profitbricks/action/list_flavors.rb +20 -0
  29. data/lib/vagrant-profitbricks/action/list_images.rb +20 -0
  30. data/lib/vagrant-profitbricks/action/list_keypairs.rb +20 -0
  31. data/lib/vagrant-profitbricks/action/list_networks.rb +20 -0
  32. data/lib/vagrant-profitbricks/action/list_servers.rb +21 -0
  33. data/lib/vagrant-profitbricks/action/message_already_created.rb +16 -0
  34. data/lib/vagrant-profitbricks/action/message_not_created.rb +16 -0
  35. data/lib/vagrant-profitbricks/action/read_ssh_info.rb +49 -0
  36. data/lib/vagrant-profitbricks/action/read_state.rb +39 -0
  37. data/lib/vagrant-profitbricks/action/run_init_script.rb +28 -0
  38. data/lib/vagrant-profitbricks/command/create_image.rb +21 -0
  39. data/lib/vagrant-profitbricks/command/flavors.rb +21 -0
  40. data/lib/vagrant-profitbricks/command/images.rb +33 -0
  41. data/lib/vagrant-profitbricks/command/keypairs.rb +21 -0
  42. data/lib/vagrant-profitbricks/command/list_images.rb +21 -0
  43. data/lib/vagrant-profitbricks/command/networks.rb +21 -0
  44. data/lib/vagrant-profitbricks/command/root.rb +79 -0
  45. data/lib/vagrant-profitbricks/command/servers.rb +21 -0
  46. data/lib/vagrant-profitbricks/config.rb +152 -0
  47. data/lib/vagrant-profitbricks/errors.rb +39 -0
  48. data/lib/vagrant-profitbricks/plugin.rb +44 -0
  49. data/lib/vagrant-profitbricks/provider.rb +50 -0
  50. data/lib/vagrant-profitbricks/version.rb +5 -0
  51. data/locales/en.yml +124 -0
  52. data/spec/spec_helper.rb +20 -0
  53. data/spec/vagrant-profitbricks/actions/list_flavors_spec.rb +48 -0
  54. data/spec/vagrant-profitbricks/actions/list_images_spec.rb +48 -0
  55. data/spec/vagrant-profitbricks/config_spec.rb +150 -0
  56. data/vagrant-profitbricks.gemspec +25 -0
  57. metadata +164 -0
@@ -0,0 +1,16 @@
1
+ module VagrantPlugins
2
+ module ProfitBricks
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_profitbricks.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 ProfitBricks
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_profitbricks.not_created"))
11
+ @app.call(env)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,49 @@
1
+ require "log4r"
2
+
3
+ module VagrantPlugins
4
+ module ProfitBricks
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_profitbricks::action::read_ssh_info")
12
+ end
13
+
14
+ def call(env)
15
+ env[:machine_ssh_info] = read_ssh_info(env[:profitbricks_compute], env[:machine])
16
+
17
+ @app.call(env)
18
+ end
19
+
20
+ def read_ssh_info(profitbricks, machine)
21
+ return nil if machine.id.nil?
22
+
23
+ # Find the machine
24
+ server = profitbricks.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
+ if server.interfaces.empty? || server.internet_access == false
33
+ # The machine can't be found
34
+ @logger.info("Server has no internet access.")
35
+ machine.id = nil
36
+ return nil
37
+ end
38
+
39
+ # Read the DNS info
40
+ return {
41
+ :host => server.nics[0].ips,
42
+ :port => 22,
43
+ :username => "root"
44
+ }
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,39 @@
1
+ require "log4r"
2
+
3
+ module VagrantPlugins
4
+ module ProfitBricks
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_profitbricks::action::read_state")
12
+ end
13
+
14
+ def call(env)
15
+ env[:machine_state_id] = read_state(env[:profitbricks_compute], env[:machine])
16
+
17
+ @app.call(env)
18
+ end
19
+
20
+ def read_state(profitbricks, machine)
21
+ return :not_created if machine.id.nil?
22
+
23
+ # Find the machine
24
+ server = profitbricks.servers.get(machine.provider_config.datacenter_id, machine.id)
25
+ rescue Excon::Error::NotFound
26
+ if server.nil? || server.state == "DELETED"
27
+ # The machine can't be found
28
+ @logger.info("Machine not found or deleted, assuming it got destroyed.")
29
+ machine.id = nil
30
+ return :not_created
31
+ end
32
+
33
+ # Return the state
34
+ return server.state.downcase.to_sym
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,28 @@
1
+ require "log4r"
2
+
3
+ module VagrantPlugins
4
+ module ProfitBricks
5
+ module Action
6
+ class RunInitScript
7
+ def initialize(app, env)
8
+ @app = app
9
+ @logger = Log4r::Logger.new("vagrant_profitbricks::action::run_init_script")
10
+ end
11
+
12
+ def call(env)
13
+ config = env[:machine].provider_config
14
+ machine_config = env[:machine].config
15
+ begin
16
+ communicator = machine_config.vm.communicator ||= :ssh
17
+ rescue NoMethodError
18
+ communicator = :ssh
19
+ end
20
+
21
+ # Can we handle Windows config here?
22
+ @app.call(env)
23
+ env[:machine].communicate.sudo config.init_script if config.init_script && communicator == :ssh
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,21 @@
1
+ module VagrantPlugins
2
+ module ProfitBricks
3
+ module Command
4
+ class CreateImage < Vagrant.plugin("2", :command)
5
+ def execute
6
+ options = {}
7
+ opts = OptionParser.new do |o|
8
+ o.banner = "Usage: vagrant profitbricks images create [options]"
9
+ end
10
+
11
+ argv = parse_options(opts)
12
+ return if !argv
13
+
14
+ with_target_vms(argv, :provider => :profitbricks) do |machine|
15
+ machine.action('create_image')
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ module VagrantPlugins
2
+ module ProfitBricks
3
+ module Command
4
+ class Flavors < Vagrant.plugin("2", :command)
5
+ def execute
6
+ options = {}
7
+ opts = OptionParser.new do |o|
8
+ o.banner = "Usage: vagrant profitbricks flavors [options]"
9
+ end
10
+
11
+ argv = parse_options(opts)
12
+ return if !argv
13
+
14
+ with_target_vms(argv, :provider => :profitbricks) do |machine|
15
+ machine.action('list_flavors')
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,33 @@
1
+ module VagrantPlugins
2
+ module ProfitBricks
3
+ module Command
4
+ class Images < Vagrant.plugin("2", :command)
5
+ def initialize(argv, env)
6
+ @main_args, @sub_command, @sub_args = split_main_and_subcommand(argv)
7
+
8
+ @subcommands = Vagrant::Registry.new
9
+ @subcommands.register(:list) do
10
+ require File.expand_path("../list_images", __FILE__)
11
+ ListImages
12
+ end
13
+
14
+ super(argv, env)
15
+ end
16
+
17
+ def execute
18
+ if @main_args.include?("-h") || @main_args.include?("--help")
19
+ # Print the help for all the profitbricks commands.
20
+ return help
21
+ end
22
+
23
+ command_class = @subcommands.get(@sub_command.to_sym) if @sub_command
24
+ return help if !command_class || !@sub_command
25
+ @logger.debug("Invoking command class: #{command_class} #{@sub_args.inspect}")
26
+
27
+ # Initialize and execute the command class
28
+ command_class.new(@sub_args, @env).execute
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,21 @@
1
+ module VagrantPlugins
2
+ module ProfitBricks
3
+ module Command
4
+ class KeyPairs < Vagrant.plugin("2", :command)
5
+ def execute
6
+ options = {}
7
+ opts = OptionParser.new do |o|
8
+ o.banner = "Usage: vagrant profitbricks keypairs [options]"
9
+ end
10
+
11
+ argv = parse_options(opts)
12
+ return if !argv
13
+
14
+ with_target_vms(argv, :provider => :profitbricks) do |machine|
15
+ machine.action('list_keypairs')
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ module VagrantPlugins
2
+ module ProfitBricks
3
+ module Command
4
+ class ListImages < Vagrant.plugin("2", :command)
5
+ def execute
6
+ options = {}
7
+ opts = OptionParser.new do |o|
8
+ o.banner = "Usage: vagrant profitbricks images list [options]"
9
+ end
10
+
11
+ argv = parse_options(opts)
12
+ return if !argv
13
+
14
+ with_target_vms(argv, :provider => :profitbricks) do |machine|
15
+ machine.action('list_images')
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ module VagrantPlugins
2
+ module ProfitBricks
3
+ module Command
4
+ class Networks < Vagrant.plugin("2", :command)
5
+ def execute
6
+ options = {}
7
+ opts = OptionParser.new do |o|
8
+ o.banner = "Usage: vagrant profitbricks networks [options]"
9
+ end
10
+
11
+ argv = parse_options(opts)
12
+ return if !argv
13
+
14
+ with_target_vms(argv, :provider => :profitbricks) do |machine|
15
+ machine.action('list_networks')
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,79 @@
1
+ require 'vagrant-profitbricks/action'
2
+
3
+ module VagrantPlugins
4
+ module ProfitBricks
5
+ module Command
6
+ class Root < Vagrant.plugin("2", :command)
7
+ def self.synopsis
8
+ I18n.t('vagrant_profitbricks.command.synopsis')
9
+ end
10
+
11
+ def initialize(argv, env)
12
+ @main_args, @sub_command, @sub_args = split_main_and_subcommand(argv)
13
+
14
+ @subcommands = Vagrant::Registry.new
15
+
16
+ @subcommands.register(:images) do
17
+ require File.expand_path("../images", __FILE__)
18
+ Images
19
+ end
20
+ @subcommands.register(:flavors) do
21
+ require File.expand_path("../flavors", __FILE__)
22
+ Flavors
23
+ end
24
+ @subcommands.register(:keypairs) do
25
+ require File.expand_path("../keypairs", __FILE__)
26
+ KeyPairs
27
+ end
28
+ @subcommands.register(:networks) do
29
+ require File.expand_path("../networks", __FILE__)
30
+ Networks
31
+ end
32
+ @subcommands.register(:servers) do
33
+ require File.expand_path("../servers", __FILE__)
34
+ Servers
35
+ end
36
+
37
+ super(argv, env)
38
+ end
39
+
40
+ def execute
41
+ if @main_args.include?("-h") || @main_args.include?("--help")
42
+ # Print the help for all the profitbricks commands.
43
+ return help
44
+ end
45
+
46
+ command_class = @subcommands.get(@sub_command.to_sym) if @sub_command
47
+ return help if !command_class || !@sub_command
48
+ @logger.debug("Invoking command class: #{command_class} #{@sub_args.inspect}")
49
+
50
+ # Initialize and execute the command class
51
+ command_class.new(@sub_args, @env).execute
52
+ end
53
+
54
+ def help
55
+ opts = OptionParser.new do |opts|
56
+ opts.banner = "Usage: vagrant profitbricks <subcommand> [<args>]"
57
+ opts.separator ""
58
+ opts.separator I18n.t('vagrant_profitbricks.command.available_subcommands')
59
+
60
+ # Add the available subcommands as separators in order to print them
61
+ # out as well.
62
+ keys = []
63
+ @subcommands.each { |key, value| keys << key.to_s }
64
+
65
+ keys.sort.each do |key|
66
+ opts.separator " #{key}"
67
+ end
68
+
69
+ opts.separator ""
70
+ opts.separator I18n.t('vagrant_profitbricks.command.help_subcommands') +
71
+ " `vagrant profitbricks <subcommand> -h`"
72
+ end
73
+
74
+ @env.ui.info(opts.help, :prefix => false)
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,21 @@
1
+ module VagrantPlugins
2
+ module ProfitBricks
3
+ module Command
4
+ class Servers < Vagrant.plugin("2", :command)
5
+ def execute
6
+ options = {}
7
+ opts = OptionParser.new do |o|
8
+ o.banner = "Usage: vagrant profitbricks servers [options]"
9
+ end
10
+
11
+ argv = parse_options(opts)
12
+ return if !argv
13
+
14
+ with_target_vms(argv, :provider => :profitbricks) do |machine|
15
+ machine.action('list_servers')
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,152 @@
1
+ require "vagrant"
2
+ require "fog/profitbricks"
3
+
4
+ module VagrantPlugins
5
+ module ProfitBricks
6
+ class Config < Vagrant.plugin("2", :config)
7
+ # The API key to access ProfitBricks - profitbricks_password
8
+ # @return [String]
9
+ attr_accessor :password
10
+
11
+ # The username to access ProfitBricks.
12
+ #
13
+ # @return [String]
14
+ attr_accessor :username
15
+
16
+ # The profitbricks_url to access ProfitBricks.
17
+ #
18
+ # expected to be a string url -
19
+ # 'https://api.profitbricks.com/cloudapi/v3/'
20
+ attr_accessor :profitbricks_url
21
+
22
+ # The flavor of server to launch, either the ID or name. This
23
+ # can also be a regular expression to partially match a name.
24
+ attr_accessor :flavor
25
+
26
+ # The name or ID of the image to use. This can also be a regular
27
+ # expression to partially match a name.
28
+ attr_accessor :image
29
+
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
+ # Id or Name (name can be regular expression ) of datacenter. If provided with Name that doesn't match
37
+ # new datacenter will be created in location specified by location option
38
+ attr_accessor :datacenter_id
39
+
40
+ # Specify location for datacenter if one needs to be created, default value is 'us/las'
41
+ attr_accessor :location
42
+
43
+ # Disk volume size in GB
44
+ attr_accessor :profitbricks_volume_size
45
+
46
+ # Disk volume type (SSD or HDD)
47
+ # Will default to HDD if not specified
48
+ attr_accessor :volume_type
49
+
50
+ # The licence type of the volume. Options: LINUX, WINDOWS, UNKNOWN, OTHER
51
+ # You will need to provide either the image or the licence_type parameters.
52
+ # licence_type is required, but if image is supplied, it is already set and cannot be changed
53
+ attr_accessor :volume_licence_type
54
+
55
+ # The storage availability zone assigned to the volume.
56
+ # Valid values: AUTO, ZONE_1, ZONE_2, or ZONE_3. This only applies to HDD volumes.
57
+ # Leave blank or set to AUTO when provisioning SSD volumes.
58
+ # Will default to AUTO if not specified
59
+ attr_accessor :volume_availability_zone
60
+
61
+ # One or more SSH keys to allow access to the volume via SSH.
62
+ # Works with ProfitBricks supplied Linux images.
63
+ attr_accessor :volume_ssh_keys
64
+
65
+ # POne-time password is set on the Image for the appropriate account.
66
+ # This field may only be set in creation requests. When reading, it always returns null.
67
+ # Password has to contain 8-50 characters. Only these characters are allowed: [abcdefghjkmnpqrstuvxABCDEFGHJKLMNPQRSTUVX23456789]
68
+ attr_accessor :image_password
69
+
70
+ # number of cores in profitbricks server
71
+ attr_accessor :profitbricks_cores
72
+
73
+ # Required, amount of memory in GB allocated to virtual server
74
+ attr_accessor :profitbricks_ram
75
+
76
+ # Sets the CPU type. "AMD_OPTERON" or "INTEL_XEON". Defaults to "AMD_OPTERON".
77
+ attr_accessor :cpu_family
78
+
79
+ # The LAN ID the network interface (NIC) will sit on. If the LAN ID does not exist it will be created.
80
+ attr_accessor :lan_id
81
+
82
+ # Indicates the private IP address has outbound access to the public internet. Defaults to 'false'.
83
+ attr_accessor :nat
84
+
85
+ def initialize
86
+ @password = UNSET_VALUE
87
+ @profitbricks_url = UNSET_VALUE
88
+ @flavor = UNSET_VALUE
89
+ @profitbricks_cores = UNSET_VALUE
90
+ @profitbricks_ram = UNSET_VALUE
91
+ @image = UNSET_VALUE
92
+ @server_name = UNSET_VALUE
93
+ @datacenter_id = UNSET_VALUE
94
+ @username = UNSET_VALUE
95
+ @profitbricks_volume_size = UNSET_VALUE
96
+ @location = UNSET_VALUE
97
+ @volume_type = UNSET_VALUE
98
+ @volume_licence_type = UNSET_VALUE
99
+ @volume_availability_zone = UNSET_VALUE
100
+ @volume_ssh_keys = UNSET_VALUE
101
+ @cpu_family = UNSET_VALUE
102
+ @lan_id = UNSET_VALUE
103
+ @nat = UNSET_VALUE
104
+ @image_password = UNSET_VALUE
105
+ end
106
+
107
+ def finalize!
108
+ @password = nil if @password == UNSET_VALUE
109
+ @profitbricks_url = nil if @profitbricks_url == UNSET_VALUE
110
+ @flavor = nil if @flavor == UNSET_VALUE
111
+ @profitbricks_cores = 1 if @profitbricks_cores == UNSET_VALUE
112
+ @profitbricks_ram = 256 if profitbricks_ram == UNSET_VALUE
113
+ @image = /ubuntu/ if @image == UNSET_VALUE
114
+ @server_name = nil if @server_name == UNSET_VALUE
115
+ @datacenter_id = nil if @datacenter_id == UNSET_VALUE
116
+ @username = nil if @username == UNSET_VALUE
117
+ @profitbricks_volume_size = 5 if @profitbricks_volume_size == UNSET_VALUE
118
+ @location = 'us/las' if @location == UNSET_VALUE
119
+ @volume_type = 'HDD' if @volume_type == UNSET_VALUE
120
+ @volume_licence_type = 'UNKNOWN' if @volume_licence_type == UNSET_VALUE
121
+ @volume_availability_zone = 'AUTO' if @volume_availability_zone == UNSET_VALUE
122
+ @volume_ssh_keys = nil if @volume_ssh_keys == UNSET_VALUE
123
+ @cpu_family = 'AMD_OPTERON' if @cpu_family == UNSET_VALUE
124
+ @lan_id = nil if @lan_id == UNSET_VALUE
125
+ @nat = false if @nat == UNSET_VALUE
126
+ @image_password = nil if @image_password == UNSET_VALUE
127
+ end
128
+
129
+ def validate(machine)
130
+ errors = _detected_errors
131
+
132
+ errors << I18n.t("vagrant_profitbricks.config.password_required") if !@password
133
+ errors << I18n.t("vagrant_profitbricks.config.username_required") if !@username
134
+ errors << I18n.t("vagrant_profitbricks.config.datacenter_required") if !@datacenter_id
135
+ {
136
+ :profitbricks_url => @profitbricks_url
137
+ }.each_pair do |key, value|
138
+ errors << I18n.t("vagrant_profitbricks.config.invalid_uri", :key => key, :uri => value) unless value.nil? || valid_uri?(value)
139
+ end
140
+
141
+ { "ProfitBricks Provider" => errors }
142
+ end
143
+
144
+ private
145
+
146
+ def valid_uri? value
147
+ uri = URI.parse value
148
+ uri.kind_of?(URI::HTTP)
149
+ end
150
+ end
151
+ end
152
+ end