vagrant-vsphere-ddns 0.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 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
@@ -0,0 +1,5 @@
1
+ *~
2
+ .vagrant/*
3
+ Vagrantfile
4
+ *.gem
5
+ Gemfile.lock
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source "https://rubygems.org"
2
+
3
+ group :development do
4
+ gem "vagrant", git: "https://github.com/mitchellh/vagrant.git"
5
+ end
6
+
7
+ group :plugins do
8
+ gem "vagrant-vsphere-ddns", path: "."
9
+ end
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,5 @@
1
+ module VagrantPlugins
2
+ module VSphereDDNS
3
+ VERSION = '0.0.1'
4
+ end
5
+ 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,5 @@
1
+ en:
2
+ vagrant-vsphere-ddns:
3
+ errors:
4
+ ip_addr_timeout: |-
5
+ Could not resolve host within timeout
@@ -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: []