vagrant-conoha 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.
Files changed (109) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +22 -0
  3. data/.rubocop.yml +35 -0
  4. data/CHANGELOG.md +3 -0
  5. data/Gemfile +19 -0
  6. data/LICENSE +23 -0
  7. data/Rakefile +25 -0
  8. data/Vagrantfile +71 -0
  9. data/dummy.box +0 -0
  10. data/example_box/README.md +13 -0
  11. data/example_box/metadata.json +3 -0
  12. data/functional_tests/Vagrantfile +58 -0
  13. data/functional_tests/keys/vagrant-openstack +27 -0
  14. data/functional_tests/keys/vagrant-openstack.pub +1 -0
  15. data/functional_tests/run_tests.sh +142 -0
  16. data/lib/vagrant-conoha.rb +29 -0
  17. data/lib/vagrant-conoha/action.rb +227 -0
  18. data/lib/vagrant-conoha/action/abstract_action.rb +22 -0
  19. data/lib/vagrant-conoha/action/connect_openstack.rb +60 -0
  20. data/lib/vagrant-conoha/action/create_server.rb +154 -0
  21. data/lib/vagrant-conoha/action/create_stack.rb +68 -0
  22. data/lib/vagrant-conoha/action/delete_server.rb +53 -0
  23. data/lib/vagrant-conoha/action/delete_stack.rb +73 -0
  24. data/lib/vagrant-conoha/action/message.rb +19 -0
  25. data/lib/vagrant-conoha/action/provision.rb +60 -0
  26. data/lib/vagrant-conoha/action/read_ssh_info.rb +72 -0
  27. data/lib/vagrant-conoha/action/read_state.rb +43 -0
  28. data/lib/vagrant-conoha/action/resume.rb +24 -0
  29. data/lib/vagrant-conoha/action/start_server.rb +24 -0
  30. data/lib/vagrant-conoha/action/stop_server.rb +25 -0
  31. data/lib/vagrant-conoha/action/suspend.rb +24 -0
  32. data/lib/vagrant-conoha/action/sync_folders.rb +129 -0
  33. data/lib/vagrant-conoha/action/wait_accessible.rb +61 -0
  34. data/lib/vagrant-conoha/action/wait_active.rb +33 -0
  35. data/lib/vagrant-conoha/action/wait_stop.rb +33 -0
  36. data/lib/vagrant-conoha/catalog/openstack_catalog.rb +67 -0
  37. data/lib/vagrant-conoha/client/cinder.rb +39 -0
  38. data/lib/vagrant-conoha/client/domain.rb +159 -0
  39. data/lib/vagrant-conoha/client/glance.rb +65 -0
  40. data/lib/vagrant-conoha/client/heat.rb +49 -0
  41. data/lib/vagrant-conoha/client/http_utils.rb +116 -0
  42. data/lib/vagrant-conoha/client/keystone.rb +77 -0
  43. data/lib/vagrant-conoha/client/neutron.rb +48 -0
  44. data/lib/vagrant-conoha/client/nova.rb +212 -0
  45. data/lib/vagrant-conoha/client/openstack.rb +59 -0
  46. data/lib/vagrant-conoha/client/request_logger.rb +23 -0
  47. data/lib/vagrant-conoha/client/rest_utils.rb +25 -0
  48. data/lib/vagrant-conoha/command/abstract_command.rb +51 -0
  49. data/lib/vagrant-conoha/command/flavor_list.rb +24 -0
  50. data/lib/vagrant-conoha/command/image_list.rb +29 -0
  51. data/lib/vagrant-conoha/command/main.rb +51 -0
  52. data/lib/vagrant-conoha/command/network_list.rb +25 -0
  53. data/lib/vagrant-conoha/command/openstack_command.rb +16 -0
  54. data/lib/vagrant-conoha/command/reset.rb +20 -0
  55. data/lib/vagrant-conoha/command/subnet_list.rb +22 -0
  56. data/lib/vagrant-conoha/command/utils.rb +22 -0
  57. data/lib/vagrant-conoha/command/volume_list.rb +25 -0
  58. data/lib/vagrant-conoha/config.rb +390 -0
  59. data/lib/vagrant-conoha/config/http.rb +39 -0
  60. data/lib/vagrant-conoha/config_resolver.rb +285 -0
  61. data/lib/vagrant-conoha/errors.rb +187 -0
  62. data/lib/vagrant-conoha/logging.rb +39 -0
  63. data/lib/vagrant-conoha/plugin.rb +48 -0
  64. data/lib/vagrant-conoha/provider.rb +50 -0
  65. data/lib/vagrant-conoha/utils.rb +26 -0
  66. data/lib/vagrant-conoha/version.rb +15 -0
  67. data/lib/vagrant-conoha/version_checker.rb +76 -0
  68. data/locales/en.yml +393 -0
  69. data/spec/vagrant-conoha/action/connect_openstack_spec.rb +695 -0
  70. data/spec/vagrant-conoha/action/create_server_spec.rb +225 -0
  71. data/spec/vagrant-conoha/action/create_stack_spec.rb +99 -0
  72. data/spec/vagrant-conoha/action/delete_server_spec.rb +89 -0
  73. data/spec/vagrant-conoha/action/delete_stack_spec.rb +63 -0
  74. data/spec/vagrant-conoha/action/message_spec.rb +33 -0
  75. data/spec/vagrant-conoha/action/provision_spec.rb +104 -0
  76. data/spec/vagrant-conoha/action/read_ssh_info_spec.rb +190 -0
  77. data/spec/vagrant-conoha/action/read_state_spec.rb +81 -0
  78. data/spec/vagrant-conoha/action/resume_server_spec.rb +49 -0
  79. data/spec/vagrant-conoha/action/start_server_spec.rb +49 -0
  80. data/spec/vagrant-conoha/action/stop_server_spec.rb +49 -0
  81. data/spec/vagrant-conoha/action/suspend_server_spec.rb +49 -0
  82. data/spec/vagrant-conoha/action/sync_folders_spec.rb +155 -0
  83. data/spec/vagrant-conoha/action/wait_accessible_spec.rb +67 -0
  84. data/spec/vagrant-conoha/action/wait_active_spec.rb +53 -0
  85. data/spec/vagrant-conoha/action/wait_stop_spec.rb +53 -0
  86. data/spec/vagrant-conoha/action_spec.rb +120 -0
  87. data/spec/vagrant-conoha/client/cinder_spec.rb +127 -0
  88. data/spec/vagrant-conoha/client/glance_spec.rb +143 -0
  89. data/spec/vagrant-conoha/client/heat_spec.rb +128 -0
  90. data/spec/vagrant-conoha/client/keystone_spec.rb +150 -0
  91. data/spec/vagrant-conoha/client/neutron_spec.rb +171 -0
  92. data/spec/vagrant-conoha/client/nova_spec.rb +757 -0
  93. data/spec/vagrant-conoha/client/utils_spec.rb +176 -0
  94. data/spec/vagrant-conoha/command/flavor_list_spec.rb +43 -0
  95. data/spec/vagrant-conoha/command/image_list_spec.rb +95 -0
  96. data/spec/vagrant-conoha/command/network_list_spec.rb +65 -0
  97. data/spec/vagrant-conoha/command/reset_spec.rb +24 -0
  98. data/spec/vagrant-conoha/command/subnet_list_spec.rb +45 -0
  99. data/spec/vagrant-conoha/command/volume_list_spec.rb +40 -0
  100. data/spec/vagrant-conoha/config_resolver_spec.rb +860 -0
  101. data/spec/vagrant-conoha/config_spec.rb +373 -0
  102. data/spec/vagrant-conoha/e2e_spec.rb.save +27 -0
  103. data/spec/vagrant-conoha/provider_spec.rb +13 -0
  104. data/spec/vagrant-conoha/spec_helper.rb +37 -0
  105. data/spec/vagrant-conoha/utils_spec.rb +129 -0
  106. data/spec/vagrant-conoha/version_checker_spec.rb +39 -0
  107. data/stackrc +25 -0
  108. data/vagrant-conoha.gemspec +32 -0
  109. metadata +343 -0
