vagrant-profitbricks 1.0.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.
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