vagrant-skytap 0.1.1a

Sign up to get free protection for your applications and to get access to all the features.
Files changed (108) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +21 -0
  3. data/.hgignore +22 -0
  4. data/.project +11 -0
  5. data/.rspec +1 -0
  6. data/CHANGELOG.md +85 -0
  7. data/Gemfile +29 -0
  8. data/LICENSE +8 -0
  9. data/README.md +292 -0
  10. data/Rakefile +31 -0
  11. data/Vagrantfile.orig +34 -0
  12. data/bar/checksums.yaml +7 -0
  13. data/bar/data.tar +0 -0
  14. data/bar/metadata +242 -0
  15. data/dummy.box +0 -0
  16. data/example_box/README.md +13 -0
  17. data/example_box/metadata.json +3 -0
  18. data/lib/vagrant-skytap/action/add_vm_to_environment.rb +35 -0
  19. data/lib/vagrant-skytap/action/create_environment.rb +44 -0
  20. data/lib/vagrant-skytap/action/delete_environment.rb +26 -0
  21. data/lib/vagrant-skytap/action/delete_vm.rb +27 -0
  22. data/lib/vagrant-skytap/action/existence_check.rb +35 -0
  23. data/lib/vagrant-skytap/action/fetch_environment.rb +32 -0
  24. data/lib/vagrant-skytap/action/initialize_api_client.rb +28 -0
  25. data/lib/vagrant-skytap/action/is_running.rb +19 -0
  26. data/lib/vagrant-skytap/action/is_stopped.rb +19 -0
  27. data/lib/vagrant-skytap/action/is_suspended.rb +19 -0
  28. data/lib/vagrant-skytap/action/message_already_created.rb +16 -0
  29. data/lib/vagrant-skytap/action/message_already_running.rb +16 -0
  30. data/lib/vagrant-skytap/action/message_environment_url.rb +16 -0
  31. data/lib/vagrant-skytap/action/message_not_created.rb +16 -0
  32. data/lib/vagrant-skytap/action/message_will_not_destroy.rb +16 -0
  33. data/lib/vagrant-skytap/action/mixin_machine_index.rb +22 -0
  34. data/lib/vagrant-skytap/action/prepare_nfs_settings.rb +46 -0
  35. data/lib/vagrant-skytap/action/prepare_nfs_valid_ids.rb +28 -0
  36. data/lib/vagrant-skytap/action/read_ssh_info.rb +23 -0
  37. data/lib/vagrant-skytap/action/read_state.rb +42 -0
  38. data/lib/vagrant-skytap/action/run_environment.rb +53 -0
  39. data/lib/vagrant-skytap/action/run_vm.rb +51 -0
  40. data/lib/vagrant-skytap/action/set_hostname.rb +31 -0
  41. data/lib/vagrant-skytap/action/set_up_vm.rb +21 -0
  42. data/lib/vagrant-skytap/action/stop_environment.rb +43 -0
  43. data/lib/vagrant-skytap/action/stop_vm.rb +43 -0
  44. data/lib/vagrant-skytap/action/store_extra_data.rb +35 -0
  45. data/lib/vagrant-skytap/action/suspend_environment.rb +32 -0
  46. data/lib/vagrant-skytap/action/suspend_vm.rb +32 -0
  47. data/lib/vagrant-skytap/action/timed_provision.rb +21 -0
  48. data/lib/vagrant-skytap/action/update_hardware.rb +37 -0
  49. data/lib/vagrant-skytap/action.rb +272 -0
  50. data/lib/vagrant-skytap/api/busyable.rb +37 -0
  51. data/lib/vagrant-skytap/api/client.rb +127 -0
  52. data/lib/vagrant-skytap/api/credentials.rb +41 -0
  53. data/lib/vagrant-skytap/api/environment.rb +99 -0
  54. data/lib/vagrant-skytap/api/interface.rb +123 -0
  55. data/lib/vagrant-skytap/api/network.rb +40 -0
  56. data/lib/vagrant-skytap/api/public_ip.rb +103 -0
  57. data/lib/vagrant-skytap/api/published_service.rb +90 -0
  58. data/lib/vagrant-skytap/api/resource.rb +44 -0
  59. data/lib/vagrant-skytap/api/runstate_operations.rb +63 -0
  60. data/lib/vagrant-skytap/api/specified_attributes.rb +27 -0
  61. data/lib/vagrant-skytap/api/vm.rb +88 -0
  62. data/lib/vagrant-skytap/api/vpn.rb +146 -0
  63. data/lib/vagrant-skytap/api/vpn_attachment.rb +57 -0
  64. data/lib/vagrant-skytap/config.rb +106 -0
  65. data/lib/vagrant-skytap/core_ext/object/blank.rb +82 -0
  66. data/lib/vagrant-skytap/core_ext/object/tap.rb +8 -0
  67. data/lib/vagrant-skytap/core_ext/try.rb +42 -0
  68. data/lib/vagrant-skytap/environment_properties.rb +11 -0
  69. data/lib/vagrant-skytap/errors.rb +59 -0
  70. data/lib/vagrant-skytap/plugin.rb +73 -0
  71. data/lib/vagrant-skytap/properties.rb +42 -0
  72. data/lib/vagrant-skytap/provider.rb +50 -0
  73. data/lib/vagrant-skytap/setup_helper.rb +193 -0
  74. data/lib/vagrant-skytap/util/ip_address.rb +69 -0
  75. data/lib/vagrant-skytap/util/subnet.rb +97 -0
  76. data/lib/vagrant-skytap/util/timer.rb +17 -0
  77. data/lib/vagrant-skytap/version.rb +5 -0
  78. data/lib/vagrant-skytap/version.rb.orig +5 -0
  79. data/lib/vagrant-skytap/vm_properties.rb +22 -0
  80. data/lib/vagrant-skytap.rb +23 -0
  81. data/locales/en.yml +127 -0
  82. data/skytap-dummy.box +0 -0
  83. data/spec/acceptance/base.rb +2 -0
  84. data/spec/acceptance/provider/halt_spec.rb +3 -0
  85. data/spec/acceptance/shared/context_skytap.rb +3 -0
  86. data/spec/spec_helper.rb +1 -0
  87. data/spec/support/isolated_environment.rb +45 -0
  88. data/spec/unit/base.rb +57 -0
  89. data/spec/unit/config_spec.rb +73 -0
  90. data/spec/unit/environment_spec.rb +144 -0
  91. data/spec/unit/skeletons/empty_environment.json +19 -0
  92. data/spec/unit/skeletons/network1.json +36 -0
  93. data/spec/unit/skeletons/vm1.json +85 -0
  94. data/spec/unit/support/dummy_communicator.rb +83 -0
  95. data/spec/unit/support/dummy_provider.rb +41 -0
  96. data/spec/unit/support/isolated_environment.rb +217 -0
  97. data/spec/unit/support/shared/action_synced_folders_context.rb +15 -0
  98. data/spec/unit/support/shared/base_context.rb +116 -0
  99. data/spec/unit/support/shared/capability_helpers_context.rb +29 -0
  100. data/spec/unit/support/shared/plugin_command_context.rb +12 -0
  101. data/spec/unit/support/shared/skytap_context.rb +3 -0
  102. data/spec/unit/vm_spec.rb +118 -0
  103. data/tasks/acceptance.rake +22 -0
  104. data/tasks/bundler.rake +3 -0
  105. data/tasks/test.rake +14 -0
  106. data/vagrant-skytap.gemspec +62 -0
  107. data/vagrant-spec.config.rb +10 -0
  108. metadata +247 -0
