vagrant-vmware-esxi 1.0.1
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.
- checksums.yaml +7 -0
- data/Gemfile +14 -0
- data/LICENSE +674 -0
- data/README.md +175 -0
- data/Rakefile +4 -0
- data/example_box/metadata.json +4 -0
- data/lib/vagrant-vmware-esxi.rb +18 -0
- data/lib/vagrant-vmware-esxi/action.rb +119 -0
- data/lib/vagrant-vmware-esxi/action/boot.rb +59 -0
- data/lib/vagrant-vmware-esxi/action/connect_esxi.rb +58 -0
- data/lib/vagrant-vmware-esxi/action/createvm.rb +302 -0
- data/lib/vagrant-vmware-esxi/action/destroy.rb +58 -0
- data/lib/vagrant-vmware-esxi/action/halt.rb +52 -0
- data/lib/vagrant-vmware-esxi/action/read_ssh_info.rb +63 -0
- data/lib/vagrant-vmware-esxi/action/read_state.rb +67 -0
- data/lib/vagrant-vmware-esxi/action/resume.rb +63 -0
- data/lib/vagrant-vmware-esxi/action/suspend.rb +61 -0
- data/lib/vagrant-vmware-esxi/action/wait_for_state.rb +40 -0
- data/lib/vagrant-vmware-esxi/config.rb +56 -0
- data/lib/vagrant-vmware-esxi/errors.rb +22 -0
- data/lib/vagrant-vmware-esxi/plugin.rb +61 -0
- data/lib/vagrant-vmware-esxi/provider.rb +44 -0
- data/lib/vagrant-vmware-esxi/version.rb +6 -0
- data/locales/en.yml +65 -0
- data/vagrant-vmware-esxi.gemspec +27 -0
- metadata +151 -0
data/README.md
ADDED
@@ -0,0 +1,175 @@
|
|
1
|
+
vagrant-vmware-esxi plugin
|
2
|
+
==========================
|
3
|
+
This is a Vagrant plugin that adds a VMware ESXi provider support. This allows Vagrant to control and provision VMs directly on an ESXi hypervisor without a need for vCenter or VShpere. ESXi hypervisor is a free download from VMware!
|
4
|
+
>https://www.vmware.com/go/get-free-esxi
|
5
|
+
|
6
|
+
|
7
|
+
Features
|
8
|
+
--------
|
9
|
+
* Any of the vmware Box formats should be compatible.
|
10
|
+
* vmware_destop, vmware_fusion, vmware_workstation...
|
11
|
+
* Will automatically download boxes from the web.
|
12
|
+
* Will automatically upload the box to your ESXi host.
|
13
|
+
* Automatic or manual VM names.
|
14
|
+
* Automatic VM names are "PREFIX-HOSTNAME-USERNAME-DIR".
|
15
|
+
* Multi machine capable.
|
16
|
+
* Supports adding your VM to a Resource Pools to partition CPU and memory usage from other VMs on your ESXi host.
|
17
|
+
* suspend / resume
|
18
|
+
* rsync, using built-in Vagrant synced folders.
|
19
|
+
* Provision using built-in Vagrant provisioner.
|
20
|
+
|
21
|
+
Requirements
|
22
|
+
------------
|
23
|
+
1. This plugin requires ovftool from VMware. Download from VMware website.
|
24
|
+
>https://www.vmware.com/support/developer/ovf/
|
25
|
+
1. You MUST enable ssh access on your ESXi hypervisor.
|
26
|
+
* Google 'How to enable ssh access on esxi'
|
27
|
+
1. The boxes should have open-vm-tools or vmware-tools installed.
|
28
|
+
|
29
|
+
Why this plugin?
|
30
|
+
----------------
|
31
|
+
Not everyone has vCenter / vSphere... vCenter cost $$$. ESXi is free!
|
32
|
+
|
33
|
+
How to install
|
34
|
+
--------------
|
35
|
+
```
|
36
|
+
vagrant plugin install vagrant-vmware-esxi
|
37
|
+
```
|
38
|
+
How to configure
|
39
|
+
----------------
|
40
|
+
|
41
|
+
1. cd SOMEDIR
|
42
|
+
1. `vagrant init`
|
43
|
+
1. `vi Vagrantfile` # setup access your ESXi host and to set some preferences.
|
44
|
+
```ruby
|
45
|
+
Vagrant.configure("2") do |config|
|
46
|
+
|
47
|
+
# Box, Select any box created for VMware that is compatible with
|
48
|
+
# the ovftool. To get maximum compatiblity You should download
|
49
|
+
# and install the latest version for your OS.
|
50
|
+
# https://www.vmware.com/support/developer/ovf/
|
51
|
+
#
|
52
|
+
# If your box is stuck at "Powered On", then most likely
|
53
|
+
# the system didn't have the vmware tools installed.
|
54
|
+
#
|
55
|
+
# Here are some of the MANY examples....
|
56
|
+
config.vm.box = 'hashicorp/precise64'
|
57
|
+
#config.vm.box = 'steveant/CentOS-7.0-1406-Minimal-x64'
|
58
|
+
#config.vm.box = 'geerlingguy/ubuntu1604'
|
59
|
+
#config.vm.box = 'laravel/homestead'
|
60
|
+
#config.vm.box = 'centos/7'
|
61
|
+
#config.vm.box = 'bento/ubuntu-14.04'
|
62
|
+
|
63
|
+
# Currently this tool supports rsync ONLY. NFS is not working yet
|
64
|
+
config.vm.synced_folder('.', '/Vagrantfiles', type: 'rsync')
|
65
|
+
|
66
|
+
#
|
67
|
+
# Provider (esxi) settings
|
68
|
+
#
|
69
|
+
config.vm.provider :esxi do |esxi|
|
70
|
+
|
71
|
+
# REQUIRED! ESXi hostname/IP
|
72
|
+
# You MUST specify a esxi_hostname or IP, uless you
|
73
|
+
# were lucky enough to name your esxi host "esxi". :-)
|
74
|
+
esxi.esxi_hostname = "esxi"
|
75
|
+
|
76
|
+
# ESXi username
|
77
|
+
# Default is "root".
|
78
|
+
esxi.esxi_username = "root"
|
79
|
+
|
80
|
+
#
|
81
|
+
# A NOTE about esxi_password / ssh keys!!
|
82
|
+
#
|
83
|
+
# If you don't specify a password and do not use ssh
|
84
|
+
# keys, you wil; be entering your esxi password A LOT!
|
85
|
+
#
|
86
|
+
# From your command line, you should be able to run
|
87
|
+
# following command without erros and be able to get to
|
88
|
+
# the esxi command prompt.
|
89
|
+
#
|
90
|
+
# $ ssh root@ESXi_IP_ADDRESS
|
91
|
+
|
92
|
+
# IMPORTANT! ESXi password.
|
93
|
+
# The ssh connections to esxi will try your ssh
|
94
|
+
# keys first. However the ovftool does NOT! To make
|
95
|
+
# vagrant up fully password-less, you will need to
|
96
|
+
# enter your password here....
|
97
|
+
esxi.esxi_password = nil
|
98
|
+
|
99
|
+
# ESXi ssh keys
|
100
|
+
# The Default is to use system defaults, However
|
101
|
+
# you can specify an array of keys here...
|
102
|
+
#esxi.esxi_private_keys = []
|
103
|
+
|
104
|
+
# SSH port.
|
105
|
+
# Default port 22
|
106
|
+
#esxi.esxi_hostport = 22
|
107
|
+
|
108
|
+
# REQUIRED! Virtual Network
|
109
|
+
# You MUST specify a Virtual Network!
|
110
|
+
# The default is fail if no Virtual Network is set!
|
111
|
+
esxi.virtual_network = "vmnet_example"
|
112
|
+
|
113
|
+
# OPTIONAL. Specify a Disk Store
|
114
|
+
# Default is to use the least used Disk Store.
|
115
|
+
#esxi.vm_disk_store = "DS_001"
|
116
|
+
|
117
|
+
# OPTIONAL. Guest VM name to be created/used.
|
118
|
+
# The Default will be automatically generated
|
119
|
+
# and will be based on the vmname_prefix,
|
120
|
+
# hostname, username, path...
|
121
|
+
#esxi.vmname = "Custome_Guest_VM_Name"
|
122
|
+
|
123
|
+
# OPTIONAL. When automatically naming VMs, use
|
124
|
+
# this prifix.
|
125
|
+
#esxi.vmname_prefix = "V-"
|
126
|
+
|
127
|
+
# OPTIONAL. Memory size override
|
128
|
+
# The default is to use the memory size specified in the
|
129
|
+
# vmx file, however you can specify a new value here.
|
130
|
+
#esxi.memsize = "2048"
|
131
|
+
|
132
|
+
# OPTIONAL. Virtual CPUs override
|
133
|
+
# The default is to use the number of virt cpus specified
|
134
|
+
# in the vmx file, however you can specify a new value here.
|
135
|
+
#esxi.numvcpus = "2"
|
136
|
+
|
137
|
+
# OPTIONAL. Resource Pool
|
138
|
+
# The default is to create VMs in the "root". You can
|
139
|
+
# specify a resource pool here to partition memory and
|
140
|
+
# cpu usage away from other systems on your esxi host.
|
141
|
+
# The resource pool must already exist and be configured.
|
142
|
+
# Vagrant will NOT create it for you.
|
143
|
+
#esxi.resource_pool = "/Vagrant"
|
144
|
+
|
145
|
+
# DANGEROUS! Allow Overwrite
|
146
|
+
# Set this to 'True' will overwrite existing VMs (with the same name)
|
147
|
+
# when you run vagrant up. ie, if the vmname already exists,
|
148
|
+
# it will be destroyed, then over written... This is helpful
|
149
|
+
# if you have a VM that vagrant lost control (lost association).
|
150
|
+
#esxi.allow_overwrite = 'True'
|
151
|
+
|
152
|
+
end
|
153
|
+
end
|
154
|
+
```
|
155
|
+
|
156
|
+
Basic usage
|
157
|
+
-----------
|
158
|
+
1. `vagrant up --provider=esxi`
|
159
|
+
1. To access the VM, use `vagrant ssh`
|
160
|
+
1. To destroy the VM, use `vagrant destroy`
|
161
|
+
1. Some other fun stuff you can do.
|
162
|
+
* `vagrant status`
|
163
|
+
* `vagrant suspend`
|
164
|
+
* `vagrant resume`
|
165
|
+
* `vagrant halt`
|
166
|
+
* `vagrant provision`
|
167
|
+
|
168
|
+
|
169
|
+
Known issues
|
170
|
+
------------
|
171
|
+
* NFS using built-in Vagrant synced folders is not yet supported.
|
172
|
+
* Multi machines may not provision one VM if the boxes are different.
|
173
|
+
* I found this seems to be a problem with libvirt also, so I'm assuming it's a vagrant problem...
|
174
|
+
* Cleanup doesn't always destroy a VM that has been partially built. Use the allow_overwrite = 'True' option if you need to force a rebuild.
|
175
|
+
* ovftool for windows doesn't put ovftool.exe in your path. You can manually set your path, or install ovftool in the \HashiCorp\Vagrant\bin directory.
|
data/Rakefile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require 'vagrant-vmware-esxi/plugin'
|
3
|
+
|
4
|
+
module VagrantPlugins
|
5
|
+
# Main entry for ESXi vagrant plugin
|
6
|
+
module ESXi
|
7
|
+
lib_path = Pathname.new(File.expand_path('../vagrant-vmware-esxi', __FILE__))
|
8
|
+
autoload :Action, lib_path.join('action')
|
9
|
+
autoload :Errors, lib_path.join('errors')
|
10
|
+
|
11
|
+
# This returns the path to the source of this plugin.
|
12
|
+
#
|
13
|
+
# @return [Pathname]
|
14
|
+
def self.source_root
|
15
|
+
@source_root ||= Pathname.new(File.expand_path('../../', __FILE__))
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
require 'vagrant/action/builder'
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module ESXi
|
5
|
+
# actions and how to run them
|
6
|
+
module Action
|
7
|
+
include Vagrant::Action::Builtin
|
8
|
+
def self.action_connect_esxi
|
9
|
+
Vagrant::Action::Builder.new.tap do |b|
|
10
|
+
b.use ConnectESXi
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.action_halt
|
15
|
+
Vagrant::Action::Builder.new.tap do |b|
|
16
|
+
b.use ReadState
|
17
|
+
b.use Halt
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.action_suspend
|
22
|
+
Vagrant::Action::Builder.new.tap do |b|
|
23
|
+
b.use ReadState
|
24
|
+
b.use Suspend
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.action_resume
|
29
|
+
Vagrant::Action::Builder.new.tap do |b|
|
30
|
+
b.use ReadState
|
31
|
+
b.use Resume
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.action_destroy
|
36
|
+
Vagrant::Action::Builder.new.tap do |b|
|
37
|
+
b.use action_halt
|
38
|
+
b.use ReadState
|
39
|
+
b.use Destroy
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.action_up
|
44
|
+
Vagrant::Action::Builder.new.tap do |b|
|
45
|
+
b.use ConfigValidate
|
46
|
+
b.use ConnectESXi
|
47
|
+
b.use HandleBox
|
48
|
+
b.use ReadState
|
49
|
+
b.use CreateVM
|
50
|
+
b.use ReadState
|
51
|
+
b.use Boot
|
52
|
+
b.use Call, WaitForState, :running, 240 do |env1, b1|
|
53
|
+
if env1[:result] == 'True'
|
54
|
+
b1.use action_provision
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.action_reload
|
61
|
+
Vagrant::Action::Builder.new.tap do |b|
|
62
|
+
b.use Call, ReadState do |env1, b1|
|
63
|
+
if env1[:machine_state].to_s == 'powered_on'
|
64
|
+
b1.use action_halt
|
65
|
+
end
|
66
|
+
b1.use action_up
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.action_read_state
|
72
|
+
Vagrant::Action::Builder.new.tap do |b|
|
73
|
+
b.use ReadSSHInfo
|
74
|
+
b.use ReadState
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.action_read_ssh_info
|
79
|
+
Vagrant::Action::Builder.new.tap do |b|
|
80
|
+
b.use ReadSSHInfo
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def self.action_ssh
|
85
|
+
Vagrant::Action::Builder.new.tap do |b|
|
86
|
+
b.use ReadState
|
87
|
+
b.use ReadSSHInfo
|
88
|
+
b.use SSHExec
|
89
|
+
b.use SSHRun
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def self.action_provision
|
94
|
+
Vagrant::Action::Builder.new.tap do |b|
|
95
|
+
b.use Call, WaitForState, :running, 240 do |env1, b1|
|
96
|
+
if env1[:result] == 'True'
|
97
|
+
b1.use ReadState
|
98
|
+
b1.use Provision
|
99
|
+
b1.use SyncedFolderCleanup
|
100
|
+
b1.use SyncedFolders
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
action_root = Pathname.new(File.expand_path('../action', __FILE__))
|
107
|
+
autoload :ConnectESXi, action_root.join('connect_esxi')
|
108
|
+
autoload :CreateVM, action_root.join('createvm')
|
109
|
+
autoload :ReadState, action_root.join('read_state')
|
110
|
+
autoload :ReadSSHInfo, action_root.join('read_ssh_info')
|
111
|
+
autoload :Boot, action_root.join('boot')
|
112
|
+
autoload :Halt, action_root.join('halt')
|
113
|
+
autoload :Destroy, action_root.join('destroy')
|
114
|
+
autoload :Suspend, action_root.join('suspend')
|
115
|
+
autoload :Resume, action_root.join('resume')
|
116
|
+
autoload :WaitForState, action_root.join('wait_for_state')
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'log4r'
|
2
|
+
require 'net/ssh/simple'
|
3
|
+
|
4
|
+
module VagrantPlugins
|
5
|
+
module ESXi
|
6
|
+
module Action
|
7
|
+
# This action Boots (power on) the VM
|
8
|
+
class Boot
|
9
|
+
def initialize(app, _env)
|
10
|
+
@app = app
|
11
|
+
@logger = Log4r::Logger.new('vagrant_vmware_esxi::action::boot')
|
12
|
+
end
|
13
|
+
|
14
|
+
def call(env)
|
15
|
+
boot(env)
|
16
|
+
@app.call(env)
|
17
|
+
end
|
18
|
+
|
19
|
+
def boot(env)
|
20
|
+
@logger.info('vagrant-vmware-esxi, boot: start...')
|
21
|
+
|
22
|
+
# Get config.
|
23
|
+
machine = env[:machine]
|
24
|
+
config = env[:machine].provider_config
|
25
|
+
|
26
|
+
@logger.info("vagrant-vmware-esxi, boot: machine id: #{machine.id}")
|
27
|
+
@logger.info('vagrant-vmware-esxi, boot: current state: '\
|
28
|
+
"#{env[:machine_state]}")
|
29
|
+
|
30
|
+
if env[:machine_state].to_s == 'powered_on' ||
|
31
|
+
env[:machine_state].to_s == 'running'
|
32
|
+
env[:ui].info I18n.t('vagrant_vmware_esxi.already_powered_on')
|
33
|
+
elsif env[:machine_state].to_s == 'not_created'
|
34
|
+
env[:ui].info I18n.t('vagrant_vmware_esxi.vagrant_vmware_esxi_message',
|
35
|
+
message: 'Cannot boot in this state')
|
36
|
+
else
|
37
|
+
Net::SSH::Simple.sync(
|
38
|
+
user: config.esxi_username,
|
39
|
+
password: config.esxi_password,
|
40
|
+
port: config.esxi_hostport,
|
41
|
+
keys: config.esxi_private_keys
|
42
|
+
) do
|
43
|
+
|
44
|
+
r = ssh config.esxi_hostname,
|
45
|
+
"vim-cmd vmsvc/power.on #{machine.id}"
|
46
|
+
if r.exit_code != 0
|
47
|
+
raise Errors::ESXiError,
|
48
|
+
message: "Unable to power on VM:\n"\
|
49
|
+
" #{r.stdout}\n#{r.stderr}"
|
50
|
+
end
|
51
|
+
env[:ui].info I18n.t('vagrant_vmware_esxi.vagrant_vmware_esxi_message',
|
52
|
+
message: 'VM has been Powered On...')
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'log4r'
|
2
|
+
require 'net/ssh/simple'
|
3
|
+
|
4
|
+
module VagrantPlugins
|
5
|
+
module ESXi
|
6
|
+
module Action
|
7
|
+
# This action connects to the ESXi, verifies credentials and
|
8
|
+
# validates if it's a ESXi host
|
9
|
+
class ConnectESXi
|
10
|
+
def initialize(app, _env)
|
11
|
+
@app = app
|
12
|
+
@logger = Log4r::Logger.new('vagrant_vmware_esxi::action::connect_esxi')
|
13
|
+
end
|
14
|
+
|
15
|
+
def call(env)
|
16
|
+
connect_esxi(env)
|
17
|
+
@app.call(env)
|
18
|
+
end
|
19
|
+
|
20
|
+
def connect_esxi(env)
|
21
|
+
@logger.info('vagrant-vmware-esxi, connect_esxi: start...')
|
22
|
+
|
23
|
+
# Get config.
|
24
|
+
config = env[:machine].provider_config
|
25
|
+
|
26
|
+
if config.esxi_private_keys.is_a? Array
|
27
|
+
config.esxi_private_keys = [
|
28
|
+
'~/.ssh/id_rsa',
|
29
|
+
'~/.ssh/id_dsa',
|
30
|
+
'~/.ssh/id_ecdsa',
|
31
|
+
'~/.ssh/id_ed25519'
|
32
|
+
]
|
33
|
+
end
|
34
|
+
@logger.info('vagrant-vmware-esxi, connect_esxi: esxi_private_keys: '\
|
35
|
+
"#{config.esxi_private_keys}")
|
36
|
+
|
37
|
+
Net::SSH::Simple.sync(
|
38
|
+
user: config.esxi_username,
|
39
|
+
password: config.esxi_password,
|
40
|
+
port: config.esxi_hostport,
|
41
|
+
keys: config.esxi_private_keys
|
42
|
+
) do
|
43
|
+
|
44
|
+
r = ssh config.esxi_hostname,
|
45
|
+
'esxcli system version get | grep Version:'
|
46
|
+
if (!r.stdout.include? 'Version:') || (r.exit_code != 0)
|
47
|
+
raise Errors::ESXiConfigError,
|
48
|
+
message: "Unable to access ESXi host.\n"\
|
49
|
+
'Verify esxi_hostname, esxi_hostport, '\
|
50
|
+
'esxi_username, esxi_password in your Vagrantfile.'
|
51
|
+
end
|
52
|
+
end
|
53
|
+
@logger.info('vagrant-vmware-esxi, connect_esxi: connect success...')
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,302 @@
|
|
1
|
+
require 'log4r'
|
2
|
+
require 'net/ssh/simple'
|
3
|
+
|
4
|
+
module VagrantPlugins
|
5
|
+
module ESXi
|
6
|
+
module Action
|
7
|
+
# This action connects to the ESXi, verifies credentials and
|
8
|
+
# validates if it's a ESXi host
|
9
|
+
class CreateVM
|
10
|
+
def initialize(app, _env)
|
11
|
+
@app = app
|
12
|
+
@logger = Log4r::Logger.new('vagrant_vmware_esxi::action::createvm')
|
13
|
+
end
|
14
|
+
|
15
|
+
def call(env)
|
16
|
+
createvm(env)
|
17
|
+
@app.call(env)
|
18
|
+
end
|
19
|
+
|
20
|
+
def createvm(env)
|
21
|
+
@logger.info('vagrant-vmware-esxi, createvm: start...')
|
22
|
+
|
23
|
+
# Get config.
|
24
|
+
machine = env[:machine]
|
25
|
+
config = env[:machine].provider_config
|
26
|
+
|
27
|
+
if env[:machine_state].to_s == 'not_created'
|
28
|
+
env[:ui].info I18n.t('vagrant_vmware_esxi.vmbuild_not_done')
|
29
|
+
else
|
30
|
+
env[:ui].info I18n.t('vagrant_vmware_esxi.vmbuild_already_done')
|
31
|
+
return
|
32
|
+
end
|
33
|
+
|
34
|
+
# Set guestvm_vmname
|
35
|
+
if !env[:machine].config.vm.hostname.nil?
|
36
|
+
# A hostname has been set, so use it. (multi node)
|
37
|
+
guestvm_vmname = env[:machine].config.vm.hostname
|
38
|
+
elsif config.vmname.nil?
|
39
|
+
# Nothing set, so generate our own
|
40
|
+
guestvm_vmname = config.vmname_prefix
|
41
|
+
guestvm_vmname << `hostname`.strip
|
42
|
+
guestvm_vmname << '-'
|
43
|
+
guestvm_vmname << `whoami`.gsub!(/[^0-9A-Za-z]/, '').strip
|
44
|
+
guestvm_vmname << '-'
|
45
|
+
base = File.basename machine.env.cwd.to_s
|
46
|
+
guestvm_vmname << base
|
47
|
+
config.vmname = guestvm_vmname
|
48
|
+
else
|
49
|
+
# A vmname has been set, so use it.
|
50
|
+
guestvm_vmname = config.vmname
|
51
|
+
end
|
52
|
+
@logger.info("vagrant-vmware-esxi, createvm: config.vmname: #{config.vmname}")
|
53
|
+
|
54
|
+
#
|
55
|
+
# Source vmx / vmdk files
|
56
|
+
src_dir = env[:machine].box.directory
|
57
|
+
@logger.info("vagrant-vmware-esxi, createvm: src_dir: #{src_dir}")
|
58
|
+
|
59
|
+
vmx_file = Dir.glob("#{src_dir}/*.vmx").first
|
60
|
+
vmdk_files = Dir.glob("#{src_dir}/*.vmdk")
|
61
|
+
@logger.info("vagrant-vmware-esxi, createvm: vmx_file: #{vmx_file}")
|
62
|
+
@logger.info("vagrant-vmware-esxi, createvm: vmdk_files: #{vmdk_files}")
|
63
|
+
|
64
|
+
#
|
65
|
+
# Open the network connection
|
66
|
+
#
|
67
|
+
Net::SSH::Simple.sync(
|
68
|
+
user: config.esxi_username,
|
69
|
+
password: config.esxi_password,
|
70
|
+
port: config.esxi_hostport,
|
71
|
+
keys: config.esxi_private_keys
|
72
|
+
) do
|
73
|
+
|
74
|
+
@logger = Log4r::Logger.new('vagrant_vmware_esxi::action::createvm-ssh')
|
75
|
+
|
76
|
+
#
|
77
|
+
# Figure out DataStore
|
78
|
+
r = ssh config.esxi_hostname,
|
79
|
+
'esxcli storage filesystem list | '\
|
80
|
+
'grep "/vmfs/volumes/.*true VMFS" | sort -nk7'
|
81
|
+
|
82
|
+
availvolumes = r.stdout.dup
|
83
|
+
if (r == '') || (r.exit_code != 0)
|
84
|
+
raise Errors::ESXiError,
|
85
|
+
message: 'Unable to get list of Disk Stores:'
|
86
|
+
end
|
87
|
+
|
88
|
+
# Use least-used if vm_disk_store is not set (or not found)
|
89
|
+
if config.vm_disk_store.nil?
|
90
|
+
desired_ds = '--- Least Used ---'
|
91
|
+
else
|
92
|
+
desired_ds = config.vm_disk_store.to_s
|
93
|
+
end
|
94
|
+
|
95
|
+
for line in availvolumes.each_line do
|
96
|
+
if line =~ %r{ #{desired_ds} }
|
97
|
+
guestvm_ds = line.split(' ')[0].to_s
|
98
|
+
guestvm_dsname = line.split(' ')[1]
|
99
|
+
break
|
100
|
+
end
|
101
|
+
guestvm_ds = line.split(' ')[0].to_s
|
102
|
+
guestvm_dsname = line.split(' ')[1]
|
103
|
+
end
|
104
|
+
|
105
|
+
if (guestvm_dsname != desired_ds) &&
|
106
|
+
!config.vm_disk_store.nil?
|
107
|
+
env[:ui].info I18n.t('vagrant_vmware_esxi.vagrant_vmware_esxi_message',
|
108
|
+
message: 'WARNING : '\
|
109
|
+
"#{config.vm_disk_store} not "\
|
110
|
+
"found, using #{guestvm_dsname}.")
|
111
|
+
end
|
112
|
+
|
113
|
+
dst_dir = "#{guestvm_ds}/#{guestvm_vmname}"
|
114
|
+
@logger.info("vagrant-vmware-esxi, createvm: dst_dir: #{dst_dir}")
|
115
|
+
@logger.info('vagrant-vmware-esxi, createvm: '\
|
116
|
+
"guestvm_dsname: #{guestvm_dsname}")
|
117
|
+
|
118
|
+
#
|
119
|
+
# Figure out network
|
120
|
+
#
|
121
|
+
r = ssh config.esxi_hostname,
|
122
|
+
'esxcli network vswitch standard list |'\
|
123
|
+
'grep Portgroups | sed "s/^ Portgroups: //g" |'\
|
124
|
+
'sed "s/,.*$//g"'
|
125
|
+
availnetworks = r.stdout.dup
|
126
|
+
if (availnetworks == '') || (r.exit_code != 0)
|
127
|
+
raise Errors::ESXiError,
|
128
|
+
message: "Unable to get list of Virtual Networks:\n"\
|
129
|
+
"#{r.stderr}"
|
130
|
+
end
|
131
|
+
|
132
|
+
guestvm_network = nil
|
133
|
+
availnetworkslist = availnetworks.dup
|
134
|
+
for line in availnetworks.each_line do
|
135
|
+
if line =~ %r{#{config.virtual_network}}
|
136
|
+
guestvm_network = config.virtual_network
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
if guestvm_network.nil?
|
141
|
+
raise Errors::ESXiConfigError,
|
142
|
+
message: "You MUST specify a valid virtual network.\n"\
|
143
|
+
"virtual_network (#{config.virtual_network}).\n"\
|
144
|
+
"Available Virtual Networks:\n#{availnetworkslist}"
|
145
|
+
end
|
146
|
+
@logger.info('vagrant-vmware-esxi, createvm: '\
|
147
|
+
"virtual_network: #{guestvm_network}")
|
148
|
+
|
149
|
+
# finalize some paramaters
|
150
|
+
if (config.memsize.is_a? String) || (config.memsize.is_a? Integer)
|
151
|
+
desired_memsize = config.memsize.to_s.to_i
|
152
|
+
end
|
153
|
+
if (config.numvcpus.is_a? String) || (config.numvcpus.is_a? Integer)
|
154
|
+
desired_numvcpus = config.numvcpus.to_s.to_i
|
155
|
+
end
|
156
|
+
|
157
|
+
#
|
158
|
+
# Fix/clean up vmx file.
|
159
|
+
#
|
160
|
+
new_vmx_contents = ''
|
161
|
+
File.readlines(vmx_file).each do |line|
|
162
|
+
|
163
|
+
if line.match(/^displayname =/i)
|
164
|
+
new_vmx_contents << "displayname = \"#{guestvm_vmname}\"\n"
|
165
|
+
elsif line.match(/^memsize =/i) && (!desired_memsize.nil?)
|
166
|
+
new_vmx_contents << "memsize = \"#{desired_memsize}\"\n"
|
167
|
+
elsif line.match(/^numvcpus =/i) && (!desired_numvcpus.nil?)
|
168
|
+
new_vmx_contents << "numvcpus = \"#{desired_numvcpus}\"\n"
|
169
|
+
elsif line.match(/^ethernet0.networkName =/i)
|
170
|
+
new_vmx_contents << "ethernet0.networkName = \"#{guestvm_network}\"\n"
|
171
|
+
elsif line.match(/^ethernet0.addressType =.*static/i)
|
172
|
+
new_vmx_contents << 'ethernet0.addressType = \"generated\"'
|
173
|
+
elsif line.match(/^ethernet[1-9]/i) ||
|
174
|
+
line.match(/^ethernet0.address = /i) ||
|
175
|
+
line.match(/^ethernet0.generatedAddress = /i) ||
|
176
|
+
line.match(/^ethernet0.generatedAddressOffset = /i)
|
177
|
+
# Do nothing, delete these lines
|
178
|
+
else
|
179
|
+
new_vmx_contents << line
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
# finalize vmx.
|
184
|
+
unless new_vmx_contents =~ %r{^numvcpus =}i
|
185
|
+
if desired_numvcpus.nil?
|
186
|
+
new_vmx_contents << "numvcpus = \"1\"\n"
|
187
|
+
else
|
188
|
+
new_vmx_contents << "numvcpus = \"#{desired_numvcpus}\"\n"
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
unless new_vmx_contents =~ %r{^ethernet0.networkName =}i
|
193
|
+
new_vmx_contents << "ethernet0.networkName = \"#{guestvm_network}\"\n"
|
194
|
+
end
|
195
|
+
|
196
|
+
if config.custom_vmx_settings.is_a? Array
|
197
|
+
env[:machine].provider_config.custom_vmx_settings.each do |k, v|
|
198
|
+
new_vmx_contents << "#{k} = \"#{v}\"\n"
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
# Write new vmx file
|
203
|
+
filename_only = File.basename vmx_file, '.vmx'
|
204
|
+
path_only = File.dirname vmx_file
|
205
|
+
new_vmx_file = "#{path_only}/ZZZZ_#{guestvm_vmname}.vmx"
|
206
|
+
|
207
|
+
File.open(new_vmx_file, 'w') { |file|
|
208
|
+
file.write(new_vmx_contents)
|
209
|
+
file.close
|
210
|
+
}
|
211
|
+
|
212
|
+
#
|
213
|
+
# Check if using a Resource Pool
|
214
|
+
if config.resource_pool.is_a? String
|
215
|
+
if config.resource_pool =~ %r{^\/}
|
216
|
+
resource_pool = config.resource_pool
|
217
|
+
else
|
218
|
+
resource_pool = '/'
|
219
|
+
resource_pool << config.resource_pool
|
220
|
+
end
|
221
|
+
else
|
222
|
+
resource_pool = ''
|
223
|
+
end
|
224
|
+
|
225
|
+
if (config.allow_overwrite =~ %r{true}i) ||
|
226
|
+
(config.allow_overwrite =~ %r{yes}i)
|
227
|
+
overwrite_opts = '--overwrite --powerOffTarget'
|
228
|
+
else
|
229
|
+
overwrite_opts = nil
|
230
|
+
end
|
231
|
+
|
232
|
+
#
|
233
|
+
# Display build summary
|
234
|
+
numvcpus = new_vmx_contents.match(/^numvcpus =.*/i)
|
235
|
+
.to_s.gsub(/^numvcpus =/i, '').gsub(/\"/, '')
|
236
|
+
memsize = new_vmx_contents.match(/^memsize =.*/i)
|
237
|
+
.to_s.gsub(/^memsize =/i, '').gsub(/\"/, '')
|
238
|
+
guestOS = new_vmx_contents.match(/^guestOS =.*/i)
|
239
|
+
.to_s.gsub(/^guestOS =/i, '').gsub(/\"/, '')
|
240
|
+
env[:ui].info I18n.t('vagrant_vmware_esxi.vagrant_vmware_esxi_message',
|
241
|
+
message: "ESXi host : #{config.esxi_hostname}")
|
242
|
+
env[:ui].info I18n.t('vagrant_vmware_esxi.vagrant_vmware_esxi_message',
|
243
|
+
message: "VM Name : #{guestvm_vmname}")
|
244
|
+
env[:ui].info I18n.t('vagrant_vmware_esxi.vagrant_vmware_esxi_message',
|
245
|
+
message: "CPUS :#{numvcpus}")
|
246
|
+
env[:ui].info I18n.t('vagrant_vmware_esxi.vagrant_vmware_esxi_message',
|
247
|
+
message: "Memsize (MB) :#{memsize}")
|
248
|
+
env[:ui].info I18n.t('vagrant_vmware_esxi.vagrant_vmware_esxi_message',
|
249
|
+
message: "Guest OS type :#{guestOS}")
|
250
|
+
env[:ui].info I18n.t('vagrant_vmware_esxi.vagrant_vmware_esxi_message',
|
251
|
+
message: "Disk Store : #{guestvm_dsname}")
|
252
|
+
env[:ui].info I18n.t('vagrant_vmware_esxi.vagrant_vmware_esxi_message',
|
253
|
+
message: "NetworkName : \"#{guestvm_network}\"")
|
254
|
+
unless overwrite_opts.nil?
|
255
|
+
env[:ui].info I18n.t('vagrant_vmware_esxi.vagrant_vmware_esxi_message',
|
256
|
+
message: 'Allow Overwrite : True')
|
257
|
+
end
|
258
|
+
env[:ui].info I18n.t('vagrant_vmware_esxi.vagrant_vmware_esxi_message',
|
259
|
+
message: "Resource Pool : #{resource_pool}")
|
260
|
+
#
|
261
|
+
# Using ovftool, import vmx in box folder, export to ESXi server
|
262
|
+
#
|
263
|
+
unless system 'ovftool --version'
|
264
|
+
raise Errors::ESXiConfigError,
|
265
|
+
message: 'ovftool not found or not in your path.'\
|
266
|
+
" Please download and "\
|
267
|
+
' install from http://www.vmware.com.'
|
268
|
+
end
|
269
|
+
ovf_cmd = "ovftool --noSSLVerify #{overwrite_opts} "\
|
270
|
+
"-nw=\"#{guestvm_network}\" -dm=thin --powerOn "\
|
271
|
+
"-ds=\"#{guestvm_dsname}\" --name=\"#{guestvm_vmname}\" "\
|
272
|
+
"\"#{new_vmx_file}\" vi://#{config.esxi_username}:"\
|
273
|
+
"#{config.esxi_password}@#{config.esxi_hostname}"\
|
274
|
+
"#{resource_pool}"
|
275
|
+
|
276
|
+
# Security bug if unremarked! Password will be exposed in log file.
|
277
|
+
# @logger.info("vagrant-vmware-esxi, createvm: ovf_cmd #{ovf_cmd}")
|
278
|
+
unless system "#{ovf_cmd}"
|
279
|
+
raise Errors::ESXiConfigError, message: 'Error with ovftool...'
|
280
|
+
end
|
281
|
+
|
282
|
+
# VMX file is not needed any longer
|
283
|
+
File.delete(new_vmx_file)
|
284
|
+
|
285
|
+
r = ssh config.esxi_hostname,
|
286
|
+
'vim-cmd vmsvc/getallvms |'\
|
287
|
+
"grep \" #{guestvm_vmname} \"|awk '{print $1}'"
|
288
|
+
vmid = r.stdout
|
289
|
+
if (vmid == '') || (r.exit_code != 0)
|
290
|
+
raise Errors::ESXiError,
|
291
|
+
message: "Unable to register / start #{guestvm_vmname}"
|
292
|
+
end
|
293
|
+
|
294
|
+
env[:machine].id = vmid.to_i
|
295
|
+
env[:ui].info I18n.t('vagrant_vmware_esxi.vagrant_vmware_esxi_message',
|
296
|
+
message: "VMID: #{env[:machine].id}")
|
297
|
+
end
|
298
|
+
end
|
299
|
+
end
|
300
|
+
end
|
301
|
+
end
|
302
|
+
end
|