@@ -0,0 +1,59 @@
1
+ require 'log4r'
2
+ require 'json'
3
+
4
+ require 'vagrant-conoha/client/heat'
5
+ require 'vagrant-conoha/client/keystone'
6
+ require 'vagrant-conoha/client/nova'
7
+ require 'vagrant-conoha/client/neutron'
8
+ require 'vagrant-conoha/client/cinder'
9
+ require 'vagrant-conoha/client/glance'
10
+
11
+ module VagrantPlugins
12
+ module ConoHa
13
+ class Session
14
+ include Singleton
15
+
16
+ attr_accessor :token
17
+ attr_accessor :project_id
18
+ attr_accessor :endpoints
19
+
20
+ def initialize
21
+ @token = nil
22
+ @project_id = nil
23
+ @endpoints = {}
24
+ end
25
+
26
+ def reset
27
+ initialize
28
+ end
29
+ end
30
+
31
+ def self.session
32
+ Session.instance
33
+ end
34
+
35
+ def self.keystone
36
+ ConoHa::KeystoneClient.instance
37
+ end
38
+
39
+ def self.nova
40
+ ConoHa::NovaClient.instance
41
+ end
42
+
43
+ def self.heat
44
+ ConoHa::HeatClient.instance
45
+ end
46
+
47
+ def self.neutron
48
+ ConoHa::NeutronClient.instance
49
+ end
50
+
51
+ def self.cinder
52
+ ConoHa::CinderClient.instance
53
+ end
54
+
55
+ def self.glance
56
+ ConoHa::GlanceClient.instance
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,23 @@
1
+ require 'log4r'
2
+ require 'json'
3
+
4
+ module VagrantPlugins
5
+ module ConoHa
6
+ module HttpUtils
7
+ module RequestLogger
8
+ def log_request(method, url, body = nil, headers)
9
+ @logger.debug "request => method : #{method}"
10
+ @logger.debug "request => url : #{url}"
11
+ @logger.debug "request => headers : #{headers}"
12
+ @logger.debug "request => body : #{body}" unless body.nil?
13
+ end
14
+
15
+ def log_response(response)
16
+ @logger.debug "response => code : #{response.code}"
17
+ @logger.debug "response => headers : #{response.headers}"
18
+ @logger.debug "response => body : #{response}"
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,25 @@
1
+ require 'restclient'
2
+
3
+ module VagrantPlugins
4
+ module ConoHa
5
+ module RestUtils
6
+ def self.get(env, url, headers = {}, &block)
7
+ config = env[:machine].provider_config
8
+ RestClient::Request.execute(method: :get, url: url, headers: headers,
9
+ timeout: config.http.read_timeout, open_timeout: config.http.open_timeout, &block)
10
+ end
11
+
12
+ def self.post(env, url, payload, headers = {}, &block)
13
+ config = env[:machine].provider_config
14
+ RestClient::Request.execute(method: :post, url: url, payload: payload, headers: headers,
15
+ timeout: config.http.read_timeout, open_timeout: config.http.open_timeout, &block)
16
+ end
17
+
18
+ def self.delete(env, url, headers = {}, &block)
19
+ config = env[:machine].provider_config
20
+ RestClient::Request.execute(method: :delete, url: url, headers: headers,
21
+ timeout: config.http.read_timeout, open_timeout: config.http.open_timeout, &block)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,51 @@
1
+ require 'vagrant-conoha/client/openstack'
2
+ require 'colorize'
3
+
4
+ module VagrantPlugins
5
+ module ConoHa
6
+ module Command
7
+ class AbstractCommand < Vagrant.plugin('2', :command)
8
+ def initialize(argv, env)
9
+ @env = env
10
+ super(normalize_args(argv), env)
11
+ end
12
+
13
+ def execute(name)
14
+ env = {}
15
+ with_target_vms(nil, provider: :conoha) do |machine|
16
+ env[:machine] = machine
17
+ env[:ui] = @env.ui
18
+ end
19
+
20
+ before_cmd(name, @argv, env)
21
+
22
+ cmd(name, @argv, env)
23
+ @env.ui.info('')
24
+ # rubocop:disable Lint/RescueException
25
+ rescue Errors::VagrantOpenstackError, SystemExit, Interrupt => e
26
+ raise e
27
+ rescue Exception => e
28
+ puts I18n.t('vagrant_openstack.global_error').red unless e.message && e.message.start_with?('Catched Error:')
29
+ raise e
30
+ end
31
+ # rubocop:enable Lint/RescueException
32
+
33
+ #
34
+ # Before Vagrant 1.5, args list ends with an extra arg '--'. It removes it if present.
35
+ #
36
+ def normalize_args(args)
37
+ return args if args.nil?
38
+ args.pop if args.size > 0 && args.last == '--'
39
+ args
40
+ end
41
+
42
+ def before_cmd(_name, _argv, _env)
43
+ end
44
+
45
+ def cmd(_name, _argv, _env)
46
+ fail 'Command not implemented. \'cmd\' method must be overridden in all subclasses'
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,24 @@
1
+ require 'vagrant-conoha/command/openstack_command'
2
+
3
+ module VagrantPlugins
4
+ module ConoHa
5
+ module Command
6
+ class FlavorList < OpenstackCommand
7
+ def self.synopsis
8
+ I18n.t('vagrant_openstack.command.flavor_list_synopsis')
9
+ end
10
+
11
+ def cmd(name, argv, env)
12
+ fail Errors::NoArgRequiredForCommand, cmd: name unless argv.size == 0
13
+ flavors = env[:openstack_client].nova.get_all_flavors(env)
14
+
15
+ rows = []
16
+ flavors.each do |f|
17
+ rows << [f.id, f.name, f.vcpus, f.ram, f.disk]
18
+ end
19
+ display_table(env, ['Id', 'Name', 'vCPU', 'RAM (Mo)', 'Disk size (Go)'], rows)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,29 @@
1
+ require 'vagrant-conoha/command/openstack_command'
2
+
3
+ module VagrantPlugins
4
+ module ConoHa
5
+ module Command
6
+ class ImageList < OpenstackCommand
7
+ def self.synopsis
8
+ I18n.t('vagrant_openstack.command.image_list_synopsis')
9
+ end
10
+
11
+ def cmd(name, argv, env)
12
+ fail Errors::NoArgRequiredForCommand, cmd: name unless argv.size == 0
13
+ rows = []
14
+ headers = %w(Id Name)
15
+ if env[:openstack_client].session.endpoints.key? :image
16
+ images = env[:openstack_client].glance.get_all_images(env)
17
+ images.each { |i| rows << [i.id, i.name, i.visibility, i.size.to_i / 1024 / 1024, i.min_ram, i.min_disk] }
18
+ headers << ['Visibility', 'Size (Mo)', 'Min RAM (Go)', 'Min Disk (Go)']
19
+ headers = headers.flatten
20
+ else
21
+ images = env[:openstack_client].nova.get_all_images(env)
22
+ images.each { |image| rows << [image.id, image.name] }
23
+ end
24
+ display_table(env, headers, rows)
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,51 @@
1
+ module VagrantPlugins
2
+ module ConoHa
3
+ module Command
4
+ COMMANDS = [
5
+ { name: :'image-list', file: 'image_list', clazz: 'ImageList' },
6
+ { name: :'flavor-list', file: 'flavor_list', clazz: 'FlavorList' },
7
+ { name: :'network-list', file: 'network_list', clazz: 'NetworkList' },
8
+ { name: :'subnet-list', file: 'subnet_list', clazz: 'SubnetList' },
9
+ { name: :'volume-list', file: 'volume_list', clazz: 'VolumeList' },
10
+ { name: :'reset', file: 'reset', clazz: 'Reset' }
11
+ ]
12
+
13
+ class Main < Vagrant.plugin('2', :command)
14
+ def self.synopsis
15
+ I18n.t('vagrant_openstack.command.main_synopsis')
16
+ end
17
+
18
+ def initialize(argv, env)
19
+ @env = env
20
+ @main_args, @sub_command, @sub_args = split_main_and_subcommand(argv)
21
+ @commands = Vagrant::Registry.new
22
+
23
+ COMMANDS.each do |cmd|
24
+ @commands.register(cmd[:name]) do
25
+ require_relative cmd[:file]
26
+ Command.const_get(cmd[:clazz])
27
+ end
28
+ end
29
+
30
+ super(argv, env)
31
+ end
32
+
33
+ def execute
34
+ command_class = @commands.get(@sub_command.to_sym) if @sub_command
35
+ return usage unless command_class && @sub_command
36
+ command_class.new(@sub_args, @env).execute(@sub_command)
37
+ end
38
+
39
+ def usage
40
+ @env.ui.info I18n.t('vagrant_openstack.command.main_usage')
41
+ @env.ui.info ''
42
+ @env.ui.info I18n.t('vagrant_openstack.command.available_subcommands')
43
+ @commands.each do |key, value|
44
+ @env.ui.info " #{key.to_s.ljust(20)} #{value.synopsis}"
45
+ end
46
+ @env.ui.info ''
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,25 @@
1
+ require 'vagrant-conoha/command/openstack_command'
2
+
3
+ module VagrantPlugins
4
+ module ConoHa
5
+ module Command
6
+ class NetworkList < OpenstackCommand
7
+ def self.synopsis
8
+ I18n.t('vagrant_openstack.command.network_list_synopsis')
9
+ end
10
+
11
+ def cmd(name, argv, env)
12
+ fail Errors::UnrecognizedArgForCommand, cmd: name, arg: argv[1] if argv.size > 1
13
+ if argv.size == 0
14
+ networks = env[:openstack_client].neutron.get_private_networks(env)
15
+ elsif argv[0] == 'all'
16
+ networks = env[:openstack_client].neutron.get_all_networks(env)
17
+ else
18
+ fail Errors::UnrecognizedArgForCommand, cmd: name, arg: argv[0]
19
+ end
20
+ display_item_list(env, networks)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,16 @@
1
+ require 'vagrant-conoha/command/utils'
2
+ require 'vagrant-conoha/command/abstract_command'
3
+
4
+ module VagrantPlugins
5
+ module ConoHa
6
+ module Command
7
+ class OpenstackCommand < AbstractCommand
8
+ include VagrantPlugins::ConoHa::Command::Utils
9
+
10
+ def before_cmd(_name, _argv, env)
11
+ VagrantPlugins::ConoHa::Action::ConnectOpenstack.new(nil, env).call(env)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,20 @@
1
+ require 'vagrant-conoha/command/utils'
2
+ require 'vagrant-conoha/command/abstract_command'
3
+
4
+ module VagrantPlugins
5
+ module ConoHa
6
+ module Command
7
+ class Reset < AbstractCommand
8
+ def self.synopsis
9
+ I18n.t('vagrant_openstack.command.reset')
10
+ end
11
+
12
+ def cmd(name, argv, env)
13
+ fail Errors::NoArgRequiredForCommand, cmd: name unless argv.size == 0
14
+ FileUtils.remove_dir("#{env[:machine].data_dir}")
15
+ env[:ui].info 'Vagrant ConoHa has been reset.'
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,22 @@
1
+ require 'vagrant-conoha/command/openstack_command'
2
+
3
+ module VagrantPlugins
4
+ module ConoHa
5
+ module Command
6
+ class SubnetList < OpenstackCommand
7
+ def self.synopsis
8
+ I18n.t('vagrant_openstack.command.subnet_list_synopsis')
9
+ end
10
+
11
+ def cmd(name, argv, env)
12
+ fail Errors::NoArgRequiredForCommand, cmd: name unless argv.size == 0
13
+ rows = []
14
+ env[:openstack_client].neutron.get_subnets(env).each do |subnet|
15
+ rows << [subnet.id, subnet.name, subnet.cidr, subnet.enable_dhcp, subnet.network_id]
16
+ end
17
+ display_table(env, ['Id', 'Name', 'CIDR', 'DHCP', 'Network Id'], rows)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,22 @@
1
+ require 'terminal-table'
2
+
3
+ module VagrantPlugins
4
+ module ConoHa
5
+ module Command
6
+ module Utils
7
+ def display_item_list(env, items)
8
+ rows = []
9
+ items.each do |item|
10
+ rows << [item.id, item.name]
11
+ end
12
+ display_table(env, %w(Id Name), rows)
13
+ end
14
+
15
+ def display_table(env, headers, rows)
16
+ table = Terminal::Table.new headings: headers, rows: rows
17
+ env[:ui].info("\n#{table}")
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,25 @@
1
+ require 'vagrant-conoha/command/openstack_command'
2
+
3
+ module VagrantPlugins
4
+ module ConoHa
5
+ module Command
6
+ class VolumeList < OpenstackCommand
7
+ def self.synopsis
8
+ I18n.t('vagrant_openstack.command.volume_list_synopsis')
9
+ end
10
+
11
+ def cmd(name, argv, env)
12
+ fail Errors::NoArgRequiredForCommand, cmd: name unless argv.size == 0
13
+ volumes = env[:openstack_client].cinder.get_all_volumes(env)
14
+
15
+ rows = []
16
+ volumes.each do |v|
17
+ attachment = "#{v.instance_id} (#{v.device})" unless v.instance_id.nil?
18
+ rows << [v.id, v.name, v.size, v.status, attachment]
19
+ end
20
+ display_table(env, ['Id', 'Name', 'Size (Go)', 'Status', 'Attachment (instance id and device)'], rows)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,390 @@
1
+ require 'vagrant'
2
+ require 'colorize'
3
+ require 'vagrant-conoha/config/http'
4
+
5
+ module VagrantPlugins
6
+ module ConoHa
7
+ class Config < Vagrant.plugin('2', :config)
8
+ # The API key to access Openstack.
9
+ #
10
+ attr_accessor :password
11
+
12
+ # The compute service url to access Openstack. If nil, it will read from hypermedia catalog form REST API
13
+ #
14
+ attr_accessor :openstack_compute_url
15
+
16
+ # The network service url to access Openstack. If nil, it will read from hypermedia catalog form REST API
17
+ #
18
+ attr_accessor :openstack_network_url
19
+
20
+ # The block storage service url to access Openstack. If nil, it will read from hypermedia catalog form REST API
21
+ #
22
+ attr_accessor :openstack_volume_url
23
+
24
+ # The orchestration service url to access Openstack. If nil, it will read from hypermedia catalog form REST API
25
+ #
26
+ attr_accessor :openstack_orchestration_url
27
+
28
+ # The image service url to access Openstack. If nil, it will read from hypermedia catalog form REST API
29
+ #
30
+ attr_accessor :openstack_image_url
31
+
32
+ # The authentication endpoint. This defaults to Openstack's global authentication endpoint.
33
+ attr_accessor :openstack_auth_url
34
+
35
+ # Openstack region
36
+ attr_accessor :region
37
+
38
+ # The flavor of server to launch, either the ID or name. This
39
+ # can also be a regular expression to partially match a name.
40
+ attr_accessor :flavor
41
+
42
+ # The name or ID of the image to use. This can also be a regular
43
+ # expression to partially match a name.
44
+ attr_accessor :image
45
+
46
+ # Volume to boot the vm from
47
+ #
48
+ attr_accessor :volume_boot
49
+
50
+ #
51
+ # The name of the openstack project on witch the vm will be created.
52
+ #
53
+ attr_accessor :tenant_name
54
+
55
+ # The name of the server. This defaults to the name of the machine
56
+ # defined by Vagrant (via `config.vm.define`), but can be overriden
57
+ # here.
58
+ attr_accessor :server_name
59
+
60
+ # The username to access Openstack.
61
+ #
62
+ # @return [String]
63
+ attr_accessor :username
64
+
65
+ # The name of the keypair to use.
66
+ #
67
+ # @return [String]
68
+ attr_accessor :keypair_name
69
+
70
+ # The SSH username to use with this OpenStack instance. This overrides
71
+ # the `config.ssh.username` variable.
72
+ #
73
+ # @return [String]
74
+ attr_accessor :ssh_username
75
+
76
+ # The SSH timeout use after server creation. If server startup is too long
77
+ # the timeout value can be increase with this variable. Default is 60 seconds
78
+ #
79
+ # @return [Integer]
80
+ attr_accessor :ssh_timeout
81
+
82
+ # Opt files/directories in to the rsync operation performed by this provider
83
+ #
84
+ # @return [Array]
85
+ attr_accessor :rsync_includes
86
+
87
+ # The floating IP address from the IP pool which will be assigned to the instance.
88
+ #
89
+ # @return [String]
90
+ attr_accessor :floating_ip
91
+
92
+ # The floating IP pool from where new IPs will be allocated
93
+ #
94
+ # @return [String]
95
+ attr_accessor :floating_ip_pool
96
+
97
+ # if set to true, vagrant will always allocate floating ip instead of trying to reuse unassigned ones
98
+ # default to false
99
+ #
100
+ # @return [Boolean]
101
+ attr_accessor :floating_ip_pool_always_allocate
102
+
103
+ # Sync folder method. Can be either "rsync" or "none"
104
+ #
105
+ # @return [String]
106
+ attr_accessor :sync_method
107
+
108
+ # Sync folder ignore files. A list of files containing exclude patterns to ignore in the rsync operation
109
+ # performed by this provider
110
+ #
111
+ # @return [Array]
112
+ attr_accessor :rsync_ignore_files
113
+
114
+ # Network list the VM will be connected to
115
+ #
116
+ # @return [Array]
117
+ attr_accessor :networks
118
+
119
+ # Volumes list that will be attached to the VM
120
+ #
121
+ # @return [Array]
122
+ attr_accessor :volumes
123
+
124
+ # Stack that will be created and associated to the instances
125
+ #
126
+ # @return [Array]
127
+ attr_accessor :stacks
128
+
129
+ # Public key path to create OpenStack keypair
130
+ #
131
+ # @return [Array]
132
+ attr_accessor :public_key_path
133
+
134
+ # Availability Zone
135
+ #
136
+ # @return [String]
137
+ attr_accessor :availability_zone
138
+
139
+ # Pass hints to the OpenStack scheduler, e.g. { "cell": "some cell name" }
140
+ attr_accessor :scheduler_hints
141
+
142
+ # List of strings representing the security groups to apply.
143
+ # e.g. ['ssh', 'http']
144
+ #
145
+ # @return [Array[String]]
146
+ attr_accessor :security_groups
147
+
148
+ # User data to be sent to the newly created OpenStack instance. Use this
149
+ # e.g. to inject a script at boot time.
150
+ #
151
+ # @return [String]
152
+ attr_accessor :user_data
153
+
154
+ # A Hash of metadata that will be sent to the instance for configuration
155
+ #
156
+ # @return [Hash]
157
+ attr_accessor :metadata
158
+
159
+ # Flag to enable/disable all SSH actions (to use for instance on private networks)
160
+ #
161
+ # @return [Boolean]
162
+ attr_accessor :ssh_disabled
163
+
164
+ # Specify the endpoint_type to use : publicURL, adminURL, or internalURL (default is publicURL)
165
+ #
166
+ # @return [String]
167
+ attr_accessor :endpoint_type
168
+
169
+ #
170
+ # @return [Integer]
171
+ attr_accessor :server_create_timeout
172
+
173
+ #
174
+ # @return [Integer]
175
+ attr_accessor :server_active_timeout
176
+
177
+ #
178
+ # @return [Integer]
179
+ attr_accessor :server_stop_timeout
180
+
181
+ #
182
+ # @return [Integer]
183
+ attr_accessor :server_delete_timeout
184
+
185
+ #
186
+ # @return [Integer]
187
+ attr_accessor :stack_create_timeout
188
+
189
+ #
190
+ # @return [Integer]
191
+ attr_accessor :stack_delete_timeout
192
+
193
+ #
194
+ # @return [HttpConfig]
195
+ attr_accessor :http
196
+
197
+ def initialize
198
+ @password = UNSET_VALUE
199
+ @openstack_compute_url = UNSET_VALUE
200
+ @openstack_network_url = UNSET_VALUE
201
+ @openstack_volume_url = UNSET_VALUE
202
+ @openstack_orchestration_url = UNSET_VALUE
203
+ @openstack_image_url = UNSET_VALUE
204
+ @openstack_auth_url = UNSET_VALUE
205
+ @endpoint_type = UNSET_VALUE
206
+ @region = UNSET_VALUE
207
+ @flavor = UNSET_VALUE
208
+ @image = UNSET_VALUE
209
+ @volume_boot = UNSET_VALUE
210
+ @tenant_name = UNSET_VALUE
211
+ @server_name = UNSET_VALUE
212
+ @username = UNSET_VALUE
213
+ @rsync_includes = []
214
+ @rsync_ignore_files = []
215
+ @keypair_name = UNSET_VALUE
216
+ @ssh_username = UNSET_VALUE
217
+ @ssh_timeout = UNSET_VALUE
218
+ @floating_ip = UNSET_VALUE
219
+ @floating_ip_pool = []
220
+ @floating_ip_pool_always_allocate = UNSET_VALUE
221
+ @sync_method = UNSET_VALUE
222
+ @availability_zone = UNSET_VALUE
223
+ @networks = []
224
+ @stacks = []
225
+ @volumes = []
226
+ @public_key_path = UNSET_VALUE
227
+ @scheduler_hints = UNSET_VALUE
228
+ @security_groups = UNSET_VALUE
229
+ @user_data = UNSET_VALUE
230
+ @metadata = UNSET_VALUE
231
+ @ssh_disabled = UNSET_VALUE
232
+ @server_create_timeout = UNSET_VALUE
233
+ @server_active_timeout = UNSET_VALUE
234
+ @server_stop_timeout = UNSET_VALUE
235
+ @server_delete_timeout = UNSET_VALUE
236
+ @stack_create_timeout = UNSET_VALUE
237
+ @stack_delete_timeout = UNSET_VALUE
238
+ @http = HttpConfig.new
239
+ end
240
+
241
+ def merge(other)
242
+ result = self.class.new
243
+
244
+ # Set all of our instance variables on the new class
245
+ [self, other].each do |obj|
246
+ obj.instance_variables.each do |key|
247
+ # Ignore keys that start with a double underscore. This allows
248
+ # configuration classes to still hold around internal state
249
+ # that isn't propagated.
250
+ next if key.to_s.start_with?('@__')
251
+
252
+ # Let user inputs a string or an array for floating ip pool attribute
253
+ obj.floating_ip_pool = [obj.floating_ip_pool].flatten if key.eql?(:@floating_ip_pool) && !obj.floating_ip_pool.nil?
254
+
255
+ # Let user inputs a string or an array for networks attribute
256
+ obj.networks = [obj.networks].flatten if key.eql?(:@networks) && !obj.networks.nil?
257
+
258
+ # Don't set the value if it is the unset value, either.
259
+ value = obj.instance_variable_get(key)
260
+
261
+ if [:@networks, :@volumes, :@rsync_includes, :@rsync_ignore_files, :@floating_ip_pool, :@stacks].include? key
262
+ result.instance_variable_set(key, value) unless value.empty?
263
+ elsif [:@http].include? key
264
+ result.instance_variable_set(key, instance_variable_get(key).merge(other.instance_variable_get(key))) if value != UNSET_VALUE
265
+ else
266
+ result.instance_variable_set(key, value) if value != UNSET_VALUE
267
+ end
268
+ end
269
+ end
270
+
271
+ # Persist through the set of invalid methods
272
+ this_invalid = @__invalid_methods || Set.new
273
+ other_invalid = other.instance_variable_get(:"@__invalid_methods") || Set.new
274
+ result.instance_variable_set(:"@__invalid_methods", this_invalid + other_invalid)
275
+
276
+ result
277
+ end
278
+
279
+ # rubocop:disable Metrics/CyclomaticComplexity
280
+ def finalize!
281
+ @password = nil if @password == UNSET_VALUE
282
+ @openstack_compute_url = nil if @openstack_compute_url == UNSET_VALUE
283
+ @openstack_network_url = nil if @openstack_network_url == UNSET_VALUE
284
+ @openstack_orchestration_url = nil if @openstack_orchestration_url == UNSET_VALUE
285
+ @openstack_volume_url = nil if @openstack_volume_url == UNSET_VALUE
286
+ @openstack_image_url = nil if @openstack_image_url == UNSET_VALUE
287
+ @openstack_auth_url = nil if @openstack_auth_url == UNSET_VALUE
288
+ @endpoint_type = 'publicURL' if @endpoint_type == UNSET_VALUE
289
+ @region = nil if @region == UNSET_VALUE
290
+ @flavor = nil if @flavor == UNSET_VALUE
291
+ @image = nil if @image == UNSET_VALUE
292
+ @volume_boot = nil if @volume_boot == UNSET_VALUE
293
+ @tenant_name = nil if @tenant_name == UNSET_VALUE
294
+ @server_name = nil if @server_name == UNSET_VALUE
295
+ @username = nil if @username == UNSET_VALUE
296
+ @rsync_includes = nil if @rsync_includes.empty?
297
+ @rsync_ignore_files = nil if @rsync_ignore_files.empty?
298
+ @floating_ip = nil if @floating_ip == UNSET_VALUE
299
+ @floating_ip_pool = nil if @floating_ip_pool == UNSET_VALUE
300
+ @floating_ip_pool_always_allocate = false if floating_ip_pool_always_allocate == UNSET_VALUE
301
+ @sync_method = 'rsync' if @sync_method == UNSET_VALUE
302
+ @keypair_name = nil if @keypair_name == UNSET_VALUE
303
+ @public_key_path = nil if @public_key_path == UNSET_VALUE
304
+ @availability_zone = nil if @availability_zone == UNSET_VALUE
305
+ @scheduler_hints = nil if @scheduler_hints == UNSET_VALUE
306
+ @security_groups = nil if @security_groups == UNSET_VALUE
307
+ @user_data = nil if @user_data == UNSET_VALUE
308
+ @metadata = nil if @metadata == UNSET_VALUE
309
+ @ssh_disabled = false if @ssh_disabled == UNSET_VALUE
310
+
311
+ # The SSH values by default are nil, and the top-level config
312
+ # `config.ssh` values are used.
313
+ @ssh_username = nil if @ssh_username == UNSET_VALUE
314
+ @ssh_timeout = 180 if @ssh_timeout == UNSET_VALUE
315
+ @server_create_timeout = 200 if @server_create_timeout == UNSET_VALUE
316
+ @server_active_timeout = 200 if @server_active_timeout == UNSET_VALUE
317
+ @server_stop_timeout = 200 if @server_stop_timeout == UNSET_VALUE
318
+ @server_delete_timeout = 200 if @server_delete_timeout == UNSET_VALUE
319
+ @stack_create_timeout = 200 if @stack_create_timeout == UNSET_VALUE
320
+ @stack_delete_timeout = 200 if @stack_delete_timeout == UNSET_VALUE
321
+ @networks = nil if @networks.empty?
322
+ @volumes = nil if @volumes.empty?
323
+ @stacks = nil if @stacks.empty?
324
+ @http.finalize!
325
+ end
326
+ # rubocop:enable Metrics/CyclomaticComplexity
327
+
328
+ def rsync_include(inc)
329
+ @rsync_includes << inc
330
+ end
331
+
332
+ def validate(machine)
333
+ errors = _detected_errors
334
+
335
+ errors << I18n.t('vagrant_openstack.config.password_required') if @password.nil? || @password.empty?
336
+ errors << I18n.t('vagrant_openstack.config.username_required') if @username.nil? || @username.empty?
337
+ errors << I18n.t('vagrant_openstack.config.tenant_name_required') if @tenant_name.nil? || @tenant_name.empty?
338
+ errors << I18n.t('vagrant_openstack.config.invalid_endpoint_type') unless %w(publicURL adminURL internalURL).include?(@endpoint_type)
339
+
340
+ validate_ssh_username(machine, errors)
341
+ validate_stack_config(errors)
342
+ validate_ssh_timeout(errors)
343
+
344
+ if machine.config.ssh.private_key_path
345
+ puts I18n.t('vagrant_openstack.config.keypair_name_required').yellow unless @keypair_name || @public_key_path
346
+ else
347
+ errors << I18n.t('vagrant_openstack.config.private_key_missing') if @keypair_name || @public_key_path
348
+ end
349
+
350
+ {
351
+ openstack_compute_url: @openstack_compute_url,
352
+ openstack_network_url: @openstack_network_url,
353
+ openstack_volume_url: @openstack_volume_url,
354
+ openstack_orchestration_url: @openstack_orchestration_url,
355
+ openstack_image_url: @openstack_image_url,
356
+ openstack_auth_url: @openstack_auth_url
357
+ }.each_pair do |key, value|
358
+ errors << I18n.t('vagrant_openstack.config.invalid_uri', key: key, uri: value) unless value.nil? || valid_uri?(value)
359
+ end
360
+
361
+ { 'Openstack Provider' => errors }
362
+ end
363
+
364
+ private
365
+
366
+ def validate_stack_config(errors)
367
+ @stacks.each do |stack|
368
+ errors << I18n.t('vagrant_openstack.config.invalid_stack') unless stack[:name] && stack[:template]
369
+ end unless @stacks.nil?
370
+ end
371
+
372
+ def validate_ssh_username(machine, errors)
373
+ puts I18n.t('vagrant_openstack.config.ssh_username_deprecated').yellow if @ssh_username
374
+ errors << I18n.t('vagrant_openstack.config.ssh_username_required') unless @ssh_username || machine.config.ssh.username
375
+ end
376
+
377
+ def validate_ssh_timeout(errors)
378
+ return if @ssh_timeout.nil? || @ssh_timeout == UNSET_VALUE
379
+ @ssh_timeout = Integer(@ssh_timeout) if @ssh_timeout.is_a? String
380
+ rescue ArgumentError
381
+ errors << I18n.t('vagrant_openstack.config.invalid_value_for_parameter', parameter: 'ssh_timeout', value: @ssh_timeout)
382
+ end
383
+
384
+ def valid_uri?(value)
385
+ uri = URI.parse value
386
+ uri.is_a?(URI::HTTP)
387
+ end
388
+ end
389
+ end
390
+ end