@@ -0,0 +1,144 @@
1
+ require_relative 'base'
2
+ require "vagrant-skytap/api/environment"
3
+
4
+ describe VagrantPlugins::Skytap::API::Environment do
5
+ include_context "unit"
6
+ Errors = VagrantPlugins::Skytap::Errors
7
+
8
+ let(:vm1_attrs) { JSON.load(File.read(File.join(File.expand_path('..', __FILE__), 'skeletons', 'vm1.json'))) }
9
+ let(:vm2_attrs) { vm1_attrs.merge("id" => "6981851", "name" => "VM2") }
10
+ let(:network1_attrs) { JSON.load(File.read(File.join(File.expand_path('..', __FILE__), 'skeletons', 'network1.json'))) }
11
+ let(:empty_environment_attrs) { JSON.load(File.read(File.join(File.expand_path('..', __FILE__), 'skeletons', 'empty_environment.json')))}
12
+
13
+ let(:attrs_one_vm) do
14
+ empty_environment_attrs.dup.tap do |ret|
15
+ ret['vms'] = [vm1_attrs]
16
+ ret['networks'] = [network1_attrs]
17
+ end
18
+ end
19
+
20
+ let(:attrs) do
21
+ attrs_one_vm.dup.tap do |ret|
22
+ ret['vms'] = [vm1_attrs, vm2_attrs]
23
+ end
24
+ end
25
+
26
+ let(:iso_env) do
27
+ # We have to create a Vagrantfile so there is a root path
28
+ env = isolated_environment
29
+ env.vagrantfile("")
30
+ env.create_vagrant_env
31
+ end
32
+
33
+ let(:machine) { iso_env.machine(iso_env.machine_names[0], :dummy) }
34
+ let(:env) {{ machine: machine }}
35
+ let(:instance) { described_class.new(attrs, env) }
36
+
37
+ let(:api_client) do
38
+ # By default, all GET requests will return an environment with VM1, VM2, and 1 network
39
+ double('api_client',
40
+ get: double('resp', body: JSON.dump(attrs))
41
+ )
42
+ end
43
+
44
+ # Ensure tests are not affected by Skytap credential environment variables
45
+ before :each do
46
+ ENV.stub(:[] => nil)
47
+ end
48
+
49
+ describe "check_vm_before_adding" do
50
+ subject do
51
+ instance.vms.first
52
+ end
53
+
54
+ it "raises SourceVmNotStopped if the vm is running" do
55
+ allow(subject).to receive(:runstate).and_return('running')
56
+ expect {described_class.check_vm_before_adding(env, subject)}.to raise_error(Errors::SourceVmNotStopped)
57
+ allow(subject).to receive(:runstate).and_call_original
58
+ end
59
+
60
+ it "raises SourceVmNotStopped if the vm is suspended" do
61
+ allow(subject).to receive(:runstate).and_return('suspended')
62
+ expect {described_class.check_vm_before_adding(env, subject)}.to raise_error(Errors::SourceVmNotStopped)
63
+ allow(subject).to receive(:runstate).and_call_original
64
+ end
65
+
66
+ it "raises nothing if the vm is stopped" do
67
+ allow(subject).to receive(:runstate).and_return('stopped')
68
+ expect {described_class.check_vm_before_adding(env, subject)}.to_not raise_error
69
+ allow(subject).to receive(:runstate).and_call_original
70
+ end
71
+ end
72
+
73
+ describe "vms" do
74
+ subject do
75
+ instance.vms.first
76
+ end
77
+ it { should be_a VagrantPlugins::Skytap::API::Vm }
78
+ end
79
+
80
+ describe "networks" do
81
+ subject do
82
+ instance.networks.first
83
+ end
84
+ it { should be_a VagrantPlugins::Skytap::API::Network }
85
+ end
86
+
87
+ describe "get_vm_by_id" do
88
+ subject do
89
+ instance
90
+ end
91
+
92
+ it "should return the appropriate vm from the collection" do
93
+ expect(subject.vms.count).to eq 2
94
+ expect(subject.get_vm_by_id('6981850').get_api_attribute('name')).to eq 'VM1'
95
+ expect(subject.get_vm_by_id('6981851').get_api_attribute('name')).to eq 'VM2'
96
+ end
97
+ end
98
+
99
+ describe "reload" do
100
+ subject do
101
+ old_attrs = attrs_one_vm.merge('networks' => [])
102
+ new_attrs = attrs.merge('name' => 'Environment with 2 vms')
103
+ client = double('api_client',
104
+ get: double('resp', body: JSON.dump(new_attrs))
105
+ )
106
+ myenv = env.merge(api_client: client)
107
+ described_class.new(old_attrs, myenv)
108
+ end
109
+
110
+ it "reloads the list of vms and networks" do
111
+ expect(subject.name).to eq 'Environment 1'
112
+ expect(subject.vms.count).to eq 1
113
+ expect(subject.networks.count).to eq 0
114
+ subject.reload
115
+ expect(subject.name).to eq 'Environment with 2 vms'
116
+ expect(subject.vms.count).to eq 2
117
+ expect(subject.networks.count).to eq 1
118
+ end
119
+ end
120
+
121
+ describe "busy?" do
122
+ subject do
123
+ instance
124
+ end
125
+
126
+ it "returns false when stopped" do
127
+ allow(subject).to receive(:runstate).and_return('stopped')
128
+ expect(subject.busy?).to eq false
129
+ allow(subject).to receive(:runstate).and_call_original
130
+ end
131
+
132
+ it "returns false when running" do
133
+ allow(subject).to receive(:runstate).and_return('running')
134
+ expect(subject.busy?).to eq false
135
+ allow(subject).to receive(:runstate).and_call_original
136
+ end
137
+
138
+ it "returns true when runstate is busy" do
139
+ allow(subject).to receive(:runstate).and_return('busy')
140
+ expect(subject.busy?).to eq true
141
+ allow(subject).to receive(:runstate).and_call_original
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,19 @@
1
+ {
2
+ "id": "5570024",
3
+ "url": "https://example.com/templates/5570024",
4
+ "name": "Environment 1",
5
+ "error": "",
6
+ "runstate": "running",
7
+ "description": "",
8
+ "suspend_on_idle": 86400,
9
+ "routable": false,
10
+ "vms": [],
11
+ "networks": [],
12
+ "lockversion": "60afa50045216f791278c10285a3a82bb1e4c5b8",
13
+ "use_smart_client": true,
14
+ "disable_internet": false,
15
+ "region": "US-West",
16
+ "region_backend": "skytap",
17
+ "owner": "https://example.com/users/15386",
18
+ "publish_sets": []
19
+ }
@@ -0,0 +1,36 @@
1
+ {
2
+ "id": "3288116",
3
+ "url": "https://example.com/templates/5570024/networks/3288116",
4
+ "name": "Default Network",
5
+ "network_type": "automatic",
6
+ "subnet": "10.0.0.0/24",
7
+ "subnet_addr": "10.0.0.0",
8
+ "subnet_size": 24,
9
+ "gateway": "10.0.0.254",
10
+ "primary_nameserver": null,
11
+ "secondary_nameserver": null,
12
+ "region": "US-West",
13
+ "domain": "skytap.example",
14
+ "vpn_attachments": [
15
+ {
16
+ "id": "3288116-vpn-711360",
17
+ "connected": true,
18
+ "network": {
19
+ "id": "3288116",
20
+ "subnet": "10.0.0.0/24",
21
+ "network_name": "Default Network",
22
+ "configuration_id": "5570024"
23
+ },
24
+ "vpn": {
25
+ "id": "vpn-711360",
26
+ "name": "Skytap sea9 NAT VPN",
27
+ "enabled": true,
28
+ "nat_enabled": true,
29
+ "remote_subnets": "10.1.0.0/24, 10.1.1.0/24, 10.1.2.0/24, 10.1.4.0/24, 10.1.6.0/24, 10.1.8.0/24, 10.1.16.0/24, 172.16.89.0/24, 192.168.0.0/16",
30
+ "remote_peer_ip": "66.193.98.66"
31
+ }
32
+ }
33
+ ],
34
+ "tunnelable": false,
35
+ "tunnels": []
36
+ }
@@ -0,0 +1,85 @@
1
+ {
2
+ "id": "6981850",
3
+ "name": "VM1",
4
+ "runstate": "stopped",
5
+ "hardware": {
6
+ "cpus": 1,
7
+ "supports_multicore": true,
8
+ "cpus_per_socket": 1,
9
+ "ram": 1024,
10
+ "svms": 1,
11
+ "guestOS": "ubuntu-64",
12
+ "max_cpus": 12,
13
+ "min_ram": 256,
14
+ "max_ram": 131072,
15
+ "vnc_keymap": null,
16
+ "uuid": null,
17
+ "disks": [
18
+ {
19
+ "id": "disk-3089616-7086702-scsi-0-0",
20
+ "size": 20480,
21
+ "type": "SCSI",
22
+ "controller": "0",
23
+ "lun": "0"
24
+ }
25
+ ],
26
+ "storage": 20480,
27
+ "upgradable": false,
28
+ "instance_type": null,
29
+ "time_sync_enabled": true,
30
+ "copy_paste_enabled": true,
31
+ "nested_virtualization": false
32
+ },
33
+ "error": false,
34
+ "asset_id": null,
35
+ "hardware_version": 10,
36
+ "interfaces": [
37
+ {
38
+ "id": "nic-3089616-7086702-0",
39
+ "ip": "10.0.0.1",
40
+ "hostname": "host-1",
41
+ "mac": "00:50:56:14:34:E4",
42
+ "services_count": 0,
43
+ "services": [],
44
+ "public_ips_count": 0,
45
+ "public_ips": [],
46
+ "vm_id": "6981850",
47
+ "vm_name": "Ubuntu Server 14.04 - 64-bit",
48
+ "status": "Running",
49
+ "nat_addresses": {
50
+ "network_nat_addresses": [],
51
+ "vpn_nat_addresses": [
52
+ {
53
+ "ip_address": "10.1.130.104",
54
+ "vpn_id": "vpn-711360",
55
+ "vpn_name": "Skytap sea9 NAT VPN",
56
+ "vpn_url": "https://example.com/vpns/vpn-711360"
57
+ }
58
+ ]
59
+ },
60
+ "network_id": "3288116",
61
+ "network_name": "Default Network",
62
+ "network_url": "https://example.com/templates/5570024/networks/3288116",
63
+ "network_type": "automatic",
64
+ "network_subnet": "10.0.0.0/24",
65
+ "nic_type": "vmxnet3",
66
+ "promiscuous": false,
67
+ "secondary_ips": []
68
+ }
69
+ ],
70
+ "notes": [],
71
+ "labels": [],
72
+ "credentials": [
73
+ {
74
+ "id": "5695620",
75
+ "text": "skytap / ChangeMe!"
76
+ }
77
+ ],
78
+ "desktop_resizable": true,
79
+ "local_mouse_cursor": true,
80
+ "maintenance_lock_engaged": false,
81
+ "region_backend": "skytap",
82
+ "created_at": "2015/09/24 14:10:55 -0700",
83
+ "can_change_object_state": true,
84
+ "template_url": "https://example.com/templates/5570024"
85
+ }
@@ -0,0 +1,83 @@
1
+ module VagrantTests
2
+ module DummyCommunicator
3
+ class Communicator < Vagrant.plugin("2", :communicator)
4
+ def ready?
5
+ true
6
+ end
7
+
8
+ attr_reader :known_commands
9
+
10
+ def initialize(machine)
11
+ @known_commands = Hash.new do |hash, key|
12
+ hash[key] = { expected: 0, received: 0, response: nil }
13
+ end
14
+ end
15
+
16
+ def expected_commands
17
+ known_commands.select do |command, info|
18
+ info[:expected] > 0
19
+ end
20
+ end
21
+
22
+ def received_commands
23
+ known_commands.select do |command, info|
24
+ info[:received] > 0
25
+ end.keys
26
+ end
27
+
28
+ def stub_command(command, response)
29
+ known_commands[command][:response] = response
30
+ end
31
+
32
+ def expect_command(command)
33
+ known_commands[command][:expected] += 1
34
+ end
35
+
36
+ def received_summary
37
+ received_commands.map { |cmd| " - #{cmd}" }.unshift('received:').join("\n")
38
+ end
39
+
40
+ def verify_expectations!
41
+ expected_commands.each do |command, info|
42
+ if info[:expected] != info[:received]
43
+ fail([
44
+ "expected to receive '#{command}' #{info[:expected]} times",
45
+ "got #{info[:received]} times instead",
46
+ received_summary
47
+ ].join("\n"))
48
+ end
49
+ end
50
+ end
51
+
52
+ def execute(command, opts=nil)
53
+ known = known_commands[command]
54
+ known[:received] += 1
55
+ response = known[:response]
56
+ return unless response
57
+
58
+ if block_given?
59
+ [:stdout, :stderr].each do |type|
60
+ Array(response[type]).each do |line|
61
+ yield type, line
62
+ end
63
+ end
64
+ end
65
+
66
+ if response[:raise]
67
+ raise response[:raise]
68
+ end
69
+
70
+ response[:exit_code]
71
+ end
72
+
73
+ def sudo(command, opts=nil, &block)
74
+ execute(command, opts, &block)
75
+ end
76
+
77
+ def test(command, opts=nil)
78
+ execute(command, opts) == 0
79
+ end
80
+ end
81
+ end
82
+ end
83
+
@@ -0,0 +1,41 @@
1
+ module VagrantTests
2
+ class DummyProviderPlugin < Vagrant.plugin("2")
3
+ name "Dummy Provider"
4
+ description <<-EOF
5
+ This creates a provider named "dummy" which does nothing, so that
6
+ the unit tests aren't reliant on VirtualBox (or any other real
7
+ provider for that matter).
8
+ EOF
9
+
10
+ provider(:dummy) { DummyProvider }
11
+ end
12
+
13
+ class DummyProvider < Vagrant.plugin("2", :provider)
14
+ def initialize(machine)
15
+ @machine = machine
16
+ end
17
+
18
+ def state=(id)
19
+ state_file.open("w+") do |f|
20
+ f.write(id.to_s)
21
+ end
22
+ end
23
+
24
+ def state
25
+ if !state_file.file?
26
+ new_state = @machine.id
27
+ new_state = Vagrant::MachineState::NOT_CREATED_ID if !new_state
28
+ self.state = new_state
29
+ end
30
+
31
+ state_id = state_file.read.to_sym
32
+ Vagrant::MachineState.new(state_id, state_id.to_s, state_id.to_s)
33
+ end
34
+
35
+ protected
36
+
37
+ def state_file
38
+ @machine.data_dir.join("dummy_state")
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,217 @@
1
+ require "fileutils"
2
+ require "pathname"
3
+ require "tempfile"
4
+ require "tmpdir"
5
+
6
+ require "json"
7
+ require "log4r"
8
+
9
+ require "vagrant/util/platform"
10
+ require "vagrant/util/subprocess"
11
+
12
+ require "support/isolated_environment"
13
+
14
+ module Unit
15
+ class IsolatedEnvironment < ::IsolatedEnvironment
16
+ def create_vagrant_env(options=nil)
17
+ options = {
18
+ cwd: @workdir,
19
+ home_path: @homedir
20
+ }.merge(options || {})
21
+
22
+ Vagrant::Environment.new(options)
23
+ end
24
+
25
+ # This creates a file in the isolated environment. By default this file
26
+ # will be created in the working directory of the isolated environment.
27
+ def file(name, contents)
28
+ @workdir.join(name).open("w+") do |f|
29
+ f.write(contents)
30
+ end
31
+ end
32
+
33
+ def vagrantfile(contents, root=nil)
34
+ root ||= @workdir
35
+ root.join("Vagrantfile").open("w+") do |f|
36
+ f.write(contents)
37
+ end
38
+ end
39
+
40
+ def box(name, vagrantfile_contents="")
41
+ # Create the box directory
42
+ box_dir = boxes_dir.join(name)
43
+ box_dir.mkpath
44
+
45
+ # Create the "box.ovf" file because that is how Vagrant heuristically
46
+ # determines a box is a V1 box.
47
+ box_dir.join("box.ovf").open("w") { |f| f.write("") }
48
+
49
+ # Populate the vagrantfile
50
+ vagrantfile(vagrantfile_contents, box_dir)
51
+
52
+ # Return the directory
53
+ box_dir
54
+ end
55
+
56
+ # Create an alias because "box" makes a V1 box, so "box1"
57
+ alias :box1 :box
58
+
59
+ # Creates a fake box to exist in this environment.
60
+ #
61
+ # @param [String] name Name of the box
62
+ # @param [Symbol] provider Provider the box was built for.
63
+ # @return [Pathname] Path to the box directory.
64
+ def box2(name, provider, options=nil)
65
+ # Default options
66
+ options = {
67
+ vagrantfile: ""
68
+ }.merge(options || {})
69
+
70
+ # Make the box directory
71
+ box_dir = boxes_dir.join(name, provider.to_s)
72
+ box_dir.mkpath
73
+
74
+ # Create a metadata.json file
75
+ box_metadata_file = box_dir.join("metadata.json")
76
+ box_metadata_file.open("w") do |f|
77
+ f.write(JSON.generate({
78
+ provider: provider.to_s
79
+ }))
80
+ end
81
+
82
+ # Create a Vagrantfile
83
+ box_vagrantfile = box_dir.join("Vagrantfile")
84
+ box_vagrantfile.open("w") do |f|
85
+ f.write(options[:vagrantfile])
86
+ end
87
+
88
+ # Return the box directory
89
+ box_dir
90
+ end
91
+
92
+ # Creates a fake box to exist in this environment according
93
+ # to the "gen-3" box format.
94
+ #
95
+ # @param [String] name
96
+ # @param [String] version
97
+ # @param [String] provider
98
+ # @return [Pathname]
99
+ def box3(name, version, provider, **opts)
100
+ # Create the directory for the box
101
+ box_dir = boxes_dir.join(name, version, provider.to_s)
102
+ box_dir.mkpath
103
+
104
+ # Create the metadata.json for it
105
+ box_metadata_file = box_dir.join("metadata.json")
106
+ box_metadata_file.open("w") do |f|
107
+ f.write(JSON.generate({
108
+ provider: provider.to_s
109
+ }))
110
+ end
111
+
112
+ # Create a Vagrantfile
113
+ if opts[:vagrantfile]
114
+ box_vagrantfile = box_dir.join("Vagrantfile")
115
+ box_vagrantfile.open("w") do |f|
116
+ f.write(opts[:vagrantfile])
117
+ end
118
+ end
119
+
120
+ # Create the metadata URL
121
+ if opts[:metadata_url]
122
+ boxes_dir.join(name, "metadata_url").open("w") do |f|
123
+ f.write(opts[:metadata_url])
124
+ end
125
+ end
126
+
127
+ box_dir
128
+ end
129
+
130
+ # This creates a "box" file that is a valid V1 box.
131
+ #
132
+ # @return [Pathname] Path to the newly created box.
133
+ def box1_file
134
+ # Create a temporary directory to store our data we will tar up
135
+ td_source = Dir.mktmpdir
136
+ td_dest = Dir.mktmpdir
137
+
138
+ # Store the temporary directory so it is not deleted until
139
+ # this instance is garbage collected.
140
+ @_box2_file_temp ||= []
141
+ @_box2_file_temp << td_dest
142
+
143
+ # The source as a Pathname, which is easier to work with
144
+ source = Pathname.new(td_source)
145
+
146
+ # The destination file
147
+ result = Pathname.new(td_dest).join("temporary.box")
148
+
149
+ # Put a "box.ovf" in there.
150
+ source.join("box.ovf").open("w") do |f|
151
+ f.write("FOO!")
152
+ end
153
+
154
+ Dir.chdir(source) do
155
+ # Find all the files in our current directory and tar it up!
156
+ files = Dir.glob(File.join(".", "**", "*"))
157
+
158
+ # Package!
159
+ Vagrant::Util::Subprocess.execute("bsdtar", "-czf", result.to_s, *files)
160
+ end
161
+
162
+ # Resulting box
163
+ result
164
+ end
165
+
166
+ # This creates a "box" file with the given provider.
167
+ #
168
+ # @param [Symbol] provider Provider for the box.
169
+ # @return [Pathname] Path to the newly created box.
170
+ def box2_file(provider, options=nil)
171
+ options ||= {}
172
+
173
+ # This is the metadata we want to store in our file
174
+ metadata = {
175
+ "type" => "v2_box",
176
+ "provider" => provider
177
+ }.merge(options[:metadata] || {})
178
+
179
+ # Create a temporary directory to store our data we will tar up
180
+ td_source = Dir.mktmpdir
181
+ td_dest = Dir.mktmpdir
182
+
183
+ # Store the temporary directory so it is not deleted until
184
+ # this instance is garbage collected.
185
+ @_box2_file_temp ||= []
186
+ @_box2_file_temp << td_dest
187
+
188
+ # The source as a Pathname, which is easier to work with
189
+ source = Pathname.new(td_source)
190
+
191
+ # The destination file
192
+ result = Pathname.new(td_dest).join("temporary.box")
193
+
194
+ # Put the metadata.json in here.
195
+ source.join("metadata.json").open("w") do |f|
196
+ f.write(JSON.generate(metadata))
197
+ end
198
+
199
+ Dir.chdir(source) do
200
+ # Find all the files in our current directory and tar it up!
201
+ files = Dir.glob(File.join(".", "**", "*"))
202
+
203
+ # Package!
204
+ Vagrant::Util::Subprocess.execute("bsdtar", "-czf", result.to_s, *files)
205
+ end
206
+
207
+ # Resulting box
208
+ result
209
+ end
210
+
211
+ def boxes_dir
212
+ dir = @homedir.join("boxes")
213
+ dir.mkpath
214
+ dir
215
+ end
216
+ end
217
+ end
@@ -0,0 +1,15 @@
1
+ shared_context "synced folder actions" do
2
+ # This creates a synced folder implementation.
3
+ def impl(usable, name)
4
+ Class.new(Vagrant.plugin("2", :synced_folder)) do
5
+ define_method(:name) do
6
+ name
7
+ end
8
+
9
+ define_method(:usable?) do |machine, raise_error=false|
10
+ raise "#{name}: usable" if raise_error && !usable
11
+ usable
12
+ end
13
+ end
14
+ end
15
+ end