vagrant-vsphere-ddns 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +5 -0
- data/Gemfile +9 -0
- data/README.md +91 -0
- data/Rakefile +1 -0
- data/lib/vagrant-vsphere-ddns/action/get_ssh_info.rb +46 -0
- data/lib/vagrant-vsphere-ddns/action/wait_for_ip_address.rb +43 -0
- data/lib/vagrant-vsphere-ddns/action.rb +22 -0
- data/lib/vagrant-vsphere-ddns/config.rb +24 -0
- data/lib/vagrant-vsphere-ddns/errors.rb +15 -0
- data/lib/vagrant-vsphere-ddns/plugin.rb +35 -0
- data/lib/vagrant-vsphere-ddns/version.rb +5 -0
- data/lib/vagrant-vsphere-ddns.rb +17 -0
- data/locales/en.yml +5 -0
- data/scripts/dns_update.py +38 -0
- data/vagrant-vsphere-ddns.gemspec +20 -0
- metadata +74 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 9a19f218ad9a80e8502c8d0055e560c146407609
|
4
|
+
data.tar.gz: ad1b4de8e83023895691897eb3c7782c61e676dd
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 39df719870d78d8202eee4bdd13d6d20eeaacfaeeb49e568007314842112f5f47860e629dbb62e520ee45c96640dd75e54c49250f5f8a9af023fa970c8c11c34
|
7
|
+
data.tar.gz: ff5755841aa2075b885784d2b47c835809cfb333f01c73cf08aba2ce3cb28e63f0d78d13245eb3482620fc57fef14d8e8ffcdd1bbf69dcaeee37e62265fa1388
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
# Vagrant vSphere DDNS plugin
|
2
|
+
|
3
|
+
This is a PoC [Vagrant](http://www.vagrantup.com) plugin that enables Vagrant to connect to vSphere VMs via dynamic domain names based on MAC addresses.
|
4
|
+
This trivial plugin enables SSH connection to VMs that do not have guest tools installed.
|
5
|
+
|
6
|
+
This plugin does not work out of the box and requires custom DHCP and DNS settings.
|
7
|
+
This configuration is however not implemented in the plugin itself and has to be performed manually in advance.
|
8
|
+
|
9
|
+
## Requirements
|
10
|
+
|
11
|
+
* Vagrant
|
12
|
+
* vagrant-vsphere plugin
|
13
|
+
|
14
|
+
## Usage
|
15
|
+
|
16
|
+
Plugin can be configured by following settings:
|
17
|
+
* `ddns.host`
|
18
|
+
* Hostname that will be used for SSH connections instead of guest IP address
|
19
|
+
* Patterns mac0, mac1, ... will be replaced by VMs MAC address
|
20
|
+
* `ddns.timeout`
|
21
|
+
* Defines how long the plugin will wait for successfull DNS resolution (default is 120 seconds)
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
Vagrant.configure("2") do |config|
|
25
|
+
config.vm.box = 'dummy-vsphere-box'
|
26
|
+
|
27
|
+
config.ddns.host = "%{mac0}.local"
|
28
|
+
config.ddns.timeout = 120
|
29
|
+
|
30
|
+
config.vm.provider :vsphere do |vsphere|
|
31
|
+
vsphere.host = 'HOST NAME OF YOUR VSPHERE INSTANCE'
|
32
|
+
vsphere.compute_resource_name = 'YOUR COMPUTE RESOURCE'
|
33
|
+
vsphere.resource_pool_name = 'YOUR RESOURCE POOL'
|
34
|
+
vsphere.template_name = '/PATH/TO/YOUR VM TEMPLATE'
|
35
|
+
vsphere.name = 'NEW VM NAME'
|
36
|
+
vsphere.user = 'YOUR VMWARE USER'
|
37
|
+
vsphere.password = 'YOUR VMWARE PASSWORD'
|
38
|
+
end
|
39
|
+
end
|
40
|
+
```
|
41
|
+
|
42
|
+
After running `vagrant up --provider=vsphere` Vagrant will attempt to reach VM using specified domain name
|
43
|
+
(e.g. `005056a44d89.local`) and fail if this it can not be resolved for 2 minutes.
|
44
|
+
|
45
|
+
## DHCP and DNS settings
|
46
|
+
|
47
|
+
* Allow dynamic DNS updates in Bind in `/etc/bind/named.conf.local`
|
48
|
+
```bash
|
49
|
+
...
|
50
|
+
include "/etc/bind/ddns.key";
|
51
|
+
|
52
|
+
zone ".local" {
|
53
|
+
type master;
|
54
|
+
forwarders {};
|
55
|
+
file "/var/lib/bind/db.local";
|
56
|
+
allow-update { key dhcpupdate; };
|
57
|
+
};
|
58
|
+
...
|
59
|
+
```
|
60
|
+
* Execute [custom script](./scripts/dns_update.py) on DHCP events in `/etc/dhcp/dhcpd.conf`
|
61
|
+
```bash
|
62
|
+
...
|
63
|
+
on commit {
|
64
|
+
execute("/etc/dhcp/dns_update.py",
|
65
|
+
"--action", "commit",
|
66
|
+
"--ip", binary-to-ascii(10, 8, ".", leased-address),
|
67
|
+
"--mac", binary-to-ascii(16, 8, ":", substring(hardware, 1, 6)),
|
68
|
+
"--zone", config-option domain-name,
|
69
|
+
"--key_file", "/etc/dhcp/ddns.key"
|
70
|
+
);
|
71
|
+
}
|
72
|
+
on release {
|
73
|
+
execute("/etc/dhcp/dns_update.py",
|
74
|
+
"--action", "release",
|
75
|
+
"--ip", binary-to-ascii(10, 8, ".", leased-address),
|
76
|
+
"--mac", binary-to-ascii(16, 8, ":", substring(hardware, 1, 6)),
|
77
|
+
"--zone", config-option domain-name,
|
78
|
+
"--key_file", "/etc/dhcp/ddns.key"
|
79
|
+
);
|
80
|
+
}
|
81
|
+
on expiry {
|
82
|
+
execute("/etc/dhcp/dns_update.py",
|
83
|
+
"--action", "expiry",
|
84
|
+
"--ip", binary-to-ascii(10, 8, ".", leased-address),
|
85
|
+
"--mac", binary-to-ascii(16, 8, ":", substring(hardware, 1, 6)),
|
86
|
+
"--zone", config-option domain-name,
|
87
|
+
"--key_file", "/etc/dhcp/ddns.key"
|
88
|
+
);
|
89
|
+
}
|
90
|
+
...
|
91
|
+
```
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'rbvmomi'
|
2
|
+
require 'vSphere/util/vim_helpers'
|
3
|
+
|
4
|
+
module VagrantPlugins
|
5
|
+
module VSphereDDNS
|
6
|
+
module Action
|
7
|
+
class GetSshInfo
|
8
|
+
include VagrantPlugins::VSphere::Util::VimHelpers
|
9
|
+
|
10
|
+
def initialize(app, env)
|
11
|
+
@app = app
|
12
|
+
@logger = Log4r::Logger.new("vagrant::vsphere-ddns::get_ssh_info")
|
13
|
+
end
|
14
|
+
|
15
|
+
def call(env)
|
16
|
+
env[:machine_ssh_info] = get_ssh_info(env[:vSphere_connection], env[:machine])
|
17
|
+
if !env[:machine_ssh_info].nil?
|
18
|
+
@logger.info("SSH info: %s:%s" % [env[:machine_ssh_info][:host], env[:machine_ssh_info][:port]])
|
19
|
+
end
|
20
|
+
@app.call env
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def get_ssh_info(connection, machine)
|
26
|
+
return nil if machine.config.ddns.host.nil?
|
27
|
+
return nil if machine.id.nil?
|
28
|
+
vm = get_vm_by_uuid connection, machine
|
29
|
+
return nil if vm.nil?
|
30
|
+
|
31
|
+
format_data = {}
|
32
|
+
vm.config.hardware.device.grep(RbVmomi::VIM::VirtualEthernetCard).each_with_index do |card, id|
|
33
|
+
break if card.nil?
|
34
|
+
format_data["mac#{id}".to_sym] = (card.macAddress.scan /[a-f0-9]/).join
|
35
|
+
end
|
36
|
+
|
37
|
+
{
|
38
|
+
host: machine.config.ddns.host % format_data,
|
39
|
+
port: (machine.config.ssh.port.nil? ? 22 : machine.config.ssh.port)
|
40
|
+
}
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'timeout'
|
2
|
+
require 'log4r'
|
3
|
+
require 'resolv'
|
4
|
+
|
5
|
+
module VagrantPlugins
|
6
|
+
module VSphereDDNS
|
7
|
+
module Action
|
8
|
+
class WaitForIPAddress
|
9
|
+
def initialize(app, env)
|
10
|
+
@app = app
|
11
|
+
@logger = Log4r::Logger.new("vagrant::vsphere-ddns::wait_for_ip_address")
|
12
|
+
end
|
13
|
+
|
14
|
+
def call(env)
|
15
|
+
timeout = env[:machine].config.ddns.ssh_timeout
|
16
|
+
@logger.info("Trying to resolve #{env[:machine_ssh_info][:host]} (timeout #{timeout} seconds)")
|
17
|
+
|
18
|
+
Timeout.timeout(timeout) do
|
19
|
+
while true
|
20
|
+
# If a ctrl-c came through, break out
|
21
|
+
return if env[:interrupted]
|
22
|
+
|
23
|
+
begin
|
24
|
+
ip_address = Resolv.getaddress(env[:machine_ssh_info][:host])
|
25
|
+
@logger.info("Host #{env[:machine_ssh_info][:host]} resolved to #{ip_address}")
|
26
|
+
break
|
27
|
+
rescue Resolv::ResolvError
|
28
|
+
@logger.warn("Could not resolve: #{env[:machine_ssh_info][:host]}")
|
29
|
+
end
|
30
|
+
sleep 1
|
31
|
+
end
|
32
|
+
end
|
33
|
+
return if env[:interrupted]
|
34
|
+
@app.call(env)
|
35
|
+
|
36
|
+
rescue Timeout::Error
|
37
|
+
raise Errors::IPAddrTimeout
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'vagrant'
|
2
|
+
require 'vagrant/action/builder'
|
3
|
+
|
4
|
+
module VagrantPlugins
|
5
|
+
module VSphereDDNS
|
6
|
+
module Action
|
7
|
+
include Vagrant::Action::Builtin
|
8
|
+
|
9
|
+
def self.action_get_ssh_info
|
10
|
+
Vagrant::Action::Builder.new.tap do |b|
|
11
|
+
b.use GetSshInfo
|
12
|
+
b.use WaitForIPAddress
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# autoload
|
17
|
+
action_root = Pathname.new(File.expand_path('../action', __FILE__))
|
18
|
+
autoload :GetSshInfo, action_root.join('get_ssh_info')
|
19
|
+
autoload :WaitForIPAddress, action_root.join("wait_for_ip_address")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'vagrant'
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module VSphereDDNS
|
5
|
+
class Config < Vagrant.plugin('2', :config)
|
6
|
+
attr_accessor :host
|
7
|
+
attr_accessor :ssh_timeout
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@host = UNSET_VALUE
|
11
|
+
@ssh_timeout = UNSET_VALUE
|
12
|
+
end
|
13
|
+
|
14
|
+
def finalize!
|
15
|
+
@ssh_timeout = 120 if @ssh_timeout == UNSET_VALUE
|
16
|
+
end
|
17
|
+
|
18
|
+
def validate(machine)
|
19
|
+
errors = _detected_errors
|
20
|
+
{ 'vagrant-vsphere-ddns' => errors }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'vagrant'
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module VSphereDNS
|
5
|
+
module Errors
|
6
|
+
class VSphereDDNSError < Vagrant::Errors::VagrantError
|
7
|
+
error_namespace("vagrant-vsphere-ddns.errors")
|
8
|
+
end
|
9
|
+
|
10
|
+
class IPAddrTimeout < VSphereDDNSError
|
11
|
+
error_key(:ip_addr_timeout)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
begin
|
2
|
+
require 'vagrant'
|
3
|
+
rescue LoadError
|
4
|
+
raise 'The plugin must be run within Vagrant.'
|
5
|
+
end
|
6
|
+
|
7
|
+
module VagrantPlugins
|
8
|
+
module VSphereDDNS
|
9
|
+
class Plugin < Vagrant.plugin('2')
|
10
|
+
name 'vsphere-ddns'
|
11
|
+
description 'Enables Vagrant to connect to vSphere VMs via dynamic domain names based on MAC addresses'
|
12
|
+
|
13
|
+
config(:ddns) do
|
14
|
+
require_relative 'config'
|
15
|
+
init!
|
16
|
+
Config
|
17
|
+
end
|
18
|
+
|
19
|
+
action_hook :get_ssh_info, :machine_action_get_ssh_info do |hook|
|
20
|
+
require_relative 'action'
|
21
|
+
hook.after VagrantPlugins::VSphere::Action::GetSshInfo, VagrantPlugins::VSphereDDNS::Action::action_get_ssh_info
|
22
|
+
end
|
23
|
+
|
24
|
+
protected
|
25
|
+
|
26
|
+
def self.init!
|
27
|
+
return if defined?(@_init)
|
28
|
+
I18n.load_path << File.expand_path('locales/en.yml', VagrantPlugins::VSphereDDNS.source_root)
|
29
|
+
I18n.reload!
|
30
|
+
@_init = true
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require 'vagrant-vsphere-ddns/plugin'
|
3
|
+
|
4
|
+
module VagrantPlugins
|
5
|
+
module VSphereDDNS
|
6
|
+
lib_path = Pathname.new(File.expand_path('../vagrant-vsphere-ddns', __FILE__))
|
7
|
+
autoload :Action, lib_path.join('action')
|
8
|
+
autoload :Errors, lib_path.join('errors')
|
9
|
+
|
10
|
+
# This returns the path to the source of this plugin.
|
11
|
+
#
|
12
|
+
# @return [Pathname]
|
13
|
+
def self.source_root
|
14
|
+
@source_root ||= Pathname.new(File.expand_path('../../', __FILE__))
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/locales/en.yml
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
|
4
|
+
import sys
|
5
|
+
import argparse
|
6
|
+
import logging
|
7
|
+
import subprocess
|
8
|
+
|
9
|
+
if __name__=='__main__':
|
10
|
+
parser = argparse.ArgumentParser()
|
11
|
+
parser.add_argument('-d', '--debug', action='store_true', default=False)
|
12
|
+
parser.add_argument('-a','--action', choices=('commit', 'release', 'expiry'), required=True)
|
13
|
+
parser.add_argument('-i','--ip', required=True)
|
14
|
+
parser.add_argument('-m','--mac', required=True)
|
15
|
+
parser.add_argument('--key_file', required=True)
|
16
|
+
parser.add_argument('--server', default='127.0.0.1')
|
17
|
+
parser.add_argument('--ttl', type=int, default=600)
|
18
|
+
parser.add_argument('--zone', required=True)
|
19
|
+
|
20
|
+
args = parser.parse_args()
|
21
|
+
logging.basicConfig(level=(logging.DEBUG if args.debug else logging.INFO), format='%(asctime)s %(levelname)-5.5s [%(name)s] %(message)s')
|
22
|
+
logging.debug('arguments: %s' % sys.argv)
|
23
|
+
|
24
|
+
mac = ''.join([format(int(x, 16), '02x') for x in args.mac.replace('-',':').split(':')])
|
25
|
+
|
26
|
+
params = "server %s\nzone %s\n" % (args.server, args.zone)
|
27
|
+
if args.action == 'commit':
|
28
|
+
params += "update add %s.%s %d IN A %s\n" % (mac, args.zone, args.ttl, args.ip)
|
29
|
+
else:
|
30
|
+
params += "update delete %s.%s. A\n" % (mac, args.zone)
|
31
|
+
if args.debug:
|
32
|
+
params += "show\n"
|
33
|
+
params += "send\n"
|
34
|
+
|
35
|
+
logging.debug('nsupdate params: %s' % params)
|
36
|
+
ret = subprocess.call('/usr/bin/nsupdate -k %s -v << EOF\n%s\nEOF' % (args.key_file, params), shell=True)
|
37
|
+
logging.debug('nsupdate returned %d' % (ret))
|
38
|
+
sys.exit(ret)
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
$LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
|
3
|
+
require 'vagrant-vsphere-ddns/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = 'vagrant-vsphere-ddns'
|
7
|
+
s.version = VagrantPlugins::VSphereDDNS::VERSION
|
8
|
+
s.authors = ['Tobias']
|
9
|
+
s.email = ['tsmolka@gmail.com']
|
10
|
+
s.homepage = 'https://github.com/tsmolka/vagrant-vsphere-ddns'
|
11
|
+
s.license = 'GPL-2.0'
|
12
|
+
s.summary = 'VMWare vSphere DDNS plugin'
|
13
|
+
s.description = 'Enables Vagrant to connect to vSphere VMs via dynamic domain names based on MAC addresses'
|
14
|
+
root_path = File.dirname(__FILE__)
|
15
|
+
s.add_dependency 'vagrant-vsphere', '~> 1.9'
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
|
18
|
+
s.executables = s.files.grep(/^bin\//) { |f| File.basename(f) }
|
19
|
+
s.require_path = 'lib'
|
20
|
+
end
|
metadata
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: vagrant-vsphere-ddns
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Tobias
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-06-21 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: vagrant-vsphere
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.9'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.9'
|
27
|
+
description: Enables Vagrant to connect to vSphere VMs via dynamic domain names based
|
28
|
+
on MAC addresses
|
29
|
+
email:
|
30
|
+
- tsmolka@gmail.com
|
31
|
+
executables: []
|
32
|
+
extensions: []
|
33
|
+
extra_rdoc_files: []
|
34
|
+
files:
|
35
|
+
- ".gitignore"
|
36
|
+
- Gemfile
|
37
|
+
- README.md
|
38
|
+
- Rakefile
|
39
|
+
- lib/vagrant-vsphere-ddns.rb
|
40
|
+
- lib/vagrant-vsphere-ddns/action.rb
|
41
|
+
- lib/vagrant-vsphere-ddns/action/get_ssh_info.rb
|
42
|
+
- lib/vagrant-vsphere-ddns/action/wait_for_ip_address.rb
|
43
|
+
- lib/vagrant-vsphere-ddns/config.rb
|
44
|
+
- lib/vagrant-vsphere-ddns/errors.rb
|
45
|
+
- lib/vagrant-vsphere-ddns/plugin.rb
|
46
|
+
- lib/vagrant-vsphere-ddns/version.rb
|
47
|
+
- locales/en.yml
|
48
|
+
- scripts/dns_update.py
|
49
|
+
- vagrant-vsphere-ddns.gemspec
|
50
|
+
homepage: https://github.com/tsmolka/vagrant-vsphere-ddns
|
51
|
+
licenses:
|
52
|
+
- GPL-2.0
|
53
|
+
metadata: {}
|
54
|
+
post_install_message:
|
55
|
+
rdoc_options: []
|
56
|
+
require_paths:
|
57
|
+
- lib
|
58
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '0'
|
68
|
+
requirements: []
|
69
|
+
rubyforge_project:
|
70
|
+
rubygems_version: 2.4.5.1
|
71
|
+
signing_key:
|
72
|
+
specification_version: 4
|
73
|
+
summary: VMWare vSphere DDNS plugin
|
74
|
+
test_files: []